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
Du musst den Interrupt auch lokal über das dazugehörige Enable-Bit freigeben. BTW: Um welchen µC handelt es sich eigentlich?
Außerdem änderst du im Interrupt nicht den Output, sondern wechselst die Datenrichtung.
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...
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...
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
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...
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.