Forum: Mikrocontroller und Digitale Elektronik Interrupt wird nicht gesperrt


von Christian D. (ddink)


Angehängte Dateien:

Lesenswert?

Hallo,

ich habe folgendes Problem, ich würde gern 8 LEDS (die Kanäle eines 
Multiplexers darstellen) vorwärts, rückwärts und random laufen lassen. 
Beim Umschalten, was über einen Interrupt (int1) ausgelöst wird, lasse 
ich die Leds einmal in der jeweiligen Richtung durchlaufen und springe 
dann ins normale Programm zurück. Der Durchlauf dauert ein ganzes Stück, 
und sollte eigentlich noch zur Interrupt Routine gehören (also die 
Interrupts sollten eigentlich gesperrt sein), jedoch löst er wenn die 
LEDS zum Beispiel vorwärts durchlaufen und ich die Taste drücke den 
Interrupt trotzdem aus, und die Leds laufen rückwärts (ihc hoffe mal das 
war verständlich erklärt^^). Bekomm das leider nicht raus, kann mir 
irgendwer Helfen? Gibt es irgendeine Einstellung wo das verhalten 
während eines Interrupts gesteuert wird? (Hab in meinem Buch nichts 
weiter gefunden.

Vielen Dank schon mal

von Z8 (Gast)


Lesenswert?

Ich habs aufgegeben. 1000 x reti (Rücksprungpunkte)

Das ist ein beschissener Prog.-stil! Eine ISR sollte einen
Einsprungpunkt und EINEN Ausprungpunkt haben. Wenn man das nicht
durchzieht, braucht man sich über so ein Programmverhalten nicht 
wundern.

Ich vermute das Du ein reti erwischt, ohne es zuwollen. (evtl.
in einer als vermeindliche Sub aufgerufenen Routine) Dadurch
wird der Int. enabled ohne mit der ISR fertig zu sein.

Korrigiere das bitte!

Gruß Z8

von Z8 (Gast)


Lesenswert?

habs gefunden! ... genau so ist es!!!!

Zuerst wird genTast angesprungen, danach breq   auf modech.
In modech ein reti (was mit Sicherheit nicht gewollt ist!)

von Z8 (Gast)


Lesenswert?

Schau Dir bitte mal den Unterschied zwischen

ret und reti an!

Ich denke es kankt daran.

Gruß Z8

von Christian D. (ddink)


Lesenswert?

Hmm, doch das reti in modech ist so gedacht. Wenn er modech ausgeführt 
hat, dann hat er das Register wo die Richtung drin steht geändert, und 
könnte eigentlich zurückspringen. Hab jetzt die Interrupts noch mal per 
Hand gesperrt und wieder aktiviert (was ja eigentlich quatsch ist) und 
mir ist aufgefallen, dass wenn ich während der Interruptroutine ein 
zweites mal die Taste drücke, er die Routine zuende ausführt, aber 
danach, den nächsten Interrupt bearbeitet, anstatt ihn zu ignorieren, da 
er ja während eines anderen Interrupts ausgelöst wurde. Selbst wenn ich 
die Interruptroutine ca 8 sek. lang mach, und nach einer Sekunde den 
int0 auslöse, dann arbeitet er den 8sekündigen gar ab, um danach den 
nächsten zu bearbeiten. Kann man das verhalten irgendwo sperren?

von Z8 (Gast)


Lesenswert?

ja siehe oben!

von Matthias L. (Gast)


Lesenswert?

>Selbst wenn ich die Interruptroutine ca 8 sek. lang mach

Du solltest dein Softwarekonzept mal überdenken!

von Z8 (Gast)


Lesenswert?

eine typische ISR sieht so aus:

isr:
   push
   push
   push

   rcall sub1
   rcall sub2
   rcall sub3

   pop
   pop
   pop

   reti

sub1:
   .
   .
   ret

sub2:
   .
   .
   ret

sub3:
   .
   .
   ret

Wenn Du soweit bist, kannst Du auch vorher zurückspringen.
Aber unter Beachtung des Stack!

Z8 :)

von Z8 (Gast)


Lesenswert?

eine typische ISR sieht so aus:

isr:
   push
   push
   push

   rcall sub1
   rcall sub2
   rcall sub3

   pop
   pop
   pop

   reti

sub1:
   .
   .
   ret  ; *wenn hier jetzt ein reti steht funktioniert das Prog.*
        ; *aber für den Rest der ISR ist der Int. frei gegeben*

sub2:
   .
   .
   ret

sub3:
   .
   .
   ret

Wenn Du soweit bist, kannst Du auch vorher zurückspringen.
Aber unter Beachtung des Stack!

von Christian D. (ddink)


Angehängte Dateien:

Lesenswert?

