PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Atmega8 Interrupt Flags



Wombatz
27.08.2011, 16:01
Hallo zusammen,

Ich habe eine Frage bezüglich Interrupt-Flag Anforderungen. Ich habe in dem Buch von Roland Walter gelesen, dass ein Interrupt nicht während der Ausführung eines Interrupts abgearbeitet werden kann. Hier wird eine Interrupt-Flag-Anforderung gesetzt, die nach der Return-Funktion abgearbeitet wird.
So weit so gut...
Das ganze wollte ich einmal ausprobieren...und siehe da es klappt nicht:
- Die Gelbe LED soll leuchten
- Bei Interrupt0 (Taste1) soll nur die Grüne LED für 5 Sek leuchten
- Bei Interrupt1 (Taste2) soll nur die Rote LED für 5 Sek leuchten
Der Code unten funktionier auch wie gewollt, nur dass die Interrupt-Flag nicht gesetzt oder ausgeführt wird, wenn ich zwei Tasten hintereinander drücke.
Kann das einer erklären?

Hier der Code:

$regfile "m8def.dat"
$crystal = 3686400

Ddrd = &B00000000 'PD2 und PD3 sind Eingänge
Portd = &B11111111 'PD2 und 3 PullUP ein

Ddrb = &B00001110 'PB 1-3 Ausgänge
Portb = &B00000000 'PB1-7 auf LOW

On Int0 Interrupt0 'INT0 definieren und Labeln
On Int1 Interrupt1 'INT1 definieren und Labeln

Mcucr = &B00000000 'INT0 und INT1 wiederhoen solange L-Pegel
Gicr = &B11000000 'Int einschalten
Sreg.7 = 1 'Int global freigeben

Do
Portb.1 = 0 'Grüne LED aus
Portb.2 = 1 'Gelbe LED ein
Portb.3 = 0 'Rote LED aus
Loop

Interrupt0:
Portb.2 = 0 'Gelbe LED aus
Portb.1 = 1 'Grüne LED für 5 Sek ein
Waitms 5000
Return

Interrupt1:
Portb.2 = 0 'Gelbe LED aus
Portb.3 = 1 'Rote LED für 5 Sek ein
Waitms 5000
Return

Sauerbruch
27.08.2011, 18:09
Hi Wombatz,

des Rätsels Lösung findet sich im Datenblatt des ATMega8, in diesem Fall auf Seite 68:

Dort steht geschrieben, dass die Interrupt-Flags von INT0 und INT1 grundsätzlich gelöscht werden, wenn die Interrupts als "level" konfiguriert sind. Ist ja eigentlich auch logisch - sonst würden ja tausende von Interrupt-Anforderungen auflaufen, wenn man die Taste nur ´ne halbe Sekunde lang drückt.

Wenn Du die Interrupts also auf "Flanke" konfigurierst (z.B. fallend), ist dieses Grundproblem schon mal behoben - es lässt sich dann auch während einer ISR der nächste Interrupt aslösen.. Allerdings wirst Du was interessantes feststellen: Manchmal leuchtet die LED 10 Sekunden statt nur 5. Das liegt daran, dass jeder Taster prellt, und deshalb oft zu Beginn der ISR der gleiche Interrupt nochmal "auf Vorrat" ausgelöst wird. Das könntest Du ändern, indem Du vor dem return das entsprechende Interrupt-Flag löschst. Aber hier gibt´s noch eine lustige Besonderheit: Diese Flags löscht man, indem man sie auf "1" setzt (ist tatsächlich so - steht auch auf Seite 68!).

Um zu vermeiden, dass Interrupts zeitlich aufeinanderfallen, sollten die ISRs so kurz wie möglich sein (das wirst Du hier im Forum auch alle Nase lang lesen). "Guter Stil" wäre es also, in der ISR nur ein Flag-Bit zu setzen, und gleich wieder zurück in die Hauptschleife zu springen. Dort werden diese Flags dann regelmäßig abgefragt, und wenn sie 1 sind, wird die dazugehörige Befehlssequenz abgearbeitet (und das Flag auf 0 gesetzt - bis zum nächsten Interrupt).

Wombatz
27.08.2011, 20:21
Vielen Dank für deine Antwort.

Das erklärt es.

