Forum: Mikrocontroller und Digitale Elektronik AVR (ATMega328P) Timer mal wieder zu langsam (~2Sec / Min)


von Spiffman G. (spiffman)


Angehängte Dateien:

Lesenswert?

Hallo,

ich habe mich auch mal an das Projekt DCF77 gewagt.
Bis die Zeit Synchronisiert wird lasse ich sie via Interrupt hoch 
zählen.
Dazu habe ich mir eine kleine Timerklasse geschrieben, die mir dabei 
helfen soll.
Jetzt habe ich allerdings bemerkt, dass meine Uhr ca. 2 Sekunden pro 
Minute zu langsam läuft und ich habe noch keine Idee warum.
Mein uC läuft mit 16MHz.

Timer2, der den 1ms-Interrupt erzeugt:
1
  //1ms Interrupt
2
  TCNT2  = 0;
3
  OCR2A  = (250 - 1);    // so gibt das 1ms - Pulse
4
  TCCR2A  = 0;        //Pins nicht verbunden, aber Clear Timer on Compare match (CTC) mode
5
  TCCR2B  = ( 1 << CS22);    //Prescaler 64
6
  TIMSK2  = ( 1 << OCIE2A);  //Timer/Counter2, Output Compare A Match Interrupt Enable

Interrupt-Routine:
1
ISR( TIMER2_COMPA_vect)
2
{
3
  GetTimerHelper().Interrupt1ms();
4
}

main:
1
    while(1)
2
    {
3
    GetTimerHelper().Process();    
4
    }

Wrapper für die globale Variable
1
CTimerHelper& GetTimerHelper()
2
{
3
  static CTimerHelper TimerHelper;
4
  return TimerHelper;
5
}

Inhalt Interruptroutine
1
void CTimerHelper::Interrupt1ms()
2
{
3
#if TIMER_SUPPORT_1MS
4
  do1ms++;
5
#endif
6
7
  ms++;
8
9
  if( ms % 10 == 0) do10ms++;
10
  #if TIMER_SUPPORT_100MS
11
  if( ms % 100 == 0) do100ms++;
12
  #endif
13
  if( ms >= 1000) {
14
    do1s++;
15
    ms = 0;
16
  }
17
}

Hat jemand eine Idee, wo ich schauen könnte?
Wenn ihr den Code kurz testen wollt geht das ganz einfach:
1
class ctest : CTimer
2
{
3
//hier eigenen code rein
4
 void Timer1s(){}
5
 void Timer10ms(){}
6
 void Timer100ms(){}
7
} test;

ggf müsst ihr noch diesen codeschnipsel vorher einfügen, dass alles 
klappt:
1
extern "C" {
2
  void __cxa_pure_virtual()
3
  {
4
    uart_puts_P( "ERROR!\n\r-->__cxa_pure_virtual\n\r");
5
    // put error handling here
6
  }
7
}


Auch wenn der Funktionsansprung etwas dauern sollte, der Timer2 läuft 
doch außerhalb des Programms weiter. D.h. die Zeit die dadurch verlohren 
wird sollte sich nicht auswirken, da der Interrupt dann einfach früher 
kommt.
Habt ihr eine Idee? Danke schon mal!

: Bearbeitet durch User
von Peter II (Gast)


Lesenswert?

Spiffman G. schrieb:
> Habt ihr eine Idee? Danke schon mal!

nicht wirklich, hast du einfach mal im Simulator getestet wie lange 10ms 
sind? Wenn es dort stimmt, dann liegt es an der Hardware, wenn nicht 
stimmt etwas mit der Software nicht.

von Arduinoquäler (Gast)


Lesenswert?

Peter II schrieb:
> dann liegt es an der Hardware, wenn nicht
> stimmt etwas mit der Software nicht.

Stimmt. Entweder liegt es an der Hardware oder an der Software.

Da sind wir ja schon einen Riesenschritt weiter.

von S. Landolt (Gast)


Lesenswert?

> TCCR2A  = 0

Das ist nicht CTC, sondern Normal Mode.

von Spiffman G. (spiffman)


Lesenswert?

S. Landolt schrieb:
>> TCCR2A  = 0
>
> Das ist nicht CTC, sondern Normal Mode.