Es tut mir wirklich leid, aber ich bin noch ein wenig Anfänger, deshalb 
weiß ich nicht wirklich was man bei einer isr tun oder lassen sollte. 
Hab ein Buch "Mikrocomputertechnik mit Controlern der Atmel..." hier, 
aber da stand nichts weiter die Interrupts betreffend. Wenn ich dass da 
richtig verstanden hab, ist der Unterschied zwischen ret, und reti, dass 
reti neben der Funktion von ret (an die Ursprüngliche Adresse+2 
zurückspringen) noch die Interrupts wieder freischaltet.
Das mit den 8 sek war eigentlich nur als Test gedacht um das zu 
verstehen. Mich hat es gewundert, dass er einen Interrupt während der 
Routine speichert und ihn danach ausführt (wenn die Interrupts wieder 
freigeschalten sind). Ich hab das jetzt auch so umgeschrieben, dass ich 
nur 1x reti habe, in den Routinen "ruckdurch" "zufalldurch" "vordurch" 
und "wartex10ms" gibt es keine keine reti, nur ret.
Hab mir jezt echt Mühe gegeben^^, aber während der isr ausgelöste 
Interrupts (die er eigntlich ignorieren sollte), speichert er sich 
irgendwie ab, und nach Abarbeitung der Isr, arbeitet er den zweiten, 
nicht mehr ausgelösten Interrupt ab.

von Johannes M. (johnny-m)


Lesenswert?

Christian Deeg wrote:
> Hab mir jezt echt Mühe gegeben^^, aber während der isr ausgelöste
> Interrupts (die er eigntlich ignorieren sollte), speichert er sich
> irgendwie ab, und nach Abarbeitung der Isr, arbeitet er den zweiten,
> nicht mehr ausgelösten Interrupt ab.
Die speichert der nicht "irgendwie" ab. Wenn ein Hardware-Ereignis 
auftritt, zu dem ein Interrupt gehört, wird das dazugehörige Flag 
gesetzt. Und zwar immer (sofern es nicht schon gesetzt ist), völlig 
egal, ob die Interrupt-Bearbeitung freigegeben ist oder nicht. Wenn der 
dazugehörige Interrupt freigegeben wird und das Flag bereits gesetzt 
ist, dann wird der entsprechende Interrupt Handler ausgeführt.

Abgesehen davon: Die Dateierweiterung für Assembler-Quelldateien ist 
nicht .txt, sondern .asm! Wenn Du Deinen Code als *.asm schickst, wird 
der auch vernünftig formatiert angezeigt.

Darüberhinaus solltest Du auch mal einen Blick ins AVR-Tutorial 
werfen. Da wird vieles leicht verständlich erklärt...

von Christian D. (ddink)


Lesenswert?

Wenn Interrupts gesperrt sind, dürfte er aber doch die Flag für das 
Hardwareereignis nicht setzen, oder? Das mit dem .asm tut mir Leid, hab 
nur fix aus dem Programm rauskopiert.
Also er setzt während einer Isr den Flag, was er ja eigentlich nicht 
machen sollte, weil das ja gesperrt ist oder? (Der Interrupt reagiert 
auf ansteigende Flanke, die Taste ist am Ende der 1. Isr aber schon 
wieder losgelassen).

von Z8 (Gast)


Lesenswert?

Hi Christian,

>speichert er sich irgendwie ab

das ist normal! Du machst "eigendlich" nichts falsch!

Wenn Du soooolange ISRs hast, (macht man eigendlich nicht!)
must Du "anhängige Ints" kurz vor Ende in Deiner ISR löschen.

siehe:

General Interrupt Flag Register – GIFR

ldi r16 , 0
out GIFR, r16    ;löschen von anhängingen ext. Ints
reti

hab jetzt nicht mehr in Erinnerung, ob Du das level-gesteuert machst,
dann trift das nicht zu.

Gruß Z8

von Johannes M. (johnny-m)


Lesenswert?

Christian Deeg wrote:
> Wenn Interrupts gesperrt sind, dürfte er aber doch die Flag für das
> Hardwareereignis nicht setzen, oder?
Nochmal: Das Flag wird immer gesetzt, wenn das entsprechende 
Hardware-Ereignis auftritt! Ansonsten könnte man keine 
Hardware-Ereignisse durch Polling abfragen. Die "Interrupt-Freigabe" 
steuert nur die Bearbeitung des Hardware-Ereignisses als Interrupt 
Request.

> Also er setzt während einer Isr den Flag, was er ja eigentlich nicht
> machen sollte, weil das ja gesperrt ist oder? (Der Interrupt reagiert
> auf ansteigende Flanke, die Taste ist am Ende der 1. Isr aber schon
> wieder losgelassen).
Siehe oben. Und Du solltest Dich mit Entprellung befassen. Das 
Prellen ist nämlich schätzungsweise der Grund dafür, dass das Flag 
erneut gesetzt wird. Die Auswertung mechanischer Kontakte über 
Interrupts ist sowieso nicht ratsam.

von Matthias L. (Gast)


Lesenswert?

>Wenn Interrupts gesperrt sind, dürfte er aber doch die Flag für das
>Hardwareereignis nicht setzen, oder?

