Forum: Mikrocontroller und Digitale Elektronik ATmega644 Timer1 CTC-Mode Timerinterrupt unregelmäßig


von Daniel M. (daniel_91)


Angehängte Dateien:

Lesenswert?

Hallo an alle hier im Forum.

Wie der Betreff schon sagt, geht es um den Timer 1 des AVR ATmega644 im 
CTC-Mode (Mode 4).

Zum Anfang ein paar Informationen zum Hintergrund des Programms:

Es handelt sich bei dem Programm um eine Funkuhr.
Das Erfassen und Abtasten des DCF77-Signals, sowie die Berechnung der 
Zeit und des Datums funktionieren einwandfrei. Auch die Ausgabe der Zeit 
auf ein LCD (240x64 Pixel, Controller: T6369C) funktioniert. Ich habe 
dazu den Timer so kofiguriert, dass alle 10ms ein Interrupt ausgelöst 
wird. In der ISR wird zum einen das DCF77-Signal abgetastet sowie bei 
jedem 100. Aufruf das Zeitwerk für die Uhr gesetzt (Sekunden, Minuten, 
Stunden, etc. hochzählen).

Der AVR wird mit einem 8MHz Quarz betrieben, der Prescaler für den Timer 
1 ist auf 64 eingestellt, das Output Compare-Register ist auf 2499 
gesetzt.
Der Output Compare-Interrupt ist aktiviert und auch global sind alle 
Interrupts aktiviert. Mit dieser Konfiguration sollten alle 10ms die ISR 
abgearbeitet werden.

Das ist auch der Fall, allerdings ergibt sich im Laufe der Zeit eine 
deutliche Ungenauigkeit. Nach ca. 10 Stunden Betriebszeit, "hinkt" die 
Uhr ca. 2 Minuten hinterher. Ich habe darufhin alle Werte noch einmal 
nachgerechnet, konnte aber keinen Fehler finden.

Da die Ausgabe der Zahlen auf dem LCD recht aufwendig ist (es wird eine 
7-Segment Anzeige nachgebildet), habe ich das ganze anschließend nur mit 
normalen Zahlen ausgegeben, also die aus dem Zeichensatz des 
LCD-Controllers.

Das kurriose daran ist, dass die Uhr nun "vorauseilt". Um dieses 
Phänomen weiter zu untersuchen, habe ich das Programm so umgeschrieben, 
das das Hauptprogramm nach jedem Durchlauf 5 Sekunden wartet 
(_delay_ms(5000);). Dadurch "hinkt" die Uhrzeit wieder enorm hinterher 
(nach 10 Minuten Betriebszeit um etwa 2 Sekunden!).

Kann es sein, das Interrupts die _delay_ms()-Funktion nicht an jeder 
Stelle unterbrechen können? Weil anders kann ich mir die Abhängigkeit 
der Interruptaufrufe vom _delay_ms() nicht erklären.

Im Anhang ist der gesamte Code angehägt.

Ich hoffe ihr könnt mir helfen.
Vielen Dank schonmal im Vorraus.

: Bearbeitet durch User
von Frank (Gast)


Lesenswert?

Daniel M. schrieb:
> Ich hoffe ihr könnt mir helfen.
Verwende kein delay_ms für eine Uhr.

Wenn Du schon einen Timer hast, brauchst Du doch nur noch eine 
Zählvariable. Wenn Du 5 Sekunden warten willst, stellst Du die auf 500 
ein, zählst die in der ISR eins runter und wartest, bis sie NUll 
geowrden ist.

von Fritz (Gast)


Lesenswert?

Daniel M. schrieb:
> das Output Compare-Register ist auf 2499
> gesetzt.

Ich komme beim Nachrechnen nur auf 1249, was aber auch der korrekte Wert 
ist.

Aus eher grundsätzlichen Erwägungen heraus finde ich, dass das ganze 
Umrechnungsgedöns nicht in den Handler gehört.

Und sofern du nicht warten willst, ob sich jemand durch deinen Code 
wühlen mag, machst du dich eben selbst ans Debugging. 
Voraussetzungen:Oszi, Freqenzzähler oder geeignetes DMM und einen freien 
Pin am µC.