Als ich die MCUCR auf &B00001010 gesetzt habe, sah das schon anders aus. Die Flags wurden übernommen und auch ausgelöst. Und auch das Prellen konnte ich bemerken!

Jedoch was ich noch nicht ganz in diesem Zusammenhang verstehe ist, wieso der Taster erneut prellt. Hierfür wurden doch die PullUP Widerstände gesetzt (Portd = &B11111111 ). Also dürfte doch keine "zwischen Spannung" (zw.0-5V) dem Taster einen Ca.-Wert vorgaukeln, die die Tasten auslösen?

Wie erklärt sich denn dieses Phänomen?

Nun habe ich versucht vor Return mit GIFR.INT1 = 1 oder GIFR.INT0 = 1 die Flags zu löschen. Jetzt löscht er aber alle Flags.
Das heißt ich kann Tasten drücken und er spring nur zurück zur Hauptschleife, ohne auslösen der Flag.

Kann das sein, dass die Flags im Speicher immer an unterster Stelle abgelegt werden und er dann egal ob INT1 oder INT0 den letzten Interrupt löscht. Das wäre dann die Erklärung

Sauerbruch
27.08.2011, 23:07
Jedoch was ich noch nicht ganz in diesem Zusammenhang verstehe ist, wieso der Taster erneut prellt. Hierfür wurden doch die PullUP Widerstände gesetzt (Portd = &B11111111 ).

Der PullUp-Widerstand kann das Prellen eines Tasters nicht verhindern! Sein Job ist es, den Eingangspin auf ein sauberes "High" zu ziehen, wenn der Taster nach Masse hin geöffnet ist, d.h. der Pin "frei in der Luft" hängt. Wenn der Taster nach Masse geschlossen wird, gibt es meistens nicht nur einen einzigen, sauberen H-L-Übergang, sondern die Kontakte können halt ganz kurz ein paar mal hin und her schwingen, bevor sie ihre neue Position erreichen. Auf einem Oszi kann man sehen, dass tatsächlich oft ein paar H-L- und L-H-Übergänge hintereinander kommen -eben weil der Taster prellt.

GIFR.INT1 bzw. GIFR.INT0 auf 1 zu setzen wäre genau das, was ich auch versucht hätte, um die Folgen eines Nachprellens in der ISR zu beheben. Seltsam, dass es nicht klappt... Und Du hast es auch richtig zugeordnet, d.h. am Ende der ISR vom INT1 wird GIFR.INT1 auf 1 gesetzt, und das selbe mit ISR INT0 und GIFR.INT0?

Wombatz
28.08.2011, 09:06
Genau das habe ich gemacht...

Interrupt0:
Portb.2 = 0 'Gelbe LED aus
Portb.1 = 1 'Grüne LED für 5 Sek ein
Waitms 5000
Gifr.int0 = 1

Return

Interrupt1:
Portb.2 = 0 'Gelbe LED aus
Portb.3 = 1 'Rote LED für 5 Sek ein
Waitms 5000
Gifr.int1 = 1

komisch...

Searcher
28.08.2011, 12:23
Hallo,
geht es mit
Gifr.intf0 = 1
bzw.
Gifr.intf1 = 1
?
Gruß
Searcher

Wombatz
28.08.2011, 13:51
Nein leider nicht...hatte ich auch schon ausprobiert!!!

Searcher
28.08.2011, 15:19
Hallo,
echt seltsam. GIFR.INTF0 - INTF1 wäre richtig. Vielleicht die $hwstack Einstellung. Da würd ich mindestens $hwstack=40 versuchen, nicht das da noch im Stack was schiefgeht.

Falls Du es noch nicht kennst: http://halvar.at/elektronik/kleiner_bascom_avr_kurs/speicher_hwstack_swstack_frame/

Gruß
Searcher

Wombatz
29.08.2011, 19:22
Ne in der Tat, auch wenn ich den Hardware Stack auf 40 setze, ist es das gleiche! Egal welcher... also jeder 2.Interrupt wird gelöscht und nur der erste wird ausgelöst. Wenn ich den GIFR.INTF0/oder 1 = 1 weglasse... dann führt der den zweiten Interrrupt aus, jedoch kann es sein, dass der Taster prellt und erneut auslöst.

Danke trotzdem für den Hinweis HW-Stack...wieder was gelernt =)