Hallo zusammen,
ich arbeite an einem TicTacToe-Spiel für unsere Projektarbeit und habe
eine kurze Frage.
Wenn man mitten in einem Spiel das Spiel abbrechen möchte, drückt der
Spieler einen Taster und ein Interrupt wird ausgelöst.
Nun wird der Interrupt ausgelöst und eine Prozedur wird ausgeführt, z.B.
Spielfeld leeren, neuen Anfangsspieler bestimmen, etc.
Wie schaffe ich es, dass nach dem Reset das Programm nicht dort weiter
ausgeführt wird wo der Interrupt stattgefunden hat sondern z.B. am
Anfang der main-Methode?
oder ist dieses nur mit unsinnigen Methoden möglich? Habe ja schon
gesucht und auch was über SRAM-Manipulierung gelesen, aber das möchte
ich dann doch nicht.
Wenn es keine vernünftige Lösung gibt, dann fall ich auf den Fall
zurück, dass das Feld nur dann resettet werden darf, wenn schon jemand
gewonnen hat und man somit an keine unschöne Stelle (KI-Algorithmus)
zurückspringt.
Vielen Dank für das Helfen
Darüber habe ich natürlich auch schon nachgedacht, nur dann kann ich
nicht die gesamten Spielrunden zählen lassen bzw. den Spieler immer
wechseln lassen, da der µC ja alle Einstellungen von neuem lädt.
Hallo Peter II,
das kann durchaus eine Lösung sein, nur was mache ich, wenn der
Controller mitten in einer Zugberechnung ist und diese sagen wir mal
noch 4 Sekunden dauert (über Sinn und Unsinn dieser Berechnung kann man
sich streiten, nur meinte mein Lehrer, ich sollte einen Algorithmus
implementieren => MiniMax)?
Für diesen Fall finde ich die Lösung etwas unangebracht.
> oder ist dieses nur mit unsinnigen Methoden möglich?
Ich würde mal sagen, deine ganze VOrgehensweise mit Spielfeld resetten
im Interrupt ist schon Unsinn genug.
Mach es richtig. Und das beginnt schon mal damit, dass man
Tasterauswertung nicht mittels Interrupt machen muss/soll. Wenn aber
Interrupt, dann registriert der Interrupt den Tastendruck, tut selbst
aber nichts weiter. Die Auswertung, was dieser Tastendruck zu bedeuten
hat, geschieht an einer ganz anderen Stelle, nämlich in der
Hauptschleife.
> mitten in einer Zugberechnung ist und diese sagen wir mal> noch 4 Sekunden dauert
Auch die Zugberechnung kann ab und an überprüfen, ob vom Benutzer ein
Abbruch gefordert wurde, hinter sich aufräumen und zurückkehren.
(*) das Aufräumen ist nämlich mit einer der wichtigen Gründe, warum du
nicht einfach mit einem Interrupt alles abwürgen kannst!
Marco M. schrieb:> das kann durchaus eine Lösung sein, nur was mache ich, wenn der> Controller mitten in einer Zugberechnung ist und diese sagen wir mal> noch 4 Sekunden dauert
dann mach die Abfrage in die Zugberechnung rein.
Marco M. schrieb:> da der µC ja alle Einstellungen von neuem lädt.
Das ist wohl ein Design-Fehler. Du musst dir einfach einteilen, welche
Daten dauerhaft gespeichert werden und welche bei jedem Start neu
initialisiert, dann verschwindet das Problem und du musst zum Spielende
bloss zum Programmstart springen: da wird ja dann eh der Stack neu
initialisiert usw., also ein sauberer Neuanfang, bloss die Dauer-Daten
bleiben erhalten - für die musst du eine Löschroutine vorsehen, die der
Benutzer nur aufruft, wenn er tatsächlich alle bisherigen Spiele
vergessen will.
Gruss Reinhard
Marco M. schrieb:> Wenn man mitten in einem Spiel das Spiel abbrechen möchte, drückt der> Spieler einen Taster und ein Interrupt wird ausgelöst.>> Nun wird der Interrupt ausgelöst und eine Prozedur wird ausgeführt, z.B.> Spielfeld leeren, neuen Anfangsspieler bestimmen, etc.
Da ist schon das Problem. Das macht man nicht im Interrupt, das gehört
ins Hauptprogramm.
Im Interrupt wird nur ein Flag gesetzt um zu signalisieren, dass ein
Spielabbruch gewünscht wurde. Dieses Flag muss das Hauptprogramm
regelmäßig prüfen und dann entsprechend handeln.
Wenn es nur darum geht, nicht über ein Dutzend Ebenen zurückkehren zu
müssen und dementsprechend überall Abbruchbedingungen einzubauen, kann
man sich auch mit setjmp()/longjmp() behelfen.
Da liegt die einfachste Lösung ja schon auf der Hand, danke allen.
Karl Heinz Buchegger schrieb:> Ich würde mal sagen, deine ganze VOrgehensweise mit Spielfeld resetten> im Interrupt ist schon Unsinn genug.
Leider habe ich gerade mal ein halbes Jahr Schulerfahrung mit einem
Mikrocontroller und dem seiner Programmierung oder besser seinen
Gegebenheiten, was man lieber lassen sollte und wie man es besser macht.
Wie genau würdest du denn die Sache lösen, dass man über einen Taster
ein Spiel abbrechen kann oder liege ich dort schon im Ansatz falsch?
Marco M. schrieb:> Leider habe ich gerade mal ein halbes Jahr Schulerfahrung mit einem> Mikrocontroller und dem seiner Programmierung oder besser seinen> Gegebenheiten, was man lieber lassen sollte und wie man es besser macht.
Das ist schon ok.
Du bist nicht er einzige, der meint 'Tasten erfordern Interrupt'.
> Wie genau würdest du denn die Sache lösen, dass man über einen Taster> ein Spiel abbrechen kann oder liege ich dort schon im Ansatz falsch?
Tastenabfrage mit der bewährten Methode aus Entprellung
und dann
Peter II schrieb:>> man sich auch mit setjmp()/longjmp() behelfen.>> und wer macht dann den stack wieder leer?
Was soll denn ein leerer Stack? Dann krachts doch beim Fortsetzen.
longjmp() stellt natürlich den Stackpointer vom Aufruf von setjmp()
wieder her.
Jetzt haben alle so schnell geschrieben, dass ich zig Beiträge außer
Acht gelassen habe, also mal alle durchgehen.
Reinhard Kern schrieb:> Das ist wohl ein Design-Fehler. Du musst dir einfach einteilen, welche> Daten dauerhaft gespeichert werden und welche bei jedem Start neu> initialisiert, dann verschwindet das Problem und du musst zum Spielende> bloss zum Programmstart springen: da wird ja dann eh der Stack neu> initialisiert usw., also ein sauberer Neuanfang, bloss die Dauer-Daten> bleiben erhalten
In der Schule wurde uns gesagt, dass bei einem Hardwarereset der µC
"quasi" zum Anfang springt (Adresse 0000). So genau haben wir das ganze
nicht durchgenommen. Jedenfalls bin ich nun davon ausgegangen, dass bei
einem Reset der Controller von vorne beginnt und somit alles ab Zeile 0
neu lädt.
Wenn das falsch ist (ist es ja offensichtlich), sollte man mich bitte
korrigieren bzw. eine gute Erklärung verlinken, wo ich neues erlernen
kann.
Andreas B. schrieb:> Da ist schon das Problem. Das macht man nicht im Interrupt, das gehört> ins Hauptprogramm.
Danke. Wieder was neues gelernt.
Peter II schrieb:> Andreas B. schrieb:>> kann>> man sich auch mit setjmp()/longjmp() behelfen.>> und wer macht dann den stack wieder leer?
Das lasse ich lieber (:
Karl Heinz Buchegger schrieb:> Tastenabfrage mit der bewährten Methode aus Entprellung
Soll also heißen, dass ich den Taster mit der Methode aus
Entprellung immer wieder testen lasse (am besten im Abstand von ca.
300ms, da dies die durchschnittliche Reaktionsfähigkeit einen Menschen
ist) anstatt diesen auf einen Interrupt zu legen?
Marco M. schrieb:> In der Schule wurde uns gesagt, dass bei einem Hardwarereset der µC> "quasi" zum Anfang springt (Adresse 0000). So genau haben wir das ganze> nicht durchgenommen. Jedenfalls bin ich nun davon ausgegangen, dass bei> einem Reset der Controller von vorne beginnt und somit alles ab Zeile 0> neu lädt.> Wenn das falsch ist (ist es ja offensichtlich), sollte man mich bitte> korrigieren bzw. eine gute Erklärung verlinken, wo ich neues erlernen> kann.
Dein Denkfehler ist, dass du den Wunsch eines Benutzers, die aktuelle
Berechnung bzw. das aktuelle Spiel abzubrechen, mit einem 'Reset des µC'
gleichsetzt.
Ein µC-Reset ist ein einschneidendes Ereignis für einen µC. Sowas wie
ein Schlag mit dem Hammer auf den Hinterkopf, alle Lichter gehen aus und
danach wird er als Baby wiedergeboren.
Daher haben die meisten Geräte den Reset-Knopf wohlweislich so, dass man
da nicht so leicht rankommt.
Wenn dein Benutzer ein neues Spiel will, dann wird einfach die laufende
Berechnung gestoppt, ein Grundzustand wieder hergestellt und von dem
gehts weiter. Das ist aber kein Reset in dem Sinne, wie ein µC-Reset
aufgefasst werden muss. Ein µC-Reset ist im Grunde ein 'Strom aus -
Strom ein' ohne den Stromschalter tatsächlich anzufassen.
Marco M. schrieb:> Soll also heißen, dass ich den Taster mit der Methode aus> Entprellung immer wieder testen lasse (am besten im Abstand von ca.> 300ms
Die letzte Methode, die mit dem Timer, macht das so alle 5 bis 10
Millisekunden. Das hört sich jetzt kurz an, ist es aber für einen µC
nicht. In Prozent Rechenzeit ausgedrückt, bist du da weit unter 1%
>, da dies die durchschnittliche Reaktionsfähigkeit einen Menschen> ist) anstatt diesen auf einen Interrupt zu legen?
Ziel ist es, das Tastenprellen zu eliminieren. Der Mensch spielt da
überhaupt keine Rolle. Aus Sicht eines µC bewegt sich ein Mensch in
extremster Zeitlupe.
Karl Heinz Buchegger schrieb:> Die letzte Methode, die mit dem Timer, macht das so alle 5 bis 10> Millisekunden. Das hört sich jetzt kurz an, ist es aber für einen µC> nicht. In Prozent Rechenzeit ausgedrückt, bist du da weit unter 1%
Klar, das ist logisch... man merkt, dass ich noch nicht so lange mit der
Materie arbeite.
Karl Heinz Buchegger schrieb:> Ziel ist es, das Tastenprellen zu eliminieren. Der Mensch spielt da> überhaupt keine Rolle. Aus Sicht eines µC bewegt sich ein Mensch in> extremster Zeitlupe.
extrem ist ja schon fast untertrieben ;)
Marco M. schrieb:>> überhaupt keine Rolle. Aus Sicht eines µC bewegt sich ein Mensch in>> extremster Zeitlupe.>> extrem ist ja schon fast untertrieben ;)
:-)
erinnert mich immer an die Zeit als Digitaluhren mit Stoppuhr Funktion
aufkamen. Wer schafft es den Knopf 2 mal hintereinander am schnellsten
zu Drücken. Ich erinnere mich da so an 15 Hunderstel Sekunden als
ungefähres Minimum, schneller ging einfach nie.
In dieser Zeit arbeitet ein 1Mhz getriebener AVR rund 120-tausend
Befehle ab :-)