Forum: Mikrocontroller und Digitale Elektronik Projekt mit genauer Sekunde - Abweichung


von Alex (Gast)


Lesenswert?

Hallo zusammen,

ich habe mir eine Uhr gebaut. Diese hat ein Display welches über 4 
Module verteilt ist. Auf einem der Module läuft der der Programmteil, 
welcher die Zeit generiert sowie die Darstellung für die anderen 
Displayteile zusammenbaut und dieses an die anderen Module per TWI 
versendet. Für die TWI-Kommunikation habe ich die Bibliothek von Peter 
Fleury verwendet.

Für die Generierung des Sekundentaktes habe ich den Beispielcode von 
Peter Dannegger benutzt und hinsichtlich der möglichkeit den Systemtakt 
später nachzujustieren ergänzt.

Jedoch habe ich nun das Problem, dass die Uhr noch immer vorgeht. Ich 
habe das Programm so gestaltet, dass ich an der Uhr einen kalibrierwert 
Eingeben kann, welcher dann die Schranken des Timers entsprechend 
variiert.

Der aktuelle Systemtakt wird in jedem Zyklus anhand des Basiswertes 
welches per #define festgelegt ist und dem Kalibrierwert, welchen man 
konfigurieren kann errechnet. Dieser wird nach änbdern auch in den 
EEProm geschrieben und ist nach neustart auch korrekt.

Eigentlich sollte ich bei +10sec Abweichung pro Tag bei einem 8Mhz Quarz 
so richtig liegen (Systemtakt müssten dann 8000925Hz sein).

Timer2 wird benutzt um die Anzeige zu Dimmen. Dies geschiet einfach 
durch das umschalten des direction Registers.

Controller: Atmega8
Ext. Quarz: 8Mhz Quarz mit 2x 22pF

Nun ist meine Frage ob hier jemand einen Punkt sieht an dem mir ein 
Fehler unterlaufen sein könnte, der ein vorgehen der Uhr bewirkt.

Vielen Dank.

Anbei selbstverständlich der code.
1
#include <stdio.h>
2
#include <avr/interrupt.h>
3
#include <util/delay.h>
4
#include <avr/eeprom.h>
5
6
#include "General.h"
7
#include "Module.h"
8
#include "TWI_Master.h"
9
#include "TWI_Slave.h"
10
11
#define DEBOUNCE    256L        // debounce clock (256Hz = 4msec)
12
13
#define BASISTAKT   7999000L;
14
15
uint32_t systemtakt;
16
uint32_t reload;
17
uint8_t rest;
18
19
20
uint16_t calValue;
21
uint8_t prescaler;
22
23
uint8_t LedSwitchValue;
24
25
volatile uint8_t Tick;
26
27
uint8_t eeLedSwitchValue EEMEM = 120;
28
uint16_t eeCalValue EEMEM = 1925;
29
30
void ClearDisplay(void);
31
void ShowDisplay(void);
32
33
// uint8_t eeNumberOfModules EEMEM = 6;
34
35
ISR(TIMER1_COMPA_vect)
36
{
37
    static uint8_t ct0 = 0xFF, ct1 = 0xFF, rpt;
38
    uint8_t i;
39
40
    i = button_state ^ ~BUTTON_PIN;                       // key changed ?
41
    ct0 = ~( ct0 & i );                             // reset or count ct0
42
    ct1 = ct0 ^ (ct1 & i);                          // reset or count ct1
43
    i &= ct0 & ct1;                                 // count until roll over ?
44
    button_state ^= i;                                 // then toggle debounced state
45
    button_press |= button_state & i;                     // 0->1: key press detect
46
47
    if( (button_state & REPEAT_MASK) == 0 )            // check repeat function
48
        rpt = REPEAT_START;                          // start delay
49
50
    if( --rpt == 0 )
51
    {
52
        rpt = REPEAT_NEXT;                            // repeat delay
53
        button_rpt |= button_state & REPEAT_MASK;
54
    }
55
56
    if(rest) OCR1A = reload;        // compare DEBOUNCE - 1 times
57
58
    if( --prescaler == 0 )
59
    {
60
        prescaler = (uint8_t)DEBOUNCE;
61
        Tick++;               // exact one second over
62
        if(rest) OCR1A = reload + rest; // compare once per second
63
    }
64
}
65
66
ISR(TIMER2_OVF_vect)
67
{
68
    if(ledcounter++ >= LedSwitchValue)
69
    {
70
        ClearDisplay();
71
72
    }
73
    if(ledcounter == 0)
74
    {
75
        ShowDisplay();
76
    }
77
}
78
79
80
void ClearDisplay()
81
/** Used for dimming: This function set all display used port pins to input **/
82
{
83
    DDRB &= ~PortMask.B;
84
    DDRC &= ~PortMask.C;
85
    DDRD &= ~PortMask.D;
86
    LED_IR_DDR &= ~(1<<LED_IR);
87
    LED_IL_DDR &= ~(1<<LED_IL);
88
}
89
90
void ShowDisplay()
91
/** Used for dimming: This function set all display used port pins to input **/
92
{
93
    DDRB |= PortMask.B;
94
    DDRC |= PortMask.C;
95
    DDRD |= PortMask.D;
96
    LED_IR_DDR |= (1<<LED_IR);
97
    LED_IL_DDR |= (1<<LED_IL);
98
}
99
100
int main (void)
101
 {
102
     
103
//*** Gekürzt *** //
104
105
    calValue = eeprom_read_word(&eeCalValue);
106
    LedSwitchValue = eeprom_read_byte(&eeLedSwitchValue);
107
108
109
//*** Gekürzt *** //
110
111
    /** Led Timer initialisieren **/
112
113
    TCCR2 = (1<<CS20);      // divide by 255
114
    TIMSK |= 1<<TOIE2;
115
116
    /** Sekundentimer im Mastermodul initialisieren **/
117
118
//*** Gekürzt *** //
119
120
        systemtakt = BASISTAKT + (uint32_t)calValue;
121
        reload = systemtakt / DEBOUNCE - 1;
122
        rest = (uint8_t)(systemtakt % DEBOUNCE);           // used for exact second
123
124
        TCCR1B = (1<<WGM12) | (1<<CS10);        // divide by 1
125
                                                // clear on compare
126
        OCR1A = reload;                         // Output Compare Register
127
128
        TCNT1 = 0;                              // Timmer startet mit 0
129
        prescaler = (uint8_t)DEBOUNCE;          //software teiler
130
131
        TIMSK |= 1<<OCIE1A;                    // beim Vergleichswertes Compare Match
132
        
133
//*** Gekürzt *** //
134
135
    /** Timer Aktivieren **/
136
137
    sei();
138
139
  while (1)
140
    {
141
        systemtakt = BASISTAKT + (uint32_t)calValue;
142
        reload = systemtakt / DEBOUNCE - 1;
143
        rest = (uint8_t)(systemtakt % DEBOUNCE);           // used for exact second
144
145
  //*** Gekürzt *** //       
146
    }
147
    return 0;
148
}

