warum timer drift

Gast #4707082
Lesenswert?

Guten Morgen!
Habe auf meinen At90CAN128 folgendes Problem.
Der Timer driftet ab und ich verstehe nicht warum.
Wenn ich die Zeit Messe vom Interrupt dann habe ich eine Zeit von 10ms
Das Runled ist aber nicht 1000ms sondern 1003ms.
Warum habe ich so einen großen Fehler?
Lg

1
OCR0A = (uint8_t)(int16_t)(F_CPU / 1024 * 10e-3 + 0.5);  // preload for 10ms
2
  TCCR0A |= (1<<WGM01)|(1<<CS02)|(1<<CS00);      // divide by 1024
3
  TIMSK0 |= (1<<OCIE0A);        // enable timer Compare A Interrupt
4

5

6
ISR(TIMER0_COMP_vect)  //_evry 10ms Interrupt
7
{
8
  static int run=100;
9
  if(--run==0)
10
  {
11
    run=10;
12
    PORTG ^=(1<<RUNLED);
13
  }
14
}
#4707094
Lesenswert?

@am grundsätzlichstem (Gast)

>Warum habe ich so einen großen Fehler?

>OCR0A = (uint8_t)(int16_t)(F_CPU / 1024 * 10e-3 + 0.5);  // preload for 10ms

Die Zeile läßßt allein durch die 2 casts nichts Gutes verheißen.
Man kann nicht mit jedem CPU-Takt exakt 100ms erreichen, erst recht 
nicht mit einem 1024er Vorteiler!!! Der macht das eher schlimmer! Mach 
es

- ohne Vorteiler
- nur mit Ganzzahlen

Dann hat man deutlich bessere Chancen. Dabei muss allerdings die 
ISR-Frequenz hoch genug sein, damit OCR1A nicht größer als 65535 wird
1
#define F_CPU 8000000
2
#define F_TIMER 200
3
#define ORCxRELOAD ((F_CPU / F_TIMER) - 1)
4

5
#if ORCxRELOAD > 65535
6
#error Timer overflow. F_TIMER too low!
7
#endif
8
 
9
OCR0A = ORCxRELOAD;

Wenn das trotzdem nicht genau hinkommt, dann so.

AVR - Die genaue Sekunde / RTC
Gast #4707095
Lesenswert?

Was verwendest du denn als Taktquelle? Den R/C Oszillator? Oder einen 
Keramik-Resonator? Oder einen Quarz, und wenn ja, welche Bauart? Und ist 
der Oszillator kalibiriert? Sind Versorgungsspannung und Temperatur 
stabil?
#4707103
Lesenswert?

@am grundsätzlichstem (Gast)

>> Wieviel ergibt bei Dir F_CPU/1024 ?

>Das ergiebt 15.625!
>F_CPU ist 16000000.

Schön daß wir das jetzt wissen. Dann wollen wir mal Compiler spielen und 
die Rechnung nachvollziehen.

#define F_CPU 16000000
OCR0A = (uint8_t)(int16_t)(F_CPU / 1024 * 10e-3 + 0.5);  // preload for 
10ms

F_CPU / 1024 = 15625   normale Ganzzahldiviiosn ohne Rest

* 10e-3 = 156,25   Fließkommarechnung

+ 0,5 = 156,75  Fließkommarechnung

Zuweisung an OCR1A = 156 (Nachkommastellen werden abgeschnitten).

Und was ergibt das als ISR-Frequenz?

16 MHz  1024  (156+1) = 99,522292993630573248407643312102 Hz

Softwareteiler / 10 macht daraus 9,9522292993630573248407643312102 Hz

Das sind -0,47% Fehler.
Gast #4707104
Lesenswert?

Michael U. schrieb:
> Wieviel ergibt bei Dir F_CPU/1024 ?

Das ergibt 15.625!
F_CPU ist 16000000.
Verstehe nicht was du meinst:-\

Danke Grüße aus München

Falk B. schrieb:
> #define F_CPU 8000000
> #define F_TIMER 200
> #define ORCxRELOAD ((F_CPU / F_TIMER) - 1)
>
> #if ORCxRELOAD > 65535
> #error Timer overflow. F_TIMER too low!
> #endif
>
> OCR0A = ORCxRELOAD;