Doch. Tritt das Ereignis auf, wird das Flag gesetzt. Ist die zugehörige 
ISR nicht freigegeben, bleibt es beim gesetzten Flag. Sonst wird die ISR 
aufgerufen und das Flag gelöscht.


>Also er setzt während einer Isr den Flag,..

Falls das Ereignis während der Abarbeitung der ISR nochmal auftritt, 
ja.


> die Taste ist am Ende

Tasten prellen und gehören grundsätzlich nicht per Interrupt 
abgefragt.

von Sven S. (stepp64) Benutzerseite


Lesenswert?

Doch. Das Flag wird immer gesetzt, wenn ein Ereignis auftritt. Aber wenn 
der Interrupt gerade gesperrt ist, springt er halt nicht in die Routine. 
Aber merken dass da was war tut er sich schon. Ist ja auch richtig so. 
Er soll ja jeden Interrupt mitbekommen. Du hast als Programmierer dafür 
zu sorgen, dass jedes Ereignis auch bearbeitet wird und genau desshalb 
macht man die ISR so kurz wie möglich und nicht mehrere Sekunden lang.

Sven

PS: Bin wohl zu langsam auf der Tastatur....

von Z8 (Gast)


Lesenswert?

Hi Sven,

>PS: Bin wohl zu langsam auf der Tastatur....

yes :)

von Christian D. (ddink)


Lesenswert?

Ahh, ich hab das Sekundenlang gemacht, um mir eben dieses Verhalten zu 
erklären, jetzt erscheint mir das auch logisch. Ich wollte extra den 
Interrupt nehmen weil ich dacht dass ich dadurch die Taste entprellen 
kann (was ja auch funktionieren würde, wenn er denn die Flag nicht 
trotzdem speichern würde). Aber jetzt werde ich wohl doch den steinigen 
Weg nehmen^^. Oder kann man vllt die Flag irgendwie vor Ende des 
Interrupts löschen?

von Matthias L. (Gast)


Lesenswert?

>Oder kann man vllt die Flag irgendwie vor Ende des
>Interrupts löschen?

Sicher. Indem du eine EINS auf dieses Bit schreibst. Das löst aber dein 
Entprellproblem nicht!

von Z8 (Gast)


Lesenswert?

Hey Matthias,

eine NULL! schreibst.

Reden wir vom gleichen Bit im GIFR-Register ?

von Matthias L. (Gast)


Lesenswert?

>eine NULL! schreibst.

eine EINS:

>>When an event on the INT1 pin triggers an interrupt request, INTF1
>>becomes set (one).
>>If the I-bit in SREG and the INT1 bit in GICR are set (one), the MCU
>>will jump to the corresponding
>>Interrupt Vector. The flag is cleared when the interrupt routine is
>>executed.
>>Alternatively, the flag can be cleared by writing a logical one
>>to it. This flag is always
>>cleared when INT1 is configured as a level interrupt.

von Z8 (Gast)


Lesenswert?

>>>When an event on the INT1 pin triggers an interrupt request, INTF1
>>>becomes set (one).

-> also eine NULL!

wenn ich nicht will, das ein "nachfolgendes Ereignis" einen Int.
auslösen soll.

Der Phasenschieber :)

von Matthias L. (Gast)


Lesenswert?

Du solltest den von mir zitierten Abschnitt nochmal, und vollständig 
lesen!

von Z8 (Gast)


Lesenswert?

was ?

>the flag can be cleared by writing a logical one
>to it

was, was, was?

nach einem Reset ist dieses Bit 0, also dürfte eine 1
einen änhängigen Int. signaliesieren. ?

von Matthias L. (Gast)


Lesenswert?

>nach einem Reset ist dieses Bit 0, also dürfte eine 1
>einen änhängigen Int. signaliesieren. ?

Beides korrekt.

Aber es ging darum, ein gesetztes Bit zu löschen.

von Z8 (Gast)


Lesenswert?

>>Alternatively, the flag can be cleared by writing a logical one
>>to it

ich halte das für eine Datenblattente!

von Matthias L. (Gast)


Lesenswert?

>ich halte das für eine Datenblattente!

Kannst du gerne tun.

von Uwe .. (uwegw)


Lesenswert?

Nein, dass ist keine Ente!
Grund: diese Interruptflag befinden sich meist irgendwo in 
Konfigurationsregistern für die zugehörige Funktionseinheit. Beim ADC 
des Mega32 z.B. ist das Flag ADIF im Register ADCSRA enthalten. Wenn man 
nun in dieses Register schreiben will, kann man dabei dieses Bit einfach 
ignorieren und dort eine Null schreiben, das beeinflusst das Flag nicht. 
Man muss also nicht erst den aktuellen Wert des Flags auslesen, um es 
beim Schreibzugriff nicht ungewollt zu löschen.

von spess53 (Gast)


Lesenswert?

>>>Alternatively, the flag can be cleared by writing a logical one
>>>to it

>ich halte das für eine Datenblattente!

Mag sein, aber interessanterweise funktioniert es so.

MfG Spess

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.