Forum: Mikrocontroller und Digitale Elektronik "Reset" über einen ext. Interrupt in C - Sprungstelle


von Marco M. (Gast)


Lesenswert?

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

von Pascal H. (pase-h)


Lesenswert?

Wie wärs mit den Hardware Reset, den eigentlich jeder µC hat?
Mfg

von Marco M. (Gast)


Lesenswert?

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.

von Peter II (Gast)


Lesenswert?

einfach ein flag setzen und dann in den ensprechendne routingen abfragen


if (ende) {
  return;
};

von Marco M. (Gast)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

> 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.

von Karl H. (kbuchegg)


Lesenswert?

> 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!

von Peter II (Gast)


Lesenswert?

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.

von Reinhard Kern (Gast)


Lesenswert?

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

von Andreas B. (andreas_b77)


Lesenswert?

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.

von Peter II (Gast)


Lesenswert?

Andreas B. schrieb:
> kann
> man sich auch mit setjmp()/longjmp() behelfen.

und wer macht dann den stack wieder leer?

von Marco M. (Gast)


Lesenswert?

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?

von Karl H. (kbuchegg)


Lesenswert?

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
1
...
2
3
int main()
4
{
5
6
   ... initialisierungen
7
8
  InitGame();
9
10
  while( 1 ) {
11
12
    if( resetRequested ) {
13
      InitGame();
14
      resetRequested = FALSE;
15
    }
16
17
    if( activePlayer == Human ) {
18
      let Human Player do his move
19
    }
20
21
    else
22
      let Computer calculate its move
23
  }
24
}
25
26
void let Computer calculate its move
27
{
28
  .....
29
30
  irgendwelche Schleifen oder sonstiges
31
  und zwischendurch immer wieder mal
32
33
    if( resetRequested )
34
      return;
35
36
  an Stellen an denen es keine Rechenzeit kostet
37
  aber auch nicht zu weit auseinander, so dass sich
38
  eine lange Verzögerung ergibt.
39
}

von Andreas B. (andreas_b77)


Lesenswert?

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.

von Marco M. (Gast)


Lesenswert?

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?

von Karl H. (kbuchegg)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Marco M. (Gast)


Lesenswert?

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 ;)

von Marco M. (Gast)


Lesenswert?

Danke an alle, die sich die Mühe gemacht haben, mir zu helfen !

Ich denke, ich weiß nun, was ich zu tun habe.

von Karl H. (kbuchegg)


Lesenswert?

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 :-)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.