Hallo, ich habe ein Problem mit dem Verständnis von Interrupts. Mein Ziel war einen Timer zu erstellen der einmal in der Sekunde einen Interrupt erzeugt. Dazu habe ich den Timer1B (16Bit) im CTC-Mode, Clock ist 16MHz, durch Prescaler auf 15625. Dann habe ich als Compare-Wert passend 15625 gewählt. So müsste das gewünschte Verhalten eintreten. Ein erster Interrupt wird mit dem Programm auch ausgelöst...danach passiert jedoch nichts mehr?! Wieso? Muss ich in der ISR etwas zurücksetzen oder ähnliches? // Interrupt service routine for timer ISR(TIMER1_COMPB_vect){ switch_led(LED_DISPLAY,1); wait_ms(10); switch_led(LED_DISPLAY,0); } int main(){ // PORTC for LEDs PORTC = 0xFF; DDRC = 0xFF; // Configure a timer // Clock: 16000000HZ // Prescaler: 1024=>15625 is the clock, CTC Mode TCCR1B = (1<<CS12) | (1<<CS10) | (1<<WGM12); OCR1B = 0x3D09; // Compare value is 15625 // Activate Interrupts TIMSK1 = (1<<OCIE1B); sei(); while(1){ } return 0; }
AT90CAN128, JTAG liegt dort auf PORTF, LEDs blinken auf wie gewollt. Nur halt nicht durch Interrupt (bzw. durch mehr als einen Interrupt).
Dein Verständnis von dem, was passieren sollte, ist schon richtig. Ich sehe auch keinen Fehler im Programm (was nicht heißt, dass keiner drin ist - irgendwas muss faul sein). Ein beliebter Fallstrick, wenn ein Interrupt nicht tut, was er soll, ist auch, dass der Prozessortyp im Studio und/oder Makefile falsch angegeben ist (nur als Tipp, wo Du noch suchen könntest).
1 | OCR1B = 0x3D09; // Compare value is 15625 |
OCR1A legt den Top-Wert beim CTC-Mode fest, nicht OCR1B. Und so nebenbei: der korrekte Wert wäre 15624.
Hmm, erstmal Danke für deine Antwort. Im AVR-Studi ist der at90can eingestellt, das Makefile hat das AVR-Studi erstellt. Was mir aber aufgefallen ist beim debuggen mit dem JTAG Ice mkII, das im SREG das I-Bit nach der ISR nicht wieder gesetzt ist.
Stefan Ernst schrieb: > OCR1A legt den Top-Wert beim CTC-Mode fest, nicht OCR1B. Auch an dich Danken! Warum zählt der Timer bis zu dem in OCR1B definierten Wert hoch und löst den Interrupt aus? Irgendeine Verbindung muss doch bestehen. Ich dachte ich muss OCR1B verwenden da ich auch das TCCR1B beschreibe.
Tobi schrieb: > Warum zählt der Timer bis zu dem in OCR1B > definierten Wert hoch und löst den Interrupt aus? Tut er sehr wahrscheinlich nicht. Ich wette dieser erste Interrupt wird bereits beim Freigeben der Interrupts ausgelöst, weil zu diesem Zeitpunkt das Compare-Flag gesetzt ist (weil zu dem Zeitpunkt, wo der Timer gestartet wird, in OCR1B der Wert 0 steht). > Ich dachte ich muss OCR1B verwenden da ich auch das > TCCR1B beschreibe. Es besteht nicht der geringste Zusammenhang zwischen den beiden 'B'.
Ein allgemeiner Tip zur Interrupt-Nutzung: Es spielt hier aufgrund der Zeitabstände keine Rolle, aber erfahrungsgemäß ist das ein beliebter Fallstrick: Interrupt-Routinen sind so kurz wie irgend möglich und setzen nur Flags und ggf. andere Variablen. Deren Behandlung bzw. die Ausführung einer Timer-Ausgelösten Aktion erfolgt dann in main. Insbesondere sind Aufrufe von Subroutinen (ausser in Ausnahmefällen) ein absolutes "DONT DO IT". Gerade LCD-Subroutinen haben oft noch eigene Verzögerungen, so das man in späteren Projekten, das Problem bekommt. "Ohne Interrupt, direkt in main gehts aber wenn ich das im Interrupt mache, gehts nicht. Scheinbar werden Interrupts verschluckt". In Deinem Fall wäre der gängige Weg, den OCR beim ersten Interrupt auf einen Wert für 10ms zu setzen und beim nächsten wieder auf 1s. In main dann wird das Display (in irgendeiner Hinsicht) geschaltet. Falls Du meinem Rat, nur mal so zum probieren folgst, denke an "volatile". Viel Erfolg.
Tobi schrieb: > Ich dachte ich muss OCR1B verwenden da ich auch das TCCR1B beschreibe. Wie bist du denn auf diesen Zusammenhang gekomnen? Das hat nämlich mal überhaupt nichts mit einander zu tun. Du betreibst den Timer im Modus 4, da wird OCR1A als TOP-Wert genommen. Wenn er - wie bei dir - 0 ist, zählt der Zähler komplett durch. Hast du mal etwas länger gewartet? Das Intervall müßte etwa bei 4 Sekunden liegen, weil der Zähler dann erst ein zweites Mal den Wert 15625 erreicht hat, bei dem der Interrupt nochmal ausgelöst würde.
Rolf Magnus schrieb: > Wenn er - wie bei dir - 0 ist, zählt der Zähler komplett durch. Wie kommst du denn darauf? Bei OCR1A=0 bleibt der Zähler dauerhaft 0. Er macht dann quasi nichts anderes, als ständig überzulaufen.
Stefan Ernst schrieb: > Rolf Magnus schrieb: >> Wenn er - wie bei dir - 0 ist, zählt der Zähler komplett durch. > > Wie kommst du denn darauf? > Bei OCR1A=0 bleibt der Zähler dauerhaft 0. Er macht dann quasi nichts > anderes, als ständig überzulaufen. Stimmt. Ich hatte mich im Datenblatt verlesen.
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.