Guten Abend,
Mein Programm soll (u.A.) durch Drücken eines Tasters, welcher durch den
Timer 0 ständig abgefragt wird, den Timer 1 aktivieren. In der Timer0
ISR befinden sich alle Routinen zum Abfragen der Eingänge (Taster) und
Timer 1 soll exakt jede Sekunde ein Interrupt liefern, sodass eine
Variable runtergezählt werden kann. Die Variable wird dann in der Main
als Bestandteil eines 7-Segment Zählers ausgewertet. Die Ausgabe erfolgt
dabei über 3 7 Seg. Anzeigen.
Also, es wird eine Zeit eingestellt, die über die 3 7-Seg. Anzeigen
angezeigt wird, bspw. 300 für 3 Minuten, 00 Sekunden. Wenn ich nun den
Taster drücke, der ja alle paar ms durch Timer0 abgefragt wird, soll
Timer 1 aktiviert werden, der dann in 1s-Schritten eine Variable
runterzählt.
Soweit funktioniert alles, bis auf eine Kleinigkeit: Wenn ich den Taster
drücke, passiert es manchmal, dass sich der Timer 1 beim ersten
Runterzählschritt "verschluckt", er zählt also nicht ab der 1. Sekunde 1
Sekunde herunter, also so: 3.59 - 3.58 - 3.57 usw, sondern überspringt
die 3.59 manchmal ganz schnell, also eher in der Zeit eines Bruchteils
einer Sekunde. Ab 3.38 läuft dann alles richtig.
Hier mal die Codeausschnitte:
void init()
{
TCCR0 = (1<<CS01);
TCNT0 = 0x00; //Timer0 Startwert auf 0 setzen
TCCR1B = (1<<WGM12) | (1<<CS12); //Timer1 CTC, Vorteiler = 256
OCR1A = F_CPU / 256; //Vergleichsregister laden mit Wert 31250
TCNT1 = 0;
TIMSK |= (1<<TOIE0); //Timer 0 Overflow enable (Tasterabfragen)
sei(); //generelle Interruptfreigabe
}
ISR(TIMER0_OVF_vect)
{
if(PORTB |= 1<< PORTB0)
{
TIMSK |= (1 << OCIE1A);
}
}
ISR(TIMER1_COMPA_vect)
{
d1--; //-1 Sekunde
}
Das Ganze ist natürlich nur ein Ausschnitt. Ich versteh nicht, warum es
manchmal nicht richtig geht. An der Entprellung der Taster kann es nicht
liegen. Auch wird das Timer1-Zählregister Anfangs auf 0 gesetzt, so dass
dort beim Starten des Timers keine wirren Werte stehen können.
Beeinflusst Timer0 vielleicht Timer1?
Freue mich über jede Hilfe.
Grüße!
Hi
1 | ISR(TIMER1_COMPA_vect) |
2 | {
|
3 | |
4 | d1--; //-1 Sekunde |
5 | }
|
wo declarierst du d1? ich wird sagen das ist ein int oder? also 16Bit. speere mal wenn du den wert setzt die interrupts. Dann geht es ohne "verschlucken" oder du machst es zu einen uint8_t. Siehe Stichwort atomarer Zugriff.
d1 wird global als volatile uint8_t deklariert. Kann also nicht daran liegen. Irgendwie scheint der permanent das Register TCNT1 zu zählen, anders kann ichs mir nicht erklären. Wenn ich nämlich gleich vor "TIMSK |= (1 << OCIE1A); " in der Timer0 ISR TCNT1 lösche (also mit TCNT1 = 0), funktionert es. Aber das kann ja auch nicht die Lösung sein, denn sonnst wird Timer1 immer wieder "resettet", wenn ich den Taster auch während des Zählens drücke. Oder wird generell nach der Timer1 Initialisierung (wie in init) das Register TCNT1 gezählt, obwohl Timer1 noch gar nicht durch "TIMSK |= (1 << OCIE1A);" freigegeben wurde?
> if(PORTB |= 1<< PORTB0)
Meinste nicht, da wäre PINB sinnvoller? Und ein "&" anstelle des "|="?
Oder übersehe ich da was funktionelles? Der Ausdruck dürfte so, wie er
da steht, immer wahr sein.
der Timer zählt nach der Iinitialisierung, das ist unabhängig vom auslösen des Interrupts.
Nee, ist klar. Hab das auch im Programm so. Ich hab das fürs Forum nur
fix umgeschrieben, weil alles über #defines läuft und da ich die der
übersichtlichkeitshalber nicht auch noch einfügen wollte, hab ichs eben
so gemacht. Danke für den Hinweis. Also, muss heißen:
if(PINB |= 1<< PINB0)
{
TIMSK |= (1 << OCIE1A);
}
Thomas wrote: > Also, muss heißen: > > if(PINB |= 1<< PINB0) Das ist immer noch falsch! Es macht so keinen Sinn, abgesehen davon, dass der Ausdruck in den Klammern immer wahr ist!
Thomas wrote:
> Ja und natürlich ein & statt |, sorry.
...Und kein "="!
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.