Forum: Compiler & IDEs Timer und Interrupts


von Henrik (Gast)


Lesenswert?

Hallo

Ich weiß, dass es zu dem Thema schon etliche Beiträge gibt, aber 
irgendwie bin ich daraus, und aus dem Tutorial nicht schlau geworden.

Ich will mit einem 16bit Timer und Interrupts eine LED zum blinken 
bringen.
Alle halbe Sekunde an und aus.

Dafür hab ich dann nen 16bit Timer programmiert, dass der in dieser zeit 
einen overflow hat.

Daran hab ich dann ein ISR gekoppelt, also ISR(TIMER1_OVF_vect).
Drinnen dann ein Programm, dass wenn die Lampe an ist, sie ausschaltet, 
und wenn sie aus ist, wieder einschaltet.

Leider tut sich auf dem Mikrocontroller rein gar nichts.

Hier meinm Programm:

#include<avr/io.h>
#include<stdint.h>
#include<avr/interrupt.h>
#ifndef F_CPU
#define F_CPU 1000000UL
#endif
#include<util/delay.h>
#ifndef__OPTIMIZE__
#endif


volatile uint8_t timer;

ISR(TIMER1_OVF_vect)
{ if (timer==0)
     {DDRB = (1<<DDB0);
      timer = 1;
     }
  if (timer==1)
     {DDRB = (0<<DDB0);
      timer = 0;
      }
}

int main ()
{
TCCR1B |= (0<<CS12) | (1<<CS11) | (0<<CS10);
timer = 0;
sei();

while(1) {



}
cli();
return 0;
}


Wäre toll, wenn mir da jemand helfen könnte, das Programm so zu 
korrigieren, dass es danach dann funktioniert!

Gruß und Danke im Voraus
Henrik

von Johannes M. (johnny-m)


Lesenswert?

Du musst den Interrupt auch lokal über das dazugehörige Enable-Bit 
freigeben.

BTW: Um welchen µC handelt es sich eigentlich?

von Stefan E. (sternst)


Lesenswert?

Außerdem änderst du im Interrupt nicht den Output, sondern wechselst die 
Datenrichtung.

von Johannes M. (johnny-m)


Lesenswert?

Stefan Ernst wrote:
> Außerdem änderst du im Interrupt nicht den Output, sondern wechselst die
> Datenrichtung.
...was aber, zumindest wenn die LED High-Side angeschlossen ist, auch 
funktionieren dürfte...

Allerdings ist das im Allgemeinen tatsächlich Unsinn. Im 
AVR-GCC-Tutorial und auch im AVR-Tutorial sind solche Sachen 
eigentlich sehr gut beschrieben (v.a. der Unterschied der einzelnen 
Register der Ports usw.). Wenn Du (OP) da nicht schlau draus geworden 
bist, dann hast Du es nicht gründlich genug gelesen. Ein bisschen Geduld 
muss man schon mitbringen...

von Johannes M. (johnny-m)


Lesenswert?

BTW: Dein Interrupt Handler lässt sich in einer einzigen Zeile 
unterbringen und die Variable timer ist ebenfalls überflüssig.
1
ISR(TIMER1_OVF_vect)
2
{ 
3
    DDRB ^= 1 << DDB0; //Aber wie oben gesagt: DDRx ist eigentlich nicht ganz korrekt...
4
}
Aber das nur ganz am Rande. Erst mal die grundlegenden Probleme in 
Angriff nehmen...

Die Timer haben übrigens i.d.R. Compare-Einheiten, mit denen sich 
bestimmte Pins ganz ohne Interrupt umschalten lassen. Ein Timer-Overflow 
ist für solche Sachen eh keine gute Wahl, zumal Du damit auf die Weise 
nie einen genauen 1Hz-Takt bekommst...

von Melvin (Gast)


Lesenswert?

1
ISR(TIMER1_OVF_vect)
2
{ if (timer==0)
3
     {DDRB = (1<<DDB0);
4
      timer = 1;
5
     }
6
  if (timer==1)
7
     {DDRB = (0<<DDB0);
8
      timer = 0;
9
      }
10
}
Du hast hier schon einen Logik-Fehler drin. Du testest in der ersten 
if-Anweisung, ob timer gleich Null ist. Dann wird eine Eins geschrieben 
und timer wird auf Eins gesetzt. In der nächsten if-Anweisung wird 
getestet, ob timer gleich Eins ist (ist true, weil du timer ja gerade 
auf Eins gesetzt hast!!) und es wird sofort wieder eine Null 
geschrieben.. Dann wird timer wieder auf Null gesetzt und das Spiel 
beginnt beim nächsten Mal von vorne.. es werden also immer beide 
Anweisungen ausgeführt und am Ende wird die Null geschrieben.

Ich glaube, man kann das lösen, indem du aus der zweiten if-Anweisung 
eine else-if-Anweisung machst, aber da ich nicht so C-sicher bin, weiß 
ich nicht, ob es diese Anweisung da gibt..
Zumindest hoffe ich, dass ihr versteht, was ich sagen wollte :-)

Gruß,
Melvin

von Johannes M. (johnny-m)


Lesenswert?

Melvin wrote:
> Ich glaube, man kann das lösen, indem du aus der zweiten if-Anweisung
> eine else-if-Anweisung machst, aber da ich nicht so C-sicher bin, weiß
> ich nicht, ob es diese Anweisung da gibt..
Gibt es (ohne Bindestrich allerdings...), aber an dieser Stelle wäre 
wenn überhaupt ein einfaches else angebracht. Schließlich schließen 
sich die Bedingungen gegenseitig aus...

Aber, wie schon oben angedeutet, ist die ganze if -Abfrage Käse...

von John G. (johngo)


Lesenswert?

Interruptroutinen sind immer etwas schwieriger zu testen als normale 
Funktionen. Ich baue deren Programmcode daher meist zuerst in eine 
normale Funktion ein, um das eigentliche Funktionieren des Codes zu 
überprüfen. Den zeitlichen verzögerten Aufruf der Funktion simuliere ich 
mit einer delay Funktion, z.B.

while(1)
{
   ledBlinker();

   delay(10000);
}

Und erst wenn das funktioniert, mache ich eine IR draus oder ich rufe 
die Funktion einfach in der IR auf, und erst dann schalte ich Timer und 
Interrupts ein.

Und nochmals, wie auch schon @sternst sagte, das Outputregister heißt 
PORTB und nicht DDRB, denn DDRB ist das DataDirectionRegister, mit du 
nur einmal am Programmanfang (und nicht wiederholt in der IR) festlegts, 
ob du den Port als Ausgang oder Eingang verwenden wills.

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.