Hallo Leute! Ich steh' etwas auf dem Schlauch. Ihr kennt das Problem: das Programm macht einfach nicht das, was man von ihm will. Man schaut sich das Programm x-mal an und ist irgendwann geneigt, den Fehler dem Compiler oder dem µC in die Schule zu schieben... Dann kommt jemand anderes daher und sieht den Fehler auf den ersten Blick. Also, ich habe ein Problem mit einem Interrupt. Nein, nicht das übliche. Der Interrupt läuft super. Sogar zu gut. Genauer gesagt möchte ich einen Interrupt zeitweise sperren. Klappt jedoch nicht. :-( Ok, der Reihe nach: Kommt ein Signal an INT1 meines Atmega32, wird eine Begrüßung auf das LCD ausgegeben. Unter bestimmten Bedingungen gibt der µC eine Fehlermeldung aus. Diese Fehlermeldung darf jetzt natürlich nicht von der Begrüßung überschrieben werden. Am Anfang meiner Fehlermeldung sperre ich deshalb INT1, gebe meine Fehlermeldung aus, warte auf eine Taste und gebe den Interrupt wieder frei. Da andere Interrupts weiterlaufen müssen, darf ich die Interrupt nicht global sperren, sondern nur den einen. [Hoffe, soweit war das noch verständlich..] hier mal ein Ausschitt aus meiner init(): // ext. Interrupt erlauben GICR |= _BV(INT0) | _BV(INT1); // bislang aufgelaufene Interrupts loeschen (sicher ist sicher) und dann Interrupts generell erlauben GIFR &= ~( _BV(INTF0) | _BV(INTF1) | _BV(INTF2) ); sei(); Ok, die Interrupts funktionieren jetzt. Jetzt meine Fehlermeldungsroutine: // Interrupt1 sperren GICR &= ~(_BV(INT1)); [Meldung ausgeben und auf Taste warten] // Interrupt1 wieder freigeben, GICR |= _BV(INT1); Der Interrupt INT1 funktioniert trotzdem noch, während er auf die Taste wartet :-( Hab ich das Datenblatt des Atmega32 nicht verstanden, bin ich zu blöd für C oder hab ich ein undokumentiertes Feature entdeckt?? Gruß.. Jochen
Externer Interrupt mit manueller Taste ist immer keine gute Idee.
Tasten prellen und neigen daher dazu, dass du dir deine Interrupts
x-mal auslösen lässt. Wenn du das schon tun willst, dann erstens wie
üblich in der ISR nur Flags setzen, keine langanhaltenden Aktionen,
zweitens dort (während die Interrupts innerhalb der ISR sowieso noch
gesperrt sind) das interrupt-enable-Bit für diesen Interrupt
zurücknehmen und es erst später wieder (timer-gesteuert) neu setzen.
Du hast völlig richtig erkannt, dass man vor dem Neusetzen alle
eventuell anhängigen Interrupts löschen sollte (geht nur bei
flankengetriggerten, pegelgetriggerte Interrupts werden immer
ausgelöst, solange der Pegel anliegt).
Aber:
> GIFR &= ~( _BV(INTF0) | _BV(INTF1) | _BV(INTF2) );
Hier hast du weder das Datenblatt noch die (avr-libc-)FAQ richtig
gelesen. ;-) Ein anhängiger Interrupt wird gelöscht, indem man ein
1-Bit schreibt, die FAQ erklärt warum das so ist und erklärt auch,
dass man das nicht mit einem read-modify-write macht wie du hier,
sondern einfach:
GIFR = _BV(INTF1);
Für die Modifikation von GICR außerhalb einer ISR würde ich übrigens
unbedingt vorher global die Interrupts sperren, sicher ist sicher.
Hallo! > Externer Interrupt mit manueller Taste ist immer keine gute Idee. Der ext. Interrupt ist keine Taste. Die Tastenabfrage mache ich über eine Routine, die auch entprellt. > Ein anhängiger Interrupt wird gelöscht, indem man ein > 1-Bit schreibt Oops.. :-) Danke für den Hinweis. Hab's korrigiert. Das dürfte jedoch nicht für mein Problem verantwortlich sein. > Für die Modifikation von GICR außerhalb einer ISR würde ich übrigens > unbedingt vorher global die Interrupts sperren, sicher ist sicher. Kann zumindest nicht schaden. Hab's eben ausprobiert. Keine Änderung. Aber meine Überlegung, daß SIG_INTERRUPT1 durch "GICR &= ~(_BV(INT1));" blockiert wird ist doch soweit richtig, oder? Gruß.. Jochen
> Aber meine Überlegung, daß SIG_INTERRUPT1 durch "GICR &= > ~(_BV(INT1));" blockiert wird ist doch soweit richtig, oder? Ja.
Hallo nochmal! Ich wollte nur Bescheid sagen, daß ich den Fehler jetzt gefunden habe. Es lag an meiner LCD-Routine! :) Ich sperre dort kurzzeitig INT1, um sicherzugehen, daß immmer beide halb-bytes zum LCD übertragen werden (war nötig, nachdem machmal das LCD ausging). Ich bin also doch nicht bekloppt, sondern nur unfähig.. ;-) Gruß.. Jochen
Jörg Wunsch wrote: > Für die Modifikation von GICR außerhalb einer ISR würde ich übrigens > unbedingt vorher global die Interrupts sperren, sicher ist sicher. grübel Warum würdest Du das?
> Ich bin also doch nicht bekloppt, sondern nur unfähig.. ;-)
Wenn du aber immerhin noch lernfähig bist, is das kein Problem ;)
Es ist generell ne gute Idee zum temporären sperren der Interrupts am
anfang den alten Zustand zu speichern, die Interrupts dann zu
deaktivieren und am ende den alten Zustand wieder herzustellen. Das
vermeidet viele solche Fehler.
Klaus wrote: > Es ist generell ne gute Idee zum temporären sperren der Interrupts am > anfang den alten Zustand zu speichern, die Interrupts dann zu > deaktivieren und am ende den alten Zustand wieder herzustellen. Das > vermeidet viele solche Fehler. Hm, darüber denke ich auch gerade nach. Ich versuche das Problem aber etwas abstrakter zu erfassen und will mich gar nicht an eine konkrete Anwendung klammern. Eigentlich dürfte das ja nur dann wichtig sein, wenn Funktionen die selbst Interrupts sperren, sich gegenseitig aufrufen, oder? Ich frage mich, ob man das möglicherweise per Design grundsätzlich vermeiden sollte? Aber kann man das immer?
Klaus W. wrote: > Jörg Wunsch wrote: > >> Für die Modifikation von GICR außerhalb einer ISR würde ich übrigens >> unbedingt vorher global die Interrupts sperren, sicher ist sicher. > > *grübel* > > Warum würdest Du das? Wei aufs GICR nur RMW funktioniert und zwischen den drei Schritten noch jemand andres dran rumfummeln könnte.
Sven Pauli wrote: > Klaus W. wrote: >> Jörg Wunsch wrote: >> >>> Für die Modifikation von GICR außerhalb einer ISR würde ich übrigens >>> unbedingt vorher global die Interrupts sperren, sicher ist sicher. >> >> *grübel* >> >> Warum würdest Du das? > > Wei aufs GICR nur RMW funktioniert und zwischen den drei Schritten noch > jemand andres dran rumfummeln könnte. Stimmt! - Aber das könnte dann ja nur eine ISR selbst sein. Und müsste dort explizit gemacht werden. Könnte man sowas wollen? Jedenfalls solange ich das nicht mache, sollte auch nichts passieren, oder? Viele Grüße, Klaus
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.