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.