von DingsDa (Gast)


Lesenswert?

Daniel M. schrieb:
> In der ISR wird zum einen das DCF77-Signal abgetastet sowie bei
> jedem 100. Aufruf das Zeitwerk für die Uhr gesetzt (Sekunden, Minuten,
> Stunden, etc. hochzählen).

Du bekommst die exakte Zeit vom DCF-77 Empfänger!?
Warum zählst Du dann selbst die Uhrzeit hoch?
Du musst doch nur die DCF-77 Daten dekodieren und anzeigen.
(Habe mir deinen Code nicht angeschaut).
Für mich unverständlich!

Wenn Du dich auf den CTC-ISR als Clocksource verlässt, dann ist
der beobachtet Effekt normal. Der 8 MHz Quarz des AVR ist nicht für
Uhrenbetrieb geeignet. Ausser Du machst einen Langzeittest und 
korrigierst Deine Werte für das Compare-Register.
Danach läuft Deine Uhr auch nicht viel genauer.

Als Hinweis: TOSC1, TOSC2 Beschreibung mal lesen.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Daniel M. schrieb:
> wird. In der ISR wird zum einen das DCF77-Signal abgetastet sowie bei
> jedem 100. Aufruf das Zeitwerk für die Uhr gesetzt (Sekunden, Minuten,
> Stunden, etc. hochzählen).

 a) In der ISR nur einen Zähler erhöhen, sonst nichts. Wenn du nach 2
    Stunden weniger als 720000 ISR Aufrufe gezählt hast (oder mehr) ist
    dein Quarz daran schuld.
 b) Probiere mal das DCF77-Signal zu simulieren (aus EEPROM einspielen),
   um zu sehen was dann passiert. Es wird vielleicht dein Problem nicht
   lösen, aber zumindest hast du dann eine Vorstellung davon, was
   reinkommt und was herauskommen soll und wird eventuelle 
Schwierigkeiten
   mit schwachem bzw. verzerrtem Signal ausschliessen.

von Peter D. (peda)


Lesenswert?

DingsDa schrieb:
> Du bekommst die exakte Zeit vom DCF-77 Empfänger!?
> Warum zählst Du dann selbst die Uhrzeit hoch?

Weil der Empfang leicht gestört werden kann, z.B. durch Gewitter, 
Staubsauger, alte PC-Monitore usw.
Jede DCF-77 Uhr hat immer auch einen Quarz für die interne Uhr.

DingsDa schrieb:
> Der 8 MHz Quarz des AVR ist nicht für
> Uhrenbetrieb geeignet.

Die billigen MC-Quarze sind schon sehr stabil. Mit Abgleich kriegt man 
wenige Sekunden/Jahr hin.

von LostInMusic (Gast)


Lesenswert?

Ich würde mit einem Assemblerprogramm den Quarz ausmessen:
1
.EQU COUNT = 60*60*1000000  ; 32-bit-Zähler reicht dafür (noch)
2
3
    ldi   r16, 0xFF
4
    out   DDRC, r16
5
6
    ldi   r22, Low (LWRD(COUNT))
7
    ldi   r23, High(LWRD(COUNT))
8
    ldi   r24, Low (HWRD(COUNT))
9
    ldi   r25, High(HWRD(COUNT))
10
11
    ldi   r16, 0x00
12
    out   PORTC, r16
13
  
14
_Loop32bit:
15
    subi  r22, 1
16
    sbci  r23, 0 
17
    sbci  r24, 0 
18
    sbci  r25, 0 
19
    nop
20
    nop
21
    brne  _Loop32bit
22
23
    ldi   r16, 0xFF
24
    out   PORTC, r16
25
26
_End:
27
    rjmp  _End

Schwingt der Quarz mit genau 8 Mhz wird eine an PortC angeschlossene LED 
exakt eine Stunde lang leuchten. Schau, wieviele Sekunden kürzer oder 
länger sie wirklich leuchtet (*) und rechne die relative Abweichung aus.

