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