Interrupt Problem

Gast #339537
Lesenswert?
• ▲
▼
Hi
Ich habe den Quellcode im Anhang geschrieben, der auch soweit
funktioniert, jedoch nur wenn das "sei" im Label sek steht.
Die Aufgabe des Codes ist nach jedem Timer0 Overflow Interrupt einen
Zähler zu erhöhen und wenn dieser den Wert 31 hat einen weiteren Zähler
um eins erhöhen (dies geschieht immer so nach ca. 1 sekunde)
Wenn ich dass besagte "sei" entferne funktioniert der Code für exakt
eine Sekunde, danach nicht mehr. Wenn das "sei" an dieser Stelle ist
funktioniert der Code einwandfrei.
Was bewirkt das "sei" an dieser Stelle?

Ich freue mich auf eure Hilfe
Angehängte Dateien:
Gast #339538
Lesenswert?
• ▲
▼
Sichere mal Dein SREG, bevor Du die eigentliche
Interrupt-Service-Routine ausführst, nach der ISR mußt Du´s wieder
rücksichern. Also:

 in   Temp, SREG
 push Temp
.....
.....
 pop  Temp
 out  SREG, Temp
 reti
Gast #339539
Lesenswert?
• ▲
▼
Weil im sek Teil direkt (ohne reti) in die Endlosschleife gesprungen
wird, was zum einen dazu führt das es irgendwann garantiert zu einem
Stackoverflow kommt, zum anderen wird (ohne reti) das globale
Interruptflag nicht autom. gesetzt.
#339540
Lesenswert?
• ▲
▼
In dem Fall, wo du "sek" anspringst, beendest du deine ISR nicht mehr
mit "reti". Das hat einerseits den Effekt, dass das I-Flag im SREG
nicht wieder gesetzt wird und dadurch kein Interrupt mehr abgearbeitet
wird.

Dein "sei" täuscht nur vor, dass es funktioniert, aber dein Stack
läuft über, weil kein RETI erreicht wird, dass die Rücksprungadresse
des Int-Aufrufs wieder vom Stack nimmt.

Du musst deine ISR so schreiben, dass sie immer mit RETI beendet wird.
Der Übersichtlichkeit halber nimmt man dazu immer das selbe RETI. Denn
wenn das Programm etwas größer wird (wenn es eine Mainloop bekommt),
dann musst du in der ISR noch das SREG sichern und ggf lokale Variablen
beschaffen, indem du Registerinhalte vorübergehend auf Stack legst (PUSH
/ POP). Der Stack muss dabei immer ausgewogen sein, jedes PUSH braucht
sein POP, jedes (R)Call sein RET und jeder Int-Aufruf sein RETI.

Falls du mal übern Zaun schaun willst, dann schau mal hier:
www.hanneslux.de/avr

...
Gast #339541
Lesenswert?
• ▲
▼
Danke für die schnelle Hilfe!

Das Problem mit dem Stapelüberlauf habe ich verstanden, nur sehe ich
das irgendwie bei der simulation im Studio nicht?
Ich sehe auch keine Möglichkeit, wie ich dass umgehen kann (Ich bin
totaler neuling)

 in   Temp, SREG
 push Temp
.....
.....
 pop  Temp
 out  SREG, Temp
 reti

Wie kann mir das Helfen?
Gast #339542
Lesenswert?
• ▲
▼
Dieses Fragment sollte in jeder ISR (Interruptserviceroutine) stehen,
für die Pünktchen setzt Du den eigenlichen Code ein, den die ISR
abarbeiten soll. Verwendest Du dann in der ISR auch noch andere
Variablen, die Du auch im Hauptprogramm benutzt, so mußt Du diese
anfangs auch push-en und am Ende der ISR wieder pop-en, damit nach dem
Interrupt alles so ist, wie es vorher war.
Gast #339544
Lesenswert?
• ▲
▼
Das darfst Du nicht! RETI ist IMMER das letzte, was eine ISR ausführen
muß! Wenn Du aus der ISR ´raus willst, mußt Du immer noch die ganzen
POP-s und das RETI ausführen lassen, sonst raucht Dein Stack ab!
#339549
Lesenswert?
• ▲
▼
in   Temp, SREG
 push Temp
.....
.....
 pop  Temp
 out  SREG, Temp
 reti

Das ist natürlich Quark :-), es sei denn, Temp wird ausschliesslich in
ISRs verwendet.
Vollständig muss es so aussehen:
 push Temp
 in   Temp, SREG
 push Temp
.....
.....
 pop  Temp
 out  SREG, Temp
 pop Temp
reti

Ich habe immer gerne ein eigenes Register für die SREG-Sicherung
benutzt.

.def sreg_bak=R2

ISR:
in sreg_bak, SREG
.
.
out SREG, sreg_bak
reti

Das bietet sich an, wenn man noch freie Register hat oder es auf
kürzeste Interrupt-Laufzeit ankommt. Bei den RAM-losen Typen geht es
nur so.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren