Hallo hab da ein kleines Problem,
und zwar will ich meinen Timer in eine Endlosschleife einfügen, aber
egal wo ich die Schleife setze, irgendwie klappt es nicht.
Entweder werden die Timer nicht abgearbeitet oder aber die LED welche an
Port B0 angeschlossen ist blinkt im falschen takt und das Programm wird
nur einmal abgearbeitet. Hoffe jemand kann mir helfen.
Gruß Paul
#include <avr/io.h>
#include <avr/interrupt.h>
//Variablen für die Zeit
volatile unsigned int millisekunden;
volatile unsigned int sekunde;
volatile unsigned int minute;
volatile unsigned int stunde;
int main(void)
{
DDRB = 0xff;
// Timer 0 konfigurieren
TCCR0 = (1<<WGM01); // CTC Modus
TCCR0 |= (1<<CS01); // Prescaler 8
// ((1000000/8)/1000) = 125
OCR0 = 125-1;
// Compare Interrupt erlauben
TIMSK |= (1<<OCIE0);
// Global Interrupts aktivieren
sei();
while(1)
{
/*Hier kann die aktuelle Zeit
ausgeben werden*/
}
}
/*
Der Compare Interrupt Handler
wird aufgerufen, wenn
TCNT0 = OCR0A = 125-1
ist (125 Schritte), d.h. genau alle 1 ms
*/
ISR (TIMER0_COMP_vect)
{
millisekunden++;
if(millisekunden == 16000)
{
sekunde++;
millisekunden = 0;
}
sekunde++;
if(sekunde == 60)
{
minute++;
sekunde = 0;
}
stunde++;
if(minute == 1)
{
PORTB |= (1<<PB0);
}
if(minute == 1)
{
PORTB &= ~(1<<PB0);
}
}
}
Pepe schrieb:> blinkt im falschen takt und das Programm wird> nur einmal abgearbeitet.
Wie schnell blinkt sie?
Woran erkennst du, das das Programm nur einmal abgearbeitet wird?
:-)
Die LED blinkt einmal auf und anstelle einer Minute blinkt sie
vielleicht 10 sekunden auf. Wenn ich die Schleife nicht drin habe so wie
oben funktioniert es.
"sekunde" nur innerhalb des "if(millisekunden == 16000)" erhöhen, nicht
unkonditional danach nochmal, und dasselbe für die anderen Variablen.
Je nach Microcontroller musst du auch ein Interrupt-Statusregister
auslesen und beschreiben, wenn der Interrupt ausgelöst wurde, um den
Interruptzustand zurückzusetzen, da der sonst nicht nochmal ausgelöst
wird (siehe Datenblatt).
Pepe schrieb:> Vielen Dank für die schnellen Antworten.>> Hast du das etwa so gemeint???
Im Grunde ja.
Aber überleg mal:
> ISR (TIMER0_COMP_vect)> {>> millisekunden++;>> if(millisekunden == 16000)> {> sekunde++;> millisekunden = 0;> }>> if(sekunde == 60)
Wann kann den sekunde überhaupt 60 werden?
Doch wohl nur dann, wenn vorher millisekunden 16000 war und daher
sekunde um 1 hochgezählt wurde. Wenn das nicht der Fall war, dann kann
sekunde auch nicht 60 sein.
> {> minute++;> sekunde = 0;> }>> if(minute == 1)> {> PORTB |= (1<<PB0);> }
wenn minute gleich 1 ist, dann schaltest du die LEDEIN>> if(minute == 1)> {> PORTB &= ~(1<<PB0);> }
wenn minute gleich 1 ist, dann schaltest du die LEDAUS
In summe ergibt das:
möglichst komplizert: wenn Minute gleich 1 ist, dann die LED einschalten
und gleich darauf wieder ausschalten. Und du denkst ernsthaft, dass du
das sehen kannst, wenn die LED ein paar Nanosekunden leuchtet?
Der Rest stimmt schon.
Die Endlosschleife ist immer in main
Und den Interrupt brauchst du auch nicht zurücksetzen. Durch den Aufruf
der ISR wird der automatisch zurückgesetzt.
So hab es jetzt noch einmal ein bisschen verändert:
Im Grunde genommen soll das ganze später eine Messung ergeben. Soll 4h
messen und das für 1 min. Danach soll das ganze wieder von vorne
beginnen.
Aber der Counter zählt ja weiter oder? Kann man den irgendwie wieder
reseten?
Hier mal der Code:
Hab jetzt mal nen break drin in der Hoffnung das wemnn die zweite
Schleife unterbrochen wird die erste wieder von 0 beginnt.
Aber wahrscheinlich muß erst mal der Counter genullt werden oder???
Gruß Andi
Das Problem ist ich kann den ISR (TIMER0_COMP_vect) nicht in die
Schleife mit einfügen dann bekomme ich vom AVR Studio ne Fehlermeldung
bei der Schleife.
Wie soll das funktionieren, wenn die Minuten von 0 bis 59 laufen
if(minute == 60)
{
minute = 0;
stunde++;
}
und du sie hier auf 240 testen willst?
if(minute == 240)
{
PORTB |= (1<<PB0);
}
Das geht so nicht. Wenn du so arbeiten willst, brauchst du durchlaufende
Minuten, keine "klassischen" Minuten wie bei der Uhr (0..59).
Logisch kannst du die vier Zeitvariablen nach der Messung zurücksetzen.
Dabei daran denken, dass du auch den Hardware-Timercounter nullst.
Das macht so keinen Sinn mit der Schleife im Interrupt. Sinn des
Interrupts ist es ja, daß der automatisch periodisch aufgerufen wird und
du den möglichst schnell wieder verlässt, damit der in der nächsten
Millisekunde wieder aufgerufen werden kann. Bei jedem Aufruf zählst du
die nächste Millisekunde, falls der Kommentar stimmt, daß der Interrupt
jede Millisekunde aufgerufen wird. In dem Fall auch "millisekunden ==
1000" testen.
Interruptzustand zurücksetzen hängt vom Chip und der
Entwicklungsumgebung ab. Wo ich letztens einen Freescale-Chip getestet
hatte, musst Bit 7 im RTCSC-Register setzen, damit der Interrupt erneut
ausgelöst wurde. Kann aber sein, daß mit "ISR (TIMER0_COMP_vect)" das
alles schon von alleine gemacht wird oder dein Microcontroller sowas
nicht braucht. Daher Datenblatt zum Microcontroller lesen und die
Erklärung zu "ISR" in der Compiler-Anleitung lesen.
Das mit der äußeren while-Schleife und dem break ist übrigens identisch,
wie wenn du die äußere while-Schleife und das break einfach weglassen
würdest. Man sollte es auch besser formatieren, also nach geschweifter
Klammer eine Ebene einrücken und wieder zurück bei geschweifter Klammer
zu, sodaß man die Struktur besser sehen kann.
Bist du sicher, daß C-Programmierung das Richtige für dich ist? Hat
normalerweise nicht was mit Versuch und Irrtum zu tun, sondern mit
überlegtem und planvollem vorgehen :-)
Pepe, schmeiss alle while() in der ISR raus. Du musst und kannst
ohne auskommen. Du hast ein while in der main(). Schreib dein Programm
so, dass kein while in der ISR ist und dafür das while in der main()
benutzt wird.
Deine Zeitvariablen (minute&stunde) kannst du auch in main() benutzen!
Die ISR ist dann nur für das Hochzählen der Zeitvariablen
verantwortlich. Lies dir den Artikel Interrupt durch und beachte das
Thema atomaren Datenzugriff mit der cli/sei Klammer.
1
// Eine neue Hilfsvariable um die Wartezeit in Minuten zu zählen
Ich würde an deiner Stelle auch darüber nachdenken, die Minuten nicht
raufzuzählen sondern runterzuzählen, so wie bei einem Countdowntimer.
In main() setzt du die minuten auf die Zeit, die es abzuwarten gilt. UNd
dann wird einfach in main() ständig überprüft, ob die Minuten wieder auf
0 heruntergezählt wurden. Die Stunden brauchst du nicht wirklich. 4
Stunden sind 240 Minuten und das geht mit einer 8 Bit Variablen noch
gut.