von Stefan F. (Gast)


Lesenswert?

So genau sind die Oszillatoren für den Systemtakt nicht. Wenn du eine 
Uhr haben willst, die ohne großartige Klimmzüge einigermaßen genau 
läuft, dann musst du einen Uhrenquarz mit zugehörigem Oszillator 
verwenden. Am Besten außerhalb des Mikrcocontrollers als RTC Chip.

Ohne Kalibrierung entsprechen diese Chips ungefähr einer billigen 
Armbanduhr in der Preisklasse unter 10 Euro. Mit Kalibrierung und 
konstanter Umgebungstemperatur kann man sie besser machen.

von Wolfgang (Gast)


Lesenswert?

Alex schrieb:
> Jedoch habe ich nun das Problem, dass die Uhr noch immer vorgeht.

Dann passt dein Korrekturwert nicht zu deinem Timing im Programm. Läge 
es an Schwankungen des Systemtaktes, müsste die Uhr mal vor- und mal 
nachgehen.

von Joe (Gast)


Lesenswert?


von Jacko (Gast)


Lesenswert?

So genau verstehe ich die Anwendung der "Genauen Sekunde"
von Peter Dannegger nicht, da man mit einem Mega8 + 8 MHz
Quarz die Sekunde quarzgenau (*) durch ganzzahlige Teilung
darstellen kann.

Wenn der Quarz nicht (*) genau tickt, gibt es ja erstmal
die Möglichkeit durch passendere Lastkapazitäten, (was am
Mega8 eher 27 pF sind) und eventuell mit einem kleinen Trimm-C
die Sekunde abzugleichen. Dafür braucht man einen genau
kalibrierten Frequenzzähler.

Wird die Uhr bei Raumtemperatur betrieben, kommt man da schon
auf < 30 s Fehler pro Monat. Viel mehr ist nicht zu erwarten.
- Dafür gibt es seit vielen Jahrzehnten DCF.

Alternativ kann man natürlich durch "Uhrenvergleich" eine
Korrektur für die interne Frequenzteilung bestimmen und
der Frequenzteilung vorgeben.