(*) Wobei Du natürlich sicherstellen musst, dass Deine Referenzuhr 
präzise geht. Eine DCF-gesteuerte Uhr bietet sich hier an, oder das 
Zeitzeichen der stündlichen Nachrichten im Radio.

>Der 8 MHz Quarz des AVR...

Was meinst Du damit?

von Daniel M. (daniel_91)


Lesenswert?

Hallo,
danke erstmal für die vielen Antworten.


> Verwende kein delay_ms für eine Uhr.
>
> Wenn Du schon einen Timer hast, brauchst Du doch nur noch eine
> Zählvariable. Wenn Du 5 Sekunden warten willst, stellst Du die auf 500
> ein, zählst die in der ISR eins runter und wartest, bis sie NUll
> geowrden ist.

Das delay_ms ist in der Uhr auch nicht implementiert, lediglich ein 
_delay_us(2) ist vorhanden, um einen Enable-Impuls für das LCD zu 
erzeugen. Aber auch wenn ich das Programm KOMPLETT OHNE _delay_xx laufen 
lasse, tritt der Fehler auf.

> Ich komme beim Nachrechnen nur auf 1249, was aber auch der korrekte Wert
> ist

Ja, entschuldigung. Genau das ist auch der Wert, den ich errechnet habe 
und der im Programm steht. Habe mich verschrieben.

> Du bekommst die exakte Zeit vom DCF-77 Empfänger!?
> Warum zählst Du dann selbst die Uhrzeit hoch?
> Du musst doch nur die DCF-77 Daten dekodieren und anzeigen.
> (Habe mir deinen Code nicht angeschaut).
> Für mich unverständlich!

Das mache ich deshalb nicht, weil ich nicht andauernd das DCF77-Signal 
abtasten möchte, sondern maximal 1 mal pro Tag die Uhrzeit aktualisieren 
will. Auch ist das Signal ja nicht permanent ungestört.

> Aus eher grundsätzlichen Erwägungen heraus finde ich, dass das ganze
> Umrechnungsgedöns nicht in den Handler gehört.

Ich dachte mir zuerst auch, dass das unter Umständen zuviel Programmcode 
ist. Aber ich habe zum Testen den ISR-Handler so gekürtzt, dass nur eine 
Variable hochgezählt wird. Und auch da trat der Fehler unverändert auf. 
Und im Angesicht dessen, dass der Fehler durch Änderungen des 
Programmcodes AUßERHALB der ISR beeinflusst wird, denke ich, dass der 
Fehler nicht in der ISR zu suchen ist.

Ich habe den Eindruck, dass mein Problem hier nicht ganz rübergekommen 
ist :)

Also es geht darum, das die Anzahl der Interrupts pro Sekunde abhängig 
vom Programmcode ist. Sprich, wenn im Programm ein paar _delay_ms(x) 
vorhanden sind, dann tritt eine andere Zahl an Interrupts auf, als wenn 
keine _delay_ms(x) vorhanden sind. Das darf doch aber aus logischer 
Sicht nicht der Fall sein, oder?

Gibt es Erfahrungen mit diesem Phänomen?

von Oliver S. (oliverso)


Lesenswert?

Daniel M. schrieb:
> Also es geht darum, das die Anzahl der Interrupts pro Sekunde abhängig
> vom Programmcode ist. Sprich, wenn im Programm ein paar _delay_ms(x)
> vorhanden sind, dann tritt eine andere Zahl an Interrupts auf, als wenn
> keine _delay_ms(x) vorhanden sind. Das darf doch aber aus logischer
> Sicht nicht der Fall sein, oder?
>
> Gibt es Erfahrungen mit diesem Phänomen?

Ja.
Kann nicht sein. Also ist in dem Programm der Wurm drin, oder du 
interpretierst irgend etwas falsch.

Oliver

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Daniel M. schrieb:
> vom Programmcode ist. Sprich, wenn im Programm ein paar _delay_ms(x)
> vorhanden sind, dann tritt eine andere Zahl an Interrupts auf, als wenn
> keine _delay_ms(x) vorhanden sind. Das darf doch aber aus logischer
> Sicht nicht der Fall sein, oder?

 Wie ware es wenn du mal 'cli' aus deinem Programm rauswirfst ?
 Hab' keine Lust durch deinen ganzen Code zu gehen, aber ich glaube,
 irgendwo in LCD-Routinen hast du 'cli' stehen.
 Also, ohne LCD ist es OK, mit LCD sperrst du Interrupts.