Da hast du Recht! Tausend Dank, hab vor lauter Bäumen den Wald nicht 
gesehen! ;-)

korrekt wäre natürlich das:
1
  TCCR2A  = ( 1 << WGM21);  //Pins nicht verbunden, aber Clear Timer on Compare match (CTC) mode

von Peter (Gast)


Lesenswert?

Du könntest einfach mal einen Pin toggeln, mit hilfe des Timers?

von boah (Gast)


Lesenswert?

Peter schrieb:
> Du könntest einfach mal einen Pin toggeln, mit hilfe des Timers?

Und du hättest dein Hirn nach dem Hinweis von S. Landolt mal toggeln 
können.

von Peter II (Gast)


Lesenswert?

Arduinoquäler schrieb:
> Stimmt. Entweder liegt es an der Hardware oder an der Software.
>
> Da sind wir ja schon einen Riesenschritt weiter.

hä? wenn man 50% ausschließen kann durch den Test hilft das doch weiter?

von Pandur S. (jetztnicht)


Lesenswert?

Weshalb sollte man fuer eine Sekunde dekadisch zehlen ?
Und fuer sowas nimmt man den timer overflow interrupt.

von Peter II (Gast)


Lesenswert?

Jetzt Nicht schrieb:
> Weshalb sollte man fuer eine Sekunde dekadisch zehlen ?
warum sollte man sich den Computer unterwerfen?

> Und fuer sowas nimmt man den timer overflow interrupt.
aber der CTC ist dafür gut geeignet.

von Atduinoquäler (Gast)


Lesenswert?

Spiffman G. schrieb:
> Habt ihr eine Idee? Danke schon mal!

Ich weiss nicht bei welchem Prozessor ich nachschauen soll, aber
wenn nicht der CTC Mode eingestellt ist dann müsstest du deinen
Timer in der ISR "von Hand" zurücksetzen. Selbst dann gibt es
noch eine kleine zeitliche Verwerfung.

Und wenn dein Timer 8 Bit gross ist: ein Faktor 256/250 ist
ungefähr 62/60.

von npn (Gast)


Lesenswert?

Atduinoquäler schrieb:
> Ich weiss nicht bei welchem Prozessor ich nachschauen soll,

Am besten beim ATMega328P, denn "Spiffman" hat diesen µC genannt. Klingt 
logisch, oder? :-)

von Atduinoquäler (Gast)


Lesenswert?

npn schrieb:
> Klingt logisch, oder? :-)

Ja hab ich auf die Schnelle übersehen.
Verzeih mir bitte! Bitttääh!

von Joachim B. (jar)


Lesenswert?

Spiffman G. schrieb:
> Timer2, der den 1ms-Interrupt erzeugt:

und warum?

reicht für DCF77 nicht 10ms muss der IRQ nicht so oft angesprungen 
werden.

OK ich nutze meist IRMP und dort sind es 64µs IRQs aber ein mitlaufender 
Zähler macht dann alle 10ms die Verzweigung in die DCF77 Abfrage sowie 
Tastenabfragen nach Dannegger.

Alle 10ms mal nach dem DCF Bit reicht doch, ist entweder 100ms oder 
200ms aktiv und das kann man mitzählen.

von npn (Gast)


Lesenswert?

Atduinoquäler schrieb:
> npn schrieb:
>> Klingt logisch, oder? :-)
>
> Ja hab ich auf die Schnelle übersehen.
> Verzeih mir bitte! Bitttääh!

Ist ja gut, weine nicht und trockne deine Tränen :-))

von Spiffman G. (spiffman)


Lesenswert?

Joachim B. schrieb:
> Spiffman G. schrieb:
>> Timer2, der den 1ms-Interrupt erzeugt:
>
> und warum?
>
> reicht für DCF77 nicht 10ms muss der IRQ nicht so oft angesprungen
> werden.
>
> Alle 10ms mal nach dem DCF Bit reicht doch, ist entweder 100ms oder
> 200ms aktiv und das kann man mitzählen.

So kann ich den Vorteiler mit dem 8-Bit Timer geschickt wählen. Bei 
16MHz komm ich ganzzahlig auf 1ms. Daher teile ich quasi in der Software 
noch mal durch 10 und sample dann das DCF77 Signal alle 10MS

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.