Forum: Mikrocontroller und Digitale Elektronik Sekunden Timer nicht synchron


von Jo S. (tigermatze)


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

von Karl H. (kbuchegg)


Lesenswert?

Was heißt 'nicht genau'? Wieviel Abweichung hast du?

von Karl H. (kbuchegg)


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;

von Karl H. (kbuchegg)


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
}

von MWS (Gast)


Lesenswert?

Der Wert, der errechnet wurde, muss für CTC minus 1 im OCRxA stehen, 
gibt 'ne Formel dazu im DB, aus der das hervorgeht.

von Uwe (de0508)


Lesenswert?

Karl Heinz hat das schon sehr gut verbessert,
mir fehlt noch die Definition von tmp_sek.

Ich verwende gerne
1
static uint8_t tmp_sek = 0;
 innerhalb der ISR,
dann ist gansklar wo die Variable verwendet wird. Und kein anderer 
Prozess kann sie verändern.

von Bingo (Gast)


Lesenswert?

Ist Second defined as volatile ?

mfg
Bingo Dänemark

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
Noch kein Account? Hier anmelden.