Daniel M. schrieb:
> Das kurriose daran ist, dass die Uhr nun "vorauseilt". Um dieses

 Nein, ohne LCD geht die Uhr so, wie es sein sollte.

von Daniel M. (daniel_91)


Lesenswert?

> Wie ware es wenn du mal 'cli' aus deinem Programm rauswirfst ?
>  Hab' keine Lust durch deinen ganzen Code zu gehen, aber ich glaube,
> irgendwo in LCD-Routinen hast du 'cli' stehen.

Nein, habe nachgeschaut, in dem Code steht niergends cli().

> Also, ohne LCD ist es OK, mit LCD sperrst du Interrupts.

Nein, ohne LCD habe ich es nicht ausprobiert, ich habe mir ja immer die 
Werte über das LCD ausgeben lassen. Ich werde es mit einer einzelnen LED 
probieren, die Jede Minute toggelt. Wenn der Fehler dann auch auftritt, 
kann es nur ein Fehler in der Funktion _delay_ms() sein oder der AVR hat 
nen Funktionsfehler.

von Stefan E. (sternst)


Lesenswert?

Daniel M. schrieb:
> Wenn der Fehler dann auch auftritt,
> kann es nur ein Fehler in der Funktion _delay_ms() sein oder der AVR hat
> nen Funktionsfehler.

Es ist um ein Vielfaches wahrscheinlicher, dass das Problem in deinem 
Code liegt. Ich habe ihn nicht bis ins letzte Detail studiert, aber was 
mir direkt auffällt: du beschreibst systemTime nicht nur in der ISR, 
sondern auch im main-Code, und das ohne jeden Schutz. Und ein 
Atomic-Problem würde auch erklären, warum eine Änderung am zeitlichen 
Verhalten des main-Codes zu geänderter Symptomatik führt.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Daniel M. schrieb:
> Nein, habe nachgeschaut, in dem Code steht niergends cli().

 Code fur 'cli' ist 0xF8, 0x94, es steht in deinem Hex file.
 EDIT:
 Hab' nachgeschaut, es ist drin, aber nach dem Aufruf der Main().
 Da du aber nie aus Main() rauskommst...

Daniel M. schrieb:
> kann es nur ein Fehler in der Funktion _delay_ms() sein oder der AVR hat
> nen Funktionsfehler.

 _delay_ms() wird's kaum sein, noch weniger wahrscheinlich ist, das der
 AVR nen Funktionsfehler hat, aber Temperatur Sensor kann sehr wohl die
 Ursache sein.

von Daniel M. (daniel_91)


Lesenswert?

Marc Vesely schrieb:
> Code fur 'cli' ist 0xF8, 0x94, es steht in deinem Hex file.
> EDIT:
> Hab' nachgeschaut, es ist drin, aber nach dem Aufruf der Main().
> Da du aber nie aus Main() rauskommst...

Aber wie kann das sein? Ich habe doch nirgends cli() geschrieben?

Marc Vesely schrieb:
> _delay_ms() wird's kaum sein, noch weniger wahrscheinlich ist, das der
> AVR nen Funktionsfehler hat, aber Temperatur Sensor kann sehr wohl die
> Ursache sein.

Ich habe den Temperatursensor rausgenommen (keine Abfrage des Sensors), 
der Fehler tritt jedoch nach wie vor auf.

von Oliver S. (oliverso)


Lesenswert?

Daniel M. schrieb:
> Marc Vesely schrieb:
> Aber wie kann das sein? Ich habe doch nirgends cli() geschrieben?

Das steht in der exit-Funktion der avrlibc. Für den Fall, daß Main doch 
mal zurückkehrt...

Oliver

von Ulrich H. (lurchi)


Lesenswert?