Das -1 in deiner Formel ist das richtig beim timer Compare  Interrupt?

Stefan U. schrieb:
> Was verwendest du denn als Taktquelle? Den R/C Oszillator? Oder einen
> Keramik-Resonator? Oder einen Quarz, und wenn ja, welche Bauart? Und ist
> der Oszillator kalibiriert? Sind Versorgungsspannung und Temperatur
> stabil?

Verwende ein SMD Quarz den Oszillator habe ich nicht kalibriert! Ist das 
bei so langen Zeiten nötig?
Lg
#4707110
Lesenswert?

@am grundsätzlichstem (Gast)
> #define ORCxRELOAD ((F_CPU / F_TIMER) - 1)

>Das -1 in deiner Formel ist das richtig beim timer Compare  Interrupt?

Ja, siehe Datenblatt. Denn der Timer zählt von 0-OCR1A, das sind OCR1A + 
1 Takte.

>Verwende ein SMD Quarz den Oszillator habe ich nicht kalibriert!

Muss man auch nicht, der ist selbst mit vergurkten Lastkapazitäten auf 
100-200ppm genau, das sind 0,02%

> Ist das bei so langen Zeiten nötig?

Der Stefan meinte den internen RC-Oszillator, denn muss man ggf. 
kalibieren.
#4707113
Lesenswert?

Hallo,

am grundsätzlichstem schrieb:
> Michael U. schrieb:
>> Wieviel ergibt bei Dir F_CPU/1024 ?
>
> Das ergiebt 15.625!
> F_CPU ist 16000000.
> Verstehe nicht was du meinst:-\

Also einen Takt für den Counter mit 64µs Zykluszeit.
Für 10ms müßtest Du also durch 156,25 teilen.

Geteilt wird also wohl durch 157 wegen Deiner Rundung.
Macht dann also 10,048ms für einen Zyklus.
Passt doch ganz gut, die 16MHz sind ja auch nicht ohne Toleranz.

Vorteiler 256 und Count 256 -  bei einem 16Bit-Counter dürfte die erste 
Kombi sein, die genau 100Hz (10ms) ergibt.
Bei 8Bit-Counter wären es wohl Vorteiler 128, Counter 125 - 1 für 1ms 
und dann eben in der ISR bis 10 zählen für 10ms.

Die Formelrechnerei macht nur Sinn, wenn man es nur ungefähr braucht...

Gruß aus Berlin
Michael
Moderator (Firma: Titel) Persönliche Seite #4707119
Lesenswert?

am grundsätzlichstem schrieb:
> Verwende ein SMD Quarz den Oszillator habe ich nicht kalibriert!
Wenn du einen Quarz verwendest gibt's nix zu kalibrieren.
Du hast also einem Quarz angelötet. Verwendest du ihn auch? Wie sind die 
Fuses eingestellt?

> Ist das bei so langen Zeiten nötig?
Prozentuale Abweichungen sind unabhängig von der absoluten Dauer. Es ist 
eher so, dass 1% Verlängerung einer Stunde viel länger ist, als 1% einer 
Sekunde ...
#4707123
Lesenswert?

@ Lothar Miller (lkmiller) (Moderator) Benutzerseite

>> Ist das bei so langen Zeiten nötig?

>Prozentuale Abweichungen sind unabhängig von der absoluten Dauer. Es ist
>eher so, dass 1% Verlängerung einer Stunde viel länger ist, als 1% einer
>Sekunde ...

Das ist ABSOLUT richtig ;-)
#4707131
Lesenswert?

Hallo,

Zeit ist relativ: wie lang 5 Minuten sind, hängt davon ab, auf welcher 
Seite der Klo-Tür man ist...

Sein Problem ist doch aber: der Timer hat Binärzähler mit wenigen festen 
Vorteilern. Da kann ich mit Kommastellen und Rundungen rechnen, wie ich 
will, am Ende wird binär ganzzahlig geteilt.
Damit dürfen auch mit dem Taschenrechner nur ganzzahlige Ergebnisse 
rauskommen, sonst passt es nicht.
Damit kann man für 10ms (100Hz) auch nur Vorteiler nehmen, wo das 
Ergebnis hinten auf 2 Nullen endet, sonst gibt es keinen ganzzahligen 
Teiler / 100 für das Count-Register.

