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;
}
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).
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.