Läuft der µC wirklich mit einem externen 8 MHz Quarz, oder ggf. wegen 
der Fuses ggf. noch noch mit dem internen RC Takt ? Beim RC takt wären 
solche Schwankungen normal.

Ein möglicher sporadischer Fehler wären noch ein Stack-Überlauf, beim 
Mega664 aber eher unwahrscheinlich, wenn da kein echtes Speicherleck 
ist, was dann eher zu totalem Murks führen würde.

von Oliver S. (oliverso)


Lesenswert?

Ulrich H. schrieb:
> Beim RC takt wären
> solche Schwankungen normal.

Auf keinen Fall. Der interne Oszillator mag exemplar- und 
temperaturabhängig zu schnell oder zu langsam laufen, aber solch 
kurzfristige Schwankungen hat er nicht.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Daniel M. schrieb:
> Ich habe den Temperatursensor rausgenommen (keine Abfrage des Sensors),
> der Fehler tritt jedoch nach wie vor auf.

>      if (!updateTime)
>      {
>        // Uhrzeit, Datum und Temperatur ausgeben
>        // Uhrzeit und Datum sind in einem globalen struct gespeichert
>        GraphicWriteDataOnLcd(MCP9808ReadAmbientTemperature());
>      }

   So steht es in deinem file.


>  if (timer1InterruptCounter == INTERRUPTS_PER_SECOND)

 Probiere mal mit >=
 Und da bin ich mit meinem Latein auch am Ende.

 EDIT:
 Kannst auch mal probieren, timer1InterruptCounter als ERSTE VARIABLE
 zu deklarieren - also nicht NACH dem copyTime

: Bearbeitet durch User
von Daniel M. (daniel_91)


Lesenswert?

Marc Vesely schrieb:
> Daniel M. schrieb:
>> Ich habe den Temperatursensor rausgenommen (keine Abfrage des Sensors),
>> der Fehler tritt jedoch nach wie vor auf.
>
>>      if (!updateTime)
>>      {
>>        // Uhrzeit, Datum und Temperatur ausgeben
>>        // Uhrzeit und Datum sind in einem globalen struct gespeichert
>>        GraphicWriteDataOnLcd(MCP9808ReadAmbientTemperature());
>>      }
>
>    So steht es in deinem file.

Ja, ich habe den überarbeiteten Code nicht hochgeladen, hier steht noch 
der alte.

Ulrich H. schrieb:
> Läuft der µC wirklich mit einem externen 8 MHz Quarz, oder ggf. wegen
> der Fuses ggf. noch noch mit dem internen RC Takt ?

Ja, der läuft definitiv mit dem Quarz, habe ebend nochmal geschaut.

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Daniel M. schrieb:
> Ja, ich habe den überarbeiteten Code nicht hochgeladen, hier steht noch
> der alte.

 Hast du es mit geänderter Abfrage oder mit anderer Adresse versucht ?

von Daniel M. (daniel_91)


Lesenswert?

Marc Vesely schrieb:
> Hast du es mit geänderter Abfrage oder mit anderer Adresse versucht ?


Es steht jetzt im Code:
1
 GraphicWriteDataOnLcd(0);

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Marc Vesely schrieb:
> Hast du es mit geänderter Abfrage oder mit anderer Adresse versucht ?

 Ich versuchte dir zu sagen, das die Variable 'timer1InterruptCounter'
 vielleicht auf einer anderer Stelle im Programm überschrieben wird.
 Deshalb ist Abfrage mit 'gleich oder größer ( >= )' besser als nur
 Abfrage auf 'gleich ( == )'.
 Ausserdem ist gleich über, also oberhalb dieser Variable eine Structur
 deklariert und mit Structuren ist das so eine Sache...
 Ich wurde timer1InterruptCounter auf jeden Fall am Anfang deklarieren.

: Bearbeitet durch User
von Daniel M. (daniel_91)


Lesenswert?

