Forum: Mikrocontroller und Digitale Elektronik Timer immer ungenau? Kurze Frage zur Rechnung (AVR)


von Neuling (Gast)


Lesenswert?

Hey, kurze Frage, vielleicht kann jemand helfen.
Wenn ich mittels einem Timer (z. B. beim atmega) eine genau definierte 
Zeit zwischen meinen CTC Interrupts haben möchte, berechne ich den 
compare wert ja so:

(F_CPU / Prescaler) = Tics per Second
Target Time * Tics per Second = Compare Wert

Soweit korrekt, oder? Bei 16 Mhz, Prescaler 64 und 1 ms habe ich dann 
als Wert 250.
So, wenn ich nun 250 ins Register schreiben würde, hätte ich aber laut 
Tutorial hier 251 Tics zwischen den Interrupts (Schritt von 250 auf 0), 
also sollte entsprechend 249 in register. Korrekt?

Nun meine Frage: Ist damit nicht das erste Intervall zu kurz? Weil hier 
starte ich ja bei 0, habe dann also nur 249 Tics bis zum Interrupt, also 
nur 0,000996 s. Ist dem so, oder habe ich hier einen Denkfehler? Wie 
löst man das am besten? Vor dem starten des Timers dessen zählregister 
manuell auf 249 setzen und ersten Interrupt ignorieren? Warum habe ich 
das dann noch nie so gesehen? Oder sehe ich was falsch?

Danke!

PS: Mir ist klar, dass das Problem aufgrund von Quarz ungenauigkeiten, 
etc. nicht oft relevant ist. Aber ich würde es dennoch gerne "richtig" 
machen.

von Peter (Gast)


Lesenswert?


von pitschu (Gast)


Lesenswert?

Die AVR timer zählen vorwärts. Wenn du also 250 ticks zählen willst, 
musst du 256-250 = 6 in den timer schreiben. Nach 250 ticks erreicht er 
den overflow, stellt auf 0 und löst den IRQ aus. im IRQ handler stellst 
du als erstes den timer wieder auf 6 - und läuft.
PS

von Falk B. (falk)


Lesenswert?

@ Neuling (Gast)

>Tutorial hier 251 Tics zwischen den Interrupts (Schritt von 250 auf 0),
>also sollte entsprechend 249 in register. Korrekt?

Ja.

>Nun meine Frage: Ist damit nicht das erste Intervall zu kurz?

Nein.

>Weil hier
>starte ich ja bei 0, habe dann also nur 249 Tics bis zum Interrupt, also
>nur 0,000996 s. Ist dem so, oder habe ich hier einen Denkfehler?

Muss deine Anwendung WIRKLICH so genau sein?

>Wie
>löst man das am besten? Vor dem starten des Timers dessen zählregister
>manuell auf 249 setzen und ersten Interrupt ignorieren?

Oder den Zähler mit -1 = 0xFFFF laden, geht genauso, nur ohne Interrupt.

>das dann noch nie so gesehen? Oder sehe ich was falsch?

Weil der erste Durchlauf meistens nie do geau sein muss, nur der Abstand 
(Frequenz) der folgenden Interrupts.

>PS: Mir ist klar, dass das Problem aufgrund von Quarz ungenauigkeiten,
>etc. nicht oft relevant ist.

Falsch. Ein Quarz ist deutlich genauer als 1/250.

von Falk B. (falk)


Lesenswert?

@ pitschu (Gast)

>Die AVR timer zählen vorwärts.

Nicht nur das, sie zählen auch ohne Nachladetricks des letzten 
Jahrtausends. Das Zauberwort lautet CTC-Mode.

von Spess53 (Gast)


Lesenswert?

Hi

>Die AVR timer zählen vorwärts. Wenn du also 250 ticks zählen willst,
>musst du 256-250 = 6 in den timer schreiben. Nach 250 ticks erreicht er
>den overflow, stellt auf 0 und löst den IRQ aus. im IRQ handler stellst
>du als erstes den timer wieder auf 6 - und läuft.

