Forum: Compiler & IDEs Interrupt/Timer Problem: Nur einmalige Ausführung


von Tobi (Gast)


Lesenswert?

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

von Hc Z. (mizch)


Lesenswert?

Welcher Controller?  (Wegen PORTC -> JTAG-Fuse?)

von Tobi (Gast)


Lesenswert?

AT90CAN128, JTAG liegt dort auf PORTF, LEDs blinken auf wie gewollt. Nur 
halt nicht durch Interrupt (bzw. durch mehr als einen Interrupt).

von Hc Z. (mizch)


Lesenswert?

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

von Stefan E. (sternst)


Lesenswert?

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.

von Tobi (Gast)


Lesenswert?

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.

von Tobi (Gast)


Lesenswert?

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.

von Stefan E. (sternst)


Lesenswert?

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'.

von Grrrr (Gast)


Lesenswert?

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.

von Rolf Magnus (Gast)


Lesenswert?

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.

von Stefan E. (sternst)


Lesenswert?

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.

von Rolf Magnus (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.