Marc Vesely schrieb:
> Ich versuchte dir zu sagen, das die Variable 'timer1InterruptCounter'
>  vielleicht auf einer anderer Stelle im Programm überschrieben wird.
>  Deshalb ist Abfrage mit 'gleich oder größer ( >= )' besser als nur
>  Abfrage auf 'gleich ( == )'.
>  Ausserdem ist gleich über, also oberhalb dieser Variable eine Structur
>  deklariert und mit Structuren ist das so eine Sache...
>  Ich wurde timer1InterruptCounter auf jeden Fall am Anfang deklarieren.

Also ich habe jetzt die Abfrage in größer gleich ( >= ) abgeändert.

Auch die Variable "timer1InterruptCounter" ist nun über der Struktur 
definiert und initialisiert.
Aber ich verstehe nicht was das bringen soll. Syntaktisch ändert sich 
doch dardurch nichts, oder? Was meinst du mit:

>  [...] und mit Structuren ist das so eine Sache...

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Daniel M. schrieb:
> Aber ich verstehe nicht was das bringen soll. Syntaktisch ändert sich
> doch dardurch nichts, oder?

 Ich denke doch.Falls die Variable ( auf einer anderer Stelle im
 Programm ) auf einen Wert über INTERRUPTS_PER_SECOND  geändert wird,
 sagen wir mal auf INTERRUPTS_PER_SECOND + 5 brauchst du im ersten fall
 fast 250 ISR-aufrufe mehr. Im zweiten fall fällst du sofort durch.

: Bearbeitet durch User
von Daniel M. (daniel_91)


Lesenswert?

Also, auch mit der geänderten Abfrage ( >= ) bleibt der Fehler bestehen.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Daniel M. schrieb:
> Also, auch mit der geänderten Abfrage ( >= ) bleibt der Fehler bestehen.

 Na, dann eben Teil für Teil abzwicken, bist du den Fehler los bist.
 Oder besser noch, nur mit main und ISR in der du nur deine Variable
 hochzählst, anfangen und Teil für Teil dazugeben.
 In main kannst du dann auch noch prüfen, ob timer1InterruptCounter
 wirklich nur um eins hochgezählt wird.
 Kannst auch im AVR-Studio LogFile öffnen, irgendein Portpin beim
 Eintritt in ISR toggeln, beim erreichen der INTERRUPTS_PER_SECOND
 wieder ein anderes Pin toggeln und Zeiten vergleichen.

von Daniel M. (daniel_91)


Lesenswert?

Ich habe jetzt 6 Stunden lang die Uhr laufen lassen, allerdings mit 
geändertem Timer-Prescaler (256).

Der Timer erzeugt jetzt pro Sekunde nur noch einen Interrupt, in der ISR 
werden nur noch die Zeitvariablen hochgezählt.

Das DCF77-Signal wird nicht mehr abgetastet, weshalb ich die Uhrzeit 
manuell ingegeben habe.

Nach 6 Stunden Betriebszeit verzögerte sich die Uhr um etwa 9 Sekunden.

Jetzt werde ich das ganze nochmal so abändern, das nur eine LED jede 
Minute getoggelt wird, ebenfalls mit einem Interrupt pro Sekunde.

von Magnus (Gast)


Lesenswert?

Daniel M. schrieb:
> Nach 6 Stunden Betriebszeit verzögerte sich die Uhr um etwa 9 Sekunden.
Macht 9 s zu
6 h = 360 min = 21600 s

= 0,00041667
= 0,041667 %
= 416,67 * 10 ^ -6

also ca. 400 ppm.

Die Quarze die z.B. reichelt verkauft haben eine Frequenztoleranz von 
±30 ppm. Bei den Quarzoszillatoren sind es ±100 ppm.

Mir scheint, Du hast einen miesen Quarz oder falsche Lastkapazitäten. 
Für den internen RC-Oszillator, bist Du zu genau.

Magnus

P.S.: delay_ms ist jetzt erstmal raus, oder? Das ist für eine Uhr auch 
nicht gedacht.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Daniel M. schrieb:
> Nach 6 Stunden Betriebszeit verzögerte sich die Uhr um etwa 9 Sekunden.

 Hast du Quarz oder Keramik-Resonator ?
 Schick doch mal den geänderten Code.

von Daniel M. (daniel_91)


Lesenswert?

