mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Timer "verschluckt" sich


Autor: Tom (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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!

Autor: Andreas W. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi
ISR(TIMER1_COMPA_vect)
{

  d1--;    //-1 Sekunde
}

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.

Autor: Tom (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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.

Autor: Andreas W. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
der Timer zählt nach der Iinitialisierung, das ist unabhängig vom 
auslösen des Interrupts.

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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);
   }

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja und natürlich ein & statt |, sorry.

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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!

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Thomas wrote:
> Ja und natürlich ein & statt |, sorry.
...Und kein "="!

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hab das Problem gelöst. Vielen Dank nochmals.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.