Deinen Code mit vielen nicht erklärten Festwerten zu
durchforsten, hab ich keine Lust.

Du solltest aber in der Lage sein, mal eine Korrektur für +1,
oder -1 Minute/Tag vorzugeben.
Die Beobachtung der Auswirkung sollte schon mal zeigen, ob
das Konzept funktioniert. - Oder, wenn es nicht funktioniert,
Hinweise geben, in welcher Richtung du im Programm-Code
nach Fehlern suchen musst.

von Wolfgang (Gast)


Lesenswert?

Jacko schrieb:
> So genau verstehe ich die Anwendung der "Genauen Sekunde"
> von Peter Dannegger nicht, ...

Den Eindruck habe ich auch.

> ... da man mit einem Mega8 + 8 MHz
> Quarz die Sekunde quarzgenau (*) durch ganzzahlige Teilung
> darstellen kann.

Das Problem dabei ist, dass ein Quarz, auf dem 8 MHz drauf steht, so gut 
wie nie mit genau 8.000000 MHz schwingt.

In dem Artikel "Genauen Sekunde" von Peter Dannegger geht es genau 
darum, ohne die Schrauberei am Quarz, i.e. ohne Frequenzabgleich des 
Quarzes, eine genau gehende Uhr zu bauen.

von oszi40 (Gast)


Lesenswert?

Wolfgang schrieb:
> ohne die Schrauberei am Quarz, i.e. ohne Frequenzabgleich des
> Quarzes, eine genau gehende Uhr zu bauen.

Das setzt aber voraus, daß nicht durch andere (Unter-)Programme 
Zeit/Takte gestohlen werden.

von Wolfgang (Gast)


Lesenswert?

oszi40 schrieb:
> Das setzt aber voraus, daß nicht durch andere (Unter-)Programme
> Zeit/Takte gestohlen werden.

Seit wann lassen sich Timer durch andere (Unter-)Programme Zeit klauen?

von A. S. (Gast)


Lesenswert?

Hast Du schon geschrieben, was nicht klappt? Also
a) wieviel geht die Uhr am Tag vor?
b) woher hast Du den Kalibrierwert?
c) hast Du b) schon an a) angepasst? Was ist die Abweichung?
d) welche Messmittel hast Du, um z.B. das Timing per toggelndem Pin zu 
prüfen?

BTW, ich kenne Deinen µC nicht: Ist sichergestellt, dass das Laden von 
OCR1A bei Deinem µC keinen Einfluss auf das fortlaufen des Timers hat?

von c-hater (Gast)


Lesenswert?

Wolfgang schrieb:

> Seit wann lassen sich Timer durch andere (Unter-)Programme Zeit klauen?

Schon immer. Ist nur eine Frage der Fähigkeit, beliebig falschen Code zu 
schreiben.

Man kann ja schließlich jederzeit die laufzeitbestimmenden Register der 
Timer durch falsche Werte überschreiben, man kann die Timer 
fälschlicherweise anhalten, man kann fälschlicherweise seine Taktquelle 
ändern, man kann verhindern, dass die Timer-ISR häufig genug bearbeitet 
wird (bzw. im Falle von Polling: man kann dafür sorgen, dass nicht 
häufig genug gepollt wird oder dafür, dass das IRQ-Flag zur falschen 
Zeit zurückgesetzt wird)

Du siehst: es gibt Unmassen Möglichkeiten, einen Timer aus dem Rhythmus 
zu bringen. Der TO muss nun eigentlich nur noch herausfinden, welche 
davon er angewendet hat...

von Patrick J. (ho-bit-hun-ter)


Lesenswert?

Hi

Hab ja keine Ahnung von C(?), aber in Assembler, wovon ich nun auch 
nicht die Ahnung habe - aber immerhin, ist's dem Timer vollkommen 
wurscht, was Du noch so treibst - Der zählt jeden Prescaler einen Tick 
hoch, fertig.
Beim nächsten Match wird ein Flag gesetzt und der Interrupt ausgelöst.
Hier hast Du nun etwas Zeit, dieses Ereignis abzuarbeiten.
Erst, wenn Du damit nicht fertig wirst, bevor der nächste 
Match-Interrupt zuschlägt, bekommst Du Deine Abweichungen - obgleich 
sämtliche Takte im µC geblieben sind, Keiner fehlt.

Ungefär aus diesem Grund baut man keine Warteschleife in die ISR ein, 
der Programmteil muß so flott wie möglich beendet werden - auch, damit 
man bis zum nächsten Interrupt noch etwas normalen Kram im µC erledigen 
klann - also Eingänge pollen und so'n Kram.

MfG von Einem, Dem noch kein Takt geklaut wurde :)

von Johnny B. (johnnyb)


Lesenswert?

Wenn man einen Uhrenquarz (32.768kHz) und die dazu passenden 
Kondensatoren verwendet, kriegt man einen sehr genauen Sekundentakt 
(gute Uhrenquarze sind mit ±15ppm toleriert).
Im Worstcase ist das dann nur eine Abweichung von 1.3s pro Tag, die man 
gänzlich ohne Kalibration/Justierung erreicht.

von Peter D. (peda)


Lesenswert?

Johnny B. schrieb:
> Im Worstcase ist das dann nur eine Abweichung von 1.3s pro Tag, die man
> gänzlich ohne Kalibration/Justierung erreicht.

Mit Kalibration wird es aber deutlich besser (wenige Sekunden pro Jahr).
Und die MHz-Quarze haben prinzipiell einen etwas besseren TK und höhere 
Güte. In den DDR-Schiffschronometern wurden deshalb 4,194MHz Quarze 
verwendet.

Ich hab mal ne RTC mit internem Quarz verwendet (Maxim: DS1994). Ohne 
Korrekturrechnung war die praktisch unbrauchbar.

von c-hater (Gast)


Lesenswert?

Peter D. schrieb:

> Mit Kalibration wird es aber deutlich besser (wenige Sekunden pro Jahr).

So ist es. Und die Kalibrierung mittels Software kann sogar deutlich 
bessere Ergebnisse erreichen als etwa mit einem Abgleich per 
Trimm-Kondensator als Bürdekapazität. Software-Ticks haben nämlich (ganz 
im Gegensatz zu Trimmkondensatoren) keinerlei Empfindlichkeit gegenüber 
Umwelteinflüssen.

> Und die MHz-Quarze haben prinzipiell einen etwas besseren TK und höhere
> Güte. In den DDR-Schiffschronometern wurden deshalb 4,194MHz Quarze
> verwendet.

Nicht nur dort. Überall wo es wirklich auf Genauigkeit ankommt und etwas 
besseres als ein Quarz als Zeitbasis nicht in Frage kommt, wurden und 
werden natürlich Quarze im MHz-Bereich verwendet. Die 32kHz-Quarze haben 
nur genau einen Vorteil: der Quarzoszillator (und der Frequenzteiler 
dahinter) verbraucht wesentlich weniger Energie als bei einem MHz-Quarz.

Wenn maximale mögliche Genauigkeit das Ziel ist, was besseres als ein 
Quarz nicht in Frage kommt und der Energieverbrauch keine Rolle spielt, 
sollte man also besser nicht die 32kHz-Quarze verwenden (auch nicht, 
wenn sie in irgendwelchen RTC-Chips stecken).

> Ich hab mal ne RTC mit internem Quarz verwendet (Maxim: DS1994). Ohne
> Korrekturrechnung war die praktisch unbrauchbar.

Nun, wenn im Datenblatt einer RTC nichtmal eine ungefähre Angabe zur zu 
erwartenden Genauigkeit der Zeitbasis zu finden ist, würde ich das Teil 
nichtmal mit einer Kneifzange anfassen wollen. Das ist Vollschrott ab 
Werk. Und zwar mit Ankündigung (in Form der Absenz eben dieser Angabe).

von Philipp K. (philipp_k59)


Lesenswert?

Peter D. schrieb:
> Ich hab mal ne RTC mit internem Quarz verwendet (Maxim: DS1994). Ohne
> Korrekturrechnung war die praktisch unbrauchbar.

Kein WundeR? Clock Accuracy is Better Than ±2 Minutes/Month at 25°C

So DS3231 mit integriertem TCXO fährt man bei 2ppm etwas besser.. kann 
man sogar nur als 32khz Quarz oder Sekundentakt benutzen.. wobei ich die 
Dinger manchmal nach einigen Monaten aus der Kiste hole und irgendwie 
nichtmal grob überschaut Sekundenfehler bemerke.

Accuracy ±2ppm from 0°C to +40°C.. dazu kann man die sogar noch trimmen 
wobei ich das nichtmal in Gebrauch hatte.

Ich baue ohne die keine Uhr mehr.

von W.S. (Gast)


Lesenswert?

Peter D. schrieb:
> Ich hab mal ne RTC mit internem Quarz verwendet (Maxim: DS1994).

Tja. Du solltest wie ich einen mittelgroßen Bogen um Maxim machen.

Eben wegen sowas verwende ich für meine Geräte RTC's von Seiko-Epson. 
Die Dinger laufen selbst mit nur einem 0.22F Goldcap mehrere Monate und 
das Datum nebst Uhrzeit stimmen immer noch bis auf wenige Sekunden nach 
so einer Durststrecke.

Sinnvollerweise gleicht man bei Uhrenanwendungen die Frequenz eben nicht 
per Software ab, sondern per Trimmkondensator oder Trimm-Varicap und 
benutzt einen sinnvoll gestalteten Ausgang (MCO oder so) des µC zusammen 
mit einem Frequenznormal und einem Oszi (Lissajous-Figur) zum Abgleich, 
damit man mit dem Oszi nicht an den eigentlichen Oszillator tippen muß. 
Ein Frequenzzähler an MCO würde auch gehen, ist aber deutlich 
gefühlloser als die Lissajous-Figur auf dem Oszi.

W.S.

von Joe (Gast)


Lesenswert?

Die Methode aus dem oben genannten BASCOM Programm ist optimal.
Dabei wird auch der Timer manipuliert, indem der Preload bei Bedarf 
verändert wird.
Ich habe das mit einem Atmega8 und 10MHz Quarz ausprobiert.
Theoretisch kann man die Genauigkeit auf 1s in 4 Monaten drücken. 
Geeicht habe ich meine Uhr und damit den Quarz mit dem DCF HF-Signal und 
meinem Oszi.
Im Sommer geht die Uhr seit einigen Jahre bis zu 5s nach, z. Z. geht sie 
etwa 2s vor. Der TK ist schlecht.
Übers Jahr ist sie etwa 1s zu langsam, das kann ich verschmerzen.

Joe

von Wolfgang (Gast)


Lesenswert?

W.S. schrieb:
> Sinnvollerweise gleicht man bei Uhrenanwendungen die Frequenz eben nicht
> per Software ab

Was ist daran sinnvoller?

Und statt irgendwelcher Lissajous-Figur auf dem Oszi anzugucken, kann 
man sich mindestens genauso gut die Drift eines Sekundenpulses gegenüber 
einem 1PPS-Signal vom GPS ansehen.

von Peter D. (peda)


Lesenswert?

W.S. schrieb:
> Sinnvollerweise gleicht man bei Uhrenanwendungen die Frequenz eben nicht
> per Software ab, sondern per Trimmkondensator

Geht aber beim DS1994 nicht. Auch hat man selten ein genaues 
Frequenznormal rumstehen.
Ich hab ihn daher auch so kalibriert, daß ich nach etwa 3 Monaten den 
Gangfehler nach der TV-Uhr bestimmt habe und eine entsprechende 
Korrekturrechnung einprogrammiert habe. Seitdem läuft er schon viele 
Jahre mit nur wenigen Sekunden Fehler pro Jahr.
Aber er wird ja schon lange nicht mehr hergestellt.

von oszi40 (Gast)


Lesenswert?

Peter D. schrieb:
> Gangfehler nach der TV-Uhr bestimmt

Das war zu Zeiten analoger TV-Signale noch recht genau. Heute ist das 
digitale Studio-Signal ca. 3 Sekunden verzögert. Da ist meine 
DCF-Armbanduhr genauer.

von Patrick J. (ho-bit-hun-ter)


Lesenswert?

Hi

Es soll da auch so Funk-Wecker geben, dabei wecken Die gar nicht mit 
Funk, sondern ganz banal mit Schall!
Soll heißen: DCF77 könnte hier als Abgleich alle paar Monate herhalten.
Bis zu meiner ersten Uhr dauert's wohl noch was, aber wenn ich einen 
Abgleich eh vorsehe, warum lasse ich dann nicht zwei µC miteinander 
schwätzen?
Der Eine hat die geschätzte Zeit und die bisherige Einschaltdauer, der 
Andere die genaue Zeit.
Aus der Differenz kann Einer der Beiden den Korrekturwert ermitteln 
(wobei die Uhr eigentlich nicht viel zu tun haben dürfte, aber man weiß 
ja nie) und die Uhr hat den neuen Korrekturwert.

MfG

von oszi40 (Gast)


Lesenswert?

Patrick J. schrieb:
> der Andere die genaue Zeit.

Kannst Du vergleichen. Mach aber mehrere Vergleiche und prüfe vorher auf 
Plausibilität des DCF77-Impulstelegramms bevor Du Deine Zeit 
"berichtigst". Aus trauriger Erfahrung kann ich Dir versichern, daß man 
manchmal durch Störungen auch Mist empfängt! NTP wäre auch eine mögliche 
Variante. https://de.wikipedia.org/wiki/NTP-Pool

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.