Magnus schrieb:
> P.S.: delay_ms ist jetzt erstmal raus, oder? Das ist für eine Uhr auch
> nicht gedacht.

_delay_ms() schon, aber _delay_us() nicht. Das brauche ich für das LCD.
Weiter oben steht aber auch, das es nicht für die Uhr selber verwendet 
wurde.

von Daniel M. (daniel_91)


Lesenswert?

Also nach diversen weiteren Versuchen steht folgendes fest:

- Unabhängig vom Programmcode hinkt die Uhr immer hinterher (das sie 
ganz am Anfang mal vorrauseilte muss daran gelegen haben, dass ich einen 
anderen Quarz verwendet hatte. Ich dachte zu dem Zeitpunkt, es läge 
vielleicht daran).

- Wie stark sie hinterherhinkt, hängt von der Anzahl der 
Interrupt-Aufrufe ab. Bei wenigen Aufrufen (1 mal pro Sekunde) beträgt 
die Abweichung ca. 3 Sekunden pro Minute, bei häufigen Aufrufen (100 mal 
pro Sekunde) nur einige wenige Millisekunden.

Marc Vesely schrieb:
> Hast du Quarz oder Keramik-Resonator ?

Ich verwende einen 8MHz-Quarz von Reichelt

von Oliver S. (oliverso)


Lesenswert?

Na ja, jetzt sind wir nach gefühlten 200 Beiträgen wieder am Anfang. 
Nach wie vor hast du einen Fehler im Programm und /oder misst falsch. 
Alles wie bisher.

Das der Resonator nicht genau mit der angegeben Frequenz läuft, ist 
normal.

Die Abhängigkeit der Ungenauigkeit von der Interrupthäufigkeit ist nicht 
normal, und liegt nicht am Prozessor.

Aber da du deine Testprogramme hier ja nicht zeigst, musst du halt 
alleine weiterraten.

Oliver

von Martin S. (led_martin)


Lesenswert?

Hallo Daniel,

wenn die Anzahl der Interrupt-Aufrufe Einfluss auf die Abweichung hat, 
vermute ich, daß im Interrupt der Timer manipuliert wird, z.B. kurz 
angehalten, oder der Timer-Wert neu gesetzt wird. Beides sollte man, bei 
einer Uhr, nicht machen. Je nachdem wie das programmiert ist holt man 
sich die zeitliche Streuung beim Interruptaufruf, oder Unterschiede in 
der Programmlaufzeit (Verzweigungen?) in den Stand des Timers. Der Timer 
muss ab der Initialisierung durchlaufen, um auf eine definierte 
Häufigkeit der Interruptaufrufe zu kommen, kann man den Timer im 
CTC-Modus laufen lassen (Siehe Datenblatt). Den Endwert für den 
CTC-Modus sollte man dann auch nicht mehr ändern, nur wenn man genau 
weiß was man da macht. Bei der Berechnung ist zu beachten, daß der 
Zyklus der Interrupptaufrufe um einen Takt länger ist, als der 
CTC-Endwert (z.B. Endwert 299 -> Alle 300 (Timer-)Taktzyklen ein 
Timer-Interrupt).

Mit freundlichem Gruß - Martin

von Daniel M. (daniel_91)


Lesenswert?

Ich habe den Fehler jetzt gefunden.

Erstmal Danke an all jene, die hier ihr Wissen eingesetzt haben um mir 
zu helfen.

Es ist, entgegen meiner Erwartungen, kein Softwarefehler oder ein Fehler 
des Mikrocontrollers gewesen.

Das Problem, warum der Takt nicht gepasst hat, lag in der Tatsache 
begründet, dass ich keine Kondensatoren von den beiden Quarzanschlüssen 
nach Masse gelegt habe.

Dieses habe ich jetzt nachgeholt und nach gut 2 Stunden Betriebszeit 
konnte ich bis jetzt noch keine Zeitabweichung feststellen.

Ich hätte nicht gedacht, das zwei 22pF-Kondensatoren einen so großen 
Einfluss auf das Schwingverhalten des Quarzes haben.

Jedenfalls scheint das Problem jetzt gelöst.

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.