Sekunden Timer nicht synchron

OP #2364351
Lesenswert?
• ▲
▼
Hi,

ich verwende einen AT90USB128 und möchte auf dem Timer/Counter 2 einen 
Sekunden Timer laufen lassen.
Leider läuft die Zeit nicht synchron, das heißt die Sekunde kommt nicht 
genau was ich mir irgendwie nicht erklären kann.
Ich habe den MC folgendermaßen konfiguriert:
1
ASSR = 0x00;    // Asynchronous Status Register;
2
TCCR2A = 0x00;    // Normal port operation, OC2A disconnected.
3
TCCR2B  = (1<<WGM21) | (1<<CS22) | (1<<CS21);  // CTC, prescaler 256 -> 8MHz / 256 = 31250Hz
4
//TCCR2B = 0x00;  // disabled
5
TCNT2 = 0x00;    // Timer/Counter Register;
6
OCR2A = 0xFA;    // (FA=250) 31250Hz / 250 = 125Hz -> jede 125-tel Sekunde ein Interrupt
7
      // 125Hz / 125 = 1Hz = 1
8
OCR2B = 0x00;    // Output Compare Register B;
9
TIMSK2 = 0x00;    // Timer/Counter Interrupt Mask Register;
10
TIFR2 = 0x00;    // Timer/Counter 2 Interrupt Flag Register;
11
GTCCR = 0x00;    // General Timer/Counter Control Register;
12

13
TIMSK2 = (1<<OCIE2A);    // Timer/Counter2 Interrupt Mask Register; the Timer/Counter2 Compare Match A interrupt is enabled.

Meine ISR wird also alle 125-tel Sekunde aufgerufen
1
ISR(TIMER2_COMPA_vect)
2
{
3
  Disable_interrupt();
4

5
  tmp_sek++;
6

7
  tmp_sek %= 125;
8
  if ( tmp_sek < last_tmp_sek )
9
    Second++;
10
  
11
  last_tmp_sek = tmp_sek;
12

13
  Enable_interrupt();
14
}

In der main-loop wird die Sekunde dann als Uhrzeit auf einem Display 
ausgegeben. Nur leider geht die Uhr falsch, weil die Sekunde nicht genau 
kommt.

Könnt ihr einen Fehler entdecken?


Vielen Dank
#2364377
Lesenswert?
• ▲
▼
ZUm Programm

OCR2A = 0xFA;    // (FA=250) 31250Hz / 250 = 125Hz -> jede 125-tel 
Sekunde ein Interrupt
      // 125Hz / 125 = 1Hz = 1

Erstens.
Wenn du dir im dir gewohnten Dezimalsystem ausrechnest, wann der Timer 
den Reset machen muss, warum schreibst du das dann in Hex hin?

  OCR2A = 250;

Zweitens.
Du musst 1 weniger nehmen. Du brauchst 250 Zähl-ZYKLEN. Auch das 
Rücksetzen vom Wert auf 0 ist ein Zyklus. Also

  OCR2A = 250 - 1;
#2364385
Lesenswert?
• ▲
▼
Drittens
Das hier
1
ISR(TIMER2_COMPA_vect)
2
{
3
  Disable_interrupt();
4

5
  tmp_sek++;
6

7
  tmp_sek %= 125;
8
  if ( tmp_sek < last_tmp_sek )
9
    Second++;
10
  
11
  last_tmp_sek = tmp_sek;
12

13
  Enable_interrupt();
14
}
ist wohl so ziemlich die komplizerteste Form die man finden kann wie man 
das schreibt.

3A
In einer ISR sind Interrupts sowieso disabled. Es gibt also keinen Grund 
Interrupts zu disablen. Und schon gar nicht zu enablen, wenn du keinen 
wirklich guten Grund dafür hast. Darum kümmert sich schon der COmpiler.

Einen % willst du drinn nicht wirklich haben. AVR können nur schlecht 
dividieren.

3B
1
ISR(TIMER2_COMPA_vect)
2
{
3
  tmp_sek++;
4

5
  if( tmp_sek == 125 ) {
6
    tmp_sek = 0;
7
    Second++;
8
  }
9
}

Antwort schreiben

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.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.