Machen nur Leute, die von CTC nichts gehört haben.

@Neuling (Gast)

Deine Berechnung ist falsch. Der OCR-Wert muss 249 sein.

MfG Spess

von Neuling (Gast)


Lesenswert?

Cool Leute, danke für eure Antworten.

pitschus Ansatz ist natürtlich super, aber ich würde lieber CTC 
verwenden und in der Interrupt Routine nicht immer selber den Timer 
schreiben müssen.

@Falk
Danke, sehr hilfreich. Aber widersprichst du dir nicht an einer Stelle?

Falk Brunner schrieb:
>>Nun meine Frage: Ist damit nicht das erste Intervall zu kurz?
>
> Nein.

Falk Brunner schrieb:
> Weil der erste Durchlauf meistens nie do geau sein muss, nur der Abstand
> (Frequenz) der folgenden Interrupts.

??? Also ist der erste durchlauf zu kurz oder nicht???

von Neuling (Gast)


Lesenswert?

Danke für die weiteren Antworten...

Spess53 schrieb:
> @Neuling (Gast)
>
> Deine Berechnung ist falsch. Der OCR-Wert muss 249 sein.

Neuling schrieb:
> also sollte entsprechend 249 in register

Aber das wollte ich doch tun...Ich bin verwirrt...

von Falk B. (falk)


Lesenswert?

@ Neuling (Gast)

>??? Also ist der erste durchlauf zu kurz oder nicht???

Nein.

von Spess53 (Gast)


Lesenswert?

Hi

>Neuling schrieb:
>> also sollte entsprechend 249 in register

>Aber das wollte ich doch tun...Ich bin verwirrt...

Um ein einen Abstand von einer 1ms bei 16MHz und Prescaler 64 für die 
Interrupts zu erreichen muss das OC-Register generell den Wert 249 
haben. Und nicht 250. Deine Formeln stimmen nicht.

MfG Spess

von Falk B. (falk)


Lesenswert?

(F_CPU / Prescaler) = Tics per Second
Target Time * Tics per Second - 1 = Compare Wert

von Neuling (Gast)


Lesenswert?

Danke für eure super Antworten. Und sorry sorry dass, ich mich etwas 
unklar ausgedrückt habe. Ich habe aus euren Beiträgen folgendes Vorgehen 
extrahiert:

Berechnung des Compare Wertes:
Falk Brunner schrieb:
> (F_CPU / Prescaler) = Tics per Second
> Target Time * Tics per Second - 1 = Compare Wert

Damit ergibt sich konkret für mich bei 16 Mhz / 64 und 1 ms:
Spess53 schrieb:
> Deine Berechnung ist falsch. Der OCR-Wert muss 249 sein.

Sind diese Berechnungen und Zusammenfassungen soweit korrekt?
Abschließend würde ich mich sehr über eine kurze Beantwortung folgender 
Frage freuen:
Ist mit diesen Werten und ohne weitere Anpassung von Registern das erste 
Intervall nun zu kurz oder nicht? Ich komme nämlich für das erste 
Intervall auf:

Neuling schrieb:
> 249 Tics bis zum Interrupt, also nur 0,000996 s.

Aber Falk sagt:
Falk Brunner schrieb:
> Nein.

Was übersehe ich hier? Würde mich sehr über einen abschließenden Hinweis 
freuen...

von Karl H. (kbuchegg)


Lesenswert?

Neuling schrieb:

> Ist mit diesen Werten und ohne weitere Anpassung von Registern das erste
> Intervall nun zu kurz oder nicht? Ich komme nämlich für das erste
> Intervall auf:

Probiers halt mit kleineren Zahlen aus.
Anstelle von 249, überlegst du dir wieviele Timerticks von Interrupt zu 
Interrupt vergehen, wenn der Top-Wert sagen wir 2 ist.
Was macht der Timer?

Er wird gestartet
1
   0  +----+
2
   1       |
3
   2       |
4
   0  +----+  <- der Timerwert ist 2, der Compare Match greift 
5
   1       |     und resettet den Timer zu 0
6
   2       |
7
   0  +----+  <- selbiges
8
   1       |
9
   2       |
10
   0  +----+  <- und nochmal
11
   1       |
12
   2       |
13
   0  +----+
14
   1       |

und wir sehen auch: nein, das erste Intervall ist nicht zu kurz. Von 
einem Compare Match zum nächsten werden immer 3 Timerticks des Timers 
benötigt. AUch beim ersten mal. 2 zum erhöhen, 1 zum resetten auf 0

von Neuling (Gast)


Lesenswert?

Super, danke für deine ausführliche Erklärung. Und sorry, dass ich mich 
so blöd anstelle.

Meine Frage kam von einer Stelle in den FAQ 
(http://www.mikrocontroller.net/articles/FAQ#Timer). Dort steht im CTC 
Abschnitt:
"denn auch der Überlauf von 249 zurück auf 0 ist ein Zählschritt"

Dies scheint dann aber ein Fehler zu sein, oder? Ich hatte es aus dem 
tutorial so verstanden, dass auch dies ein Zählerschritt wäre. Aber dem 
ist dann wohl nicht so, oder? Also wird im CTC Mode der Zähler einfach 
direkt wieder auf 0 gesetzt, sobald ein compare match vorliegt?

Vielen vielen Dank

von Karl H. (kbuchegg)


Lesenswert?

Neuling schrieb:
> Super, danke für deine ausführliche Erklärung. Und sorry, dass ich mich
> so blöd anstelle.
>
> Meine Frage kam von einer Stelle in den FAQ
> (http://www.mikrocontroller.net/articles/FAQ#Timer). Dort steht im CTC
> Abschnitt:
> "denn auch der Überlauf von 249 zurück auf 0 ist ein Zählschritt"

Genauso wie in meinem Beispiel.
Der "Überlauf" von 2 auf 0 ist ein Zählschritt.
Der Top-Wert war 2, aber es dauert 3 Timerticks um einmal von 0 
ausgehend wieder bei der 0 zu landen.

> ist dann wohl nicht so, oder? Also wird im CTC Mode der Zähler einfach
> direkt wieder auf 0 gesetzt, sobald ein compare match vorliegt?

Reihenfolge!
Offensichtlich wird bei jedem Zeittakt zuerst geprüft, ob eine Compare 
Match vorliegt. Tut er das, dann wird der Zähler auf 0 gesetzt. Tut er 
das nicht, dann wird der Zähler um 1 erhöht.
Aber: Wenn durch dieses Erhöhen ein Compare Match entsteht, dann wird 
das erst im nächsten Zeittakt erkannt. Denn diese Überprüfung findet 
statt, ehe der Timer erhöht wird. Nach dem Inkrement des Timers wird im 
selben Zeittakt kein Compare Match mehr erkannt.

1
The 8-bit comparator continuously compares TCNT0 with the Output
2
Compare Registers (OCR0A and OCR0B). Whenever TCNT0 equals OCR0A
3
or OCR0B, the comparator signals a match. A match will set the
4
Output Compare Flag (OCF0A or OCF0B) at the next timer clock
5
cycle.

*** at the next timer clock cycle ***

(d.h. erkannt wird er schon, aber er wirkt sich erst im nächsten timer 
clock cycle aus.)

von Neuling (Gast)


Lesenswert?

Danke danke danke! Es ist total Klasse, dass du (ihr) euch so viel Zeit 
für mich nehmt.

Nun habe ich es verstanden! Und das Tutorial ist falsch:
"denn auch der Überlauf von 249 zurück auf 0 ist ein Zählschritt"

Das ist kein Zählschritt, denn der "Übergang" wird doch direkt 
durchgeführt (also mit dem Takt der MCU) und nicht mit der 
Geschwindigkeit des Timers.

Mir ist absolut klar, dass von 0 bis n zählen genau "n" Schritte sind. 0 
nach 1, 1 nach 2, ..., n-1 nach n. Aber dann wird eben nicht wieder auf 
0 gezählt. Dann wird der CTC erkannt, der Interrupt aufgerufen und der 
Zähler auf 0 GESETZT. Und dann gehts wieder n Schritte von vorne los.

So wie es im falschen Tutorial steht, würde von 0 bis n gezählt (n 
Schritte), dann der Interrupt ausgelöst. Der Timer "zählt" weiter in 
seiner Geschwindkeit den Überlauf zu 0. Das stimmt aber offensichtlich 
nicht. Also ist das Tutorial an der Stelle falsch, oder spinne ich?

von Karl H. (kbuchegg)


Lesenswert?

Neuling schrieb:
> Danke danke danke! Es ist total Klasse, dass du (ihr) euch so viel Zeit
> für mich nehmt.
>
> Nun habe ich es verstanden! Und das Tutorial ist falsch:

Das ist schon richtig.

> Das ist kein Zählschritt, denn der "Übergang" wird doch direkt
> durchgeführt (also mit dem Takt der MCU) und nicht mit der
> Geschwindigkeit des Timers.

Der Timertakt ist hier ausschlaggebend. Hast du einen Vorteiler von 64 
eingestellt, dann bleibt der Timer 64 CPU-Takte lang auf 249 ehe er dann 
auf 0 gesetzt wird.

> Mir ist absolut klar, dass von 0 bis n zählen genau "n" Schritte sind. 0
> nach 1, 1 nach 2, ..., n-1 nach n. Aber dann wird eben nicht wieder auf
> 0 gezählt. Dann wird der CTC erkannt, der Interrupt aufgerufen und der
> Zähler auf 0 GESETZT.

Aber dieses 0 setzen dauert genau so lange, wie das Hochzählen des 
Timers um 1.

Wie bei einer Uhr!
Alle Sekunden sind gleich lang. Auch die, in der der Sekundenzeiger von 
der Sekunde 59 zur Sekunde 0 'springt'.

Will man mit einem Timer einen Sekundenzeiger nachbilden, dann setzt man 
den Compare-Match auf 59.

Und das stimmt auch dann noch, wenn du ins Getriebe eingreifst, so dass 
sich der Sekundenzeiger 5 mal so langsam bewegt, als normal. Der 
Sekundenzeiger, äh, Timer steht dann 5 Takte lang auf der 59, ehe dann 
(wenn eigentlich das hochzählen auf 60 drann wäre) bemerkt wird, das die 
59 vom Timer mit den 59 vom Compare Match übereinstimmen und der Timer 
anstatt auf 60 hochzuzählen auf 0 zurückgesetzt wird.

von Neuling (Gast)


Lesenswert?

Oh man, langsam werde ich irre im Kopf (liegt vielleicht auch an der 
Uhrzeit). Bevor ich zum Inhalt komme, muss ich kurz noch einmal sagen: 
Karl Heinz Buchegger, du rockst!!! Danke, dass du dir all die Zeit für 
meine sinnlose (aber mir sehr wichtige) Detailverliebtheit nimmst!!! 
DANKE!!!

Karl Heinz Buchegger schrieb:
> Der
> Sekundenzeiger, äh, Timer steht dann 5 Takte lang auf der 59, ehe dann
> (wenn eigentlich das hochzählen auf 60 drann wäre) bemerkt wird, das die
> 59 vom Timer mit den 59 vom Compare Match übereinstimmen und der Timer
> anstatt auf 60 hochzuzählen auf 0 zurückgesetzt wird.

Jetzt habe ich es, ich dachte bisher, der Interrupt wird dann direkt 
ausgelöst, aber er erfolgt ja quasi immer einen Zählertakt verspätet 
(hattest du ja auch geschrieben...). Also konkret (mit zahlen aus deinem 
Beispiel):

* T = 0
* 5 Takte vergehen
...
* T = 58
* 5 Takte vergehen, T wechselt auf 59, CTC match signalisiert, noch kein 
Interrupt ausgelöst (laut zitiertem Datenblatt)
* 5 Takte vergehen, T wechselt auf 0, Interrupt wird ausgelöst

Damit wird der Timer nach 60 "Hochzählungen" ausgelöst. Damit ist alles 
konsistent. Das Tutorial auch.

Abschließend meine letzte Frage:
Sehe ich es richtig, dass der Interrupt quasi immer einen Takt verspätet 
kommt und deswegen:
Target Time * Tics per Second - 1 = Compare Wert
gilt?

von c-hater (Gast)


Lesenswert?

Neuling schrieb:

> Abschließend meine letzte Frage:
> Sehe ich es richtig, dass der Interrupt quasi immer einen Takt verspätet
> kommt und deswegen:
> Target Time * Tics per Second - 1 = Compare Wert
> gilt?

Nein, du hast es immer noch nicht verstanden.

1)
Es spielt i.A. keine Rolle, wann der Interrupt im Zählzyklus ausgelöst 
wird, wichtig ist allein, daß er regelmäßig und im richtigen Abstand 
ausgelöst wird. Da es unabhängig vom Zählumfang immer den Reset nach 
Null gibt, wird praktischerweise an dieser Stelle der Interrupt 
ausgelöst.

2)
Daß der Zählzyklus einen Timertakt länger ist als der Wert, den man in's 
OCR-Register schreibt, hat rein garnichts mit dem Interrupt zu tun, so 
ein Timer läuft nämlich auch ganz ohne Interrupt, der ist mehr oder 
weniger ein Abfallprodukt. Der Grund liegt vielmehr darin, daß der 
Zähler "synchron" arbeitet, deswegen kann er nicht im gleichen Takt den 
Gleichstand zwischen TCNT und OCR erkennen und als Folge davon den 
Zählerstand in TCNT beeinflussen. Das kann er erst im nächsten Takt tun.

Die synchrone Arbeitsweise ist ein ganz grundlegendes Prinzip in der 
Digitaltechnik, denn sie sorgt für einen sicheren Betrieb der Sache. Man 
kann Zähler auch asynchron resetten, aber das funktioniert nur mehr oder 
weniger zufällig (durch Ausnutzung von Gatterlaufzeiten), denn wenn es 
die nicht gäbe und echte Gleichzeitigkeit herrschen würde, würde sich 
ein logischer Konflikt ergeben.

TCNT==OCR? ja -> TCNT=0 -> TCNT==OCR? nein

D.h.: zu einem ganz bestimmten Zeitpunkt tritt die Situation ein, daß 
die Frage TCNT==OCR? nicht mehr eindeutig beantwortbar ist. Wie schon 
gesagt sorgen Gatterlaufzeiten dafür, daß es keine echte 
Gleichzeitigkeit gibt, aber dieser logische Widerspruch wirkt sich 
trotzdem in der Form aus, daß der Rücksetzimpuls auf die Dauer einer 
solchen Gatterlaufzeit schrumpft, was u.U. zu kurz ist, um zuverlässig 
das Rücksetzen auszulösen.

Genau sowas vermeidet man mit der synchronen Arbeitsweise.

von Neuling (Gast)


Lesenswert?

Danke! Deine Ausführungen zur synchronen Arbeitsweise waren sehr 
hilfreich, danke.

c-hater schrieb:
> Es spielt i.A. keine Rolle, wann der Interrupt im Zählzyklus ausgelöst
> wird, wichtig ist allein, daß er regelmäßig und im richtigen Abstand
> ausgelöst wird.

Alles klar, aber wie weit ist denn der zeitliche "Abstand" vom 
Zählerstand x bis er das nächste mal wieder bei x ist? Also wenn ich OCR 
auf n-Setze und der Schritt von OCR zu 0 auch ein "echter" Zählritt ist, 
dann sind es doch n + 1 Schritte, oder?

Und daher muss ich OCR auf u - 1 setzen, wenn ich u Schritte dazwischen 
haben will, ist das so nun korrekt erklärt?

Die synchorne Arbeitsweise wirkt sich doch dann nur darauf aus, wann der 
Interrupt kommt. Ob er also bei OCR oder bei 0 ausgelöst wird. Konkret 
passiert dies bei 0, und das ist ja quasi um eins verschoben, aber weil 
das für alle Durchläufe gilt macht es keinen Unterschied. Korrekt? Und 
für den ersten durchlauf ist es egal, weil dort bei 0 noch kein 
Interrupt auftritt. Korrekt?

von Karl H. (kbuchegg)


Lesenswert?

Neuling schrieb:

> Alles klar, aber wie weit ist denn der zeitliche "Abstand" vom
> Zählerstand x bis er das nächste mal wieder bei x ist? Also wenn ich OCR
> auf n-Setze und der Schritt von OCR zu 0 auch ein "echter" Zählritt ist,
> dann sind es doch n + 1 Schritte, oder?

Ja.
Gemessen in Timer-Takten.

(Das betone ich deswegen, weil das aufgrund der Vorteilers ja nicht 
identisch sein muss mit CPU-Takten)

> Und daher muss ich OCR auf u - 1 setzen, wenn ich u Schritte dazwischen
> haben will, ist das so nun korrekt erklärt?

Im Prinzip: ja.
Wobei der Vorteiler natürlich noch mit in die Betrachtung einbezogen 
werden muss. Die Frage lautet daher: 'wenn ich u Schritte ...' von 
welchem Takt ist hier die Rede? CPU Takt oder Timer Takt?

Bei diesen Berechnungen und Betrachtungen gilt ausschliesslich und immer 
der Timer-Takt, der sich aus dem CPU-Takt unter Berücksichtigung des 
Timer-Prescalers ergibt.

> Die synchorne Arbeitsweise wirkt sich doch dann nur darauf aus, wann der
> Interrupt kommt.

Das ist ein klein wenig zu kurz gedacht.
Denn der Interrupt kommt nicht einfach so.
Wenn ein Compare Match vorliegt, wird erst mal nur das entsprechende 
Flag gesetzt. Ob dieses gesetzte Flag dann in weiterer Folge einen 
Interrupt auslöst oder nicht, ist eine Frage dessen, wie der Timer 
konfiguriert wird. Aber das Flag wird immer gesetzt. Und zwar im Timer 
Takt, bei dem vor dem Erhöhen das erst mal der Gleichstand festgestellt 
wird.

> Ob er also bei OCR oder bei 0 ausgelöst wird.

Vergiss die 0. die ist im Grunde nicht wichtig.
Wichtig ist der Gleichstand der beiden Register.
Dieser Gleichstand wird durch erhöhen des TCNT Registers irgendwann 
erreicht. Und im Timertakt danach, wird dann das Flag gesetzt und alle 
weiteren Operationen laufen dadurch an.


> passiert dies bei 0, und das ist ja quasi um eins verschoben, aber weil
> das für alle Durchläufe gilt macht es keinen Unterschied. Korrekt?

Exakt. Der Mechanismus ist immer derselbe. Bei allen Durchläufen. Und 
daher sind alle Durchläufe auch immer gleich lang.

> Und
> für den ersten durchlauf ist es egal, weil dort bei 0 noch kein
> Interrupt auftritt. Korrekt?

genau.

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.