Gruß aus Berlin
Michael
Gast #4707134
Lesenswert?

Falk B. schrieb:
> Sthet oben.

Du meinst das hier:

Falk B. schrieb:
> F_CPU / 1024 = 15625   normale Ganzzahldiviiosn ohne Rest
>
> * 10e-3 = 156,25   Fließkommarechnung

ok.

Falk B. schrieb:
>>Unter der äußerst verwegenen Annahme, dass 10e-3 = 0,001 oder 1/1000
>>bedeutet?
>
> Das ist nicht nur verwegen sondern sogar richtig!

15625 * 0,001 (oder *1/1000) ist demnach 156,25? Ahaaaa.
#4707146
Lesenswert?

@ Zweifler (Gast)

>>>Unter der äußerst verwegenen Annahme, dass 10e-3 = 0,001 oder 1/1000
>>>bedeutet?
>
>> Das ist nicht nur verwegen sondern sogar richtig!

>15625 * 0,001 (oder *1/1000) ist demnach 156,25? Ahaaaa.

Natürlich nicht. 10e-3 = 10 * 10^-3 = 0,01 = 1/100
Gast #4707148
Lesenswert?

Falk B. schrieb:
> @ Zweifler (Gast)
>
>>>>Unter der äußerst verwegenen Annahme, dass 10e-3 = 0,001 oder 1/1000
>>>>bedeutet?
>>
>>> Das ist nicht nur verwegen sondern sogar richtig!
>
>>15625 * 0,001 (oder *1/1000) ist demnach 156,25? Ahaaaa.
>
> Natürlich nicht. 10e-3 = 10 * 10^-3 = 0,01 = 1/100

Ok, ich gebs auf. Gegen solch höhere Mathematik kommt man nicht an.

Ich akzeptiere: 10e-3 ist sowohl 0,001 als auch 0,01, je nachdem, wie Du 
das brauchst.
Gast #4707429
Lesenswert?

Wie dem auch sei, ein Lösungsansatz wäre: Du rechnest aus, wie viel 
Abweichung pro Timerinterrupt entsteht.

In der ISR erhöhst du bei jedem Interrupt eine float Variable um diesen 
Wert.

Sobald die aufaddierten Fehler gleich (oder mehr) als ein Timer-Takt 
sind, machst du
a) ändert du OCR0A einmal so dass das nächste Intervall genau einen Takt 
kürzer als normal wird.
b) Die Variable wird um die Dauer eines Timertaktes verringert.

Beim nächsten Interrupt muss OCR0A wieder auf den "normalen" Wert zurück 
gestellt werden.

Dadurch erreichst du, dass ab und zu ein Timer-Takt ausgelasen wird. Die 
Interrupts werden ein kleines bisschen unregelmäßig aber dafür kommst du 
insgesamt im Durchschnitt auf die gewünschten 10ms.

Im Prinzip entspricht das den Schaltjahren. Der Februar wird jedes 
vierte Jahr ausnahmsweise um einen Tag verlängert, weil der Kalender zu 
schnell ist.

Du musst aber ab und zu ein Timer-Intervall um einen Takt verkürzen, 
weil dein Timer zu langsam läuft.
Gast #4707482
Lesenswert?

Michael U. schrieb:
> Hallo,
>
> am grundsätzlichstem schrieb:
>> Michael U. schrieb:
>>> Wieviel ergibt bei Dir F_CPU/1024 ?
>> Das ergiebt 15.625!
>> F_CPU ist 16000000.
>> Verstehe nicht was du meinst:-\
>
> Vorteiler 256 und Count 256 -  bei einem 16Bit-Counter dürfte die erste
> Kombi sein, die genau 100Hz (10ms) ergibt.
> Bei 8Bit-Counter wären es wohl Vorteiler 128, Counter 125 - 1 für 1ms
> und dann eben in der ISR bis 10 zählen für 10ms.
>
> Die Formelrechnerei macht nur Sinn, wenn man es nur ungefähr braucht...
>
> Gruß aus Berlin
> Michael

Dieser Ansatz hat mich jetzt auf eine sehr akzeptable Zeit basis 
gebracht!!
Danke an alle für die Hilfe!

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren