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.
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
@ 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.
@ 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.
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
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???
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...
@ Neuling (Gast)
>??? Also ist der erste durchlauf zu kurz oder nicht???
Nein.
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
(F_CPU / Prescaler) = Tics per Second Target Time * Tics per Second - 1 = Compare Wert
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...
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
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
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.)
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?
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.
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?
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.
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?
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.