Forum: Mikrocontroller und Digitale Elektronik Genaue Uhr - Frequenzteiler


von Jürgen H. (misteret)


Lesenswert?

Hallo,
um eine sehr genaue Uhrzeit zu bekommen, ist es ja denke ich besser, 
wenn möglichst wenige ISR vorkommen, da hier ja wieder Taktzyklen 
verloren gehen.

Nun überlege ich, wie ich am besten den Vorteiler mit dem OCR1A Register 
kombiniere.


Habe hier 2 Varianten, welche ist besser?
(Quarz mit 16Mhz verwende ich)


1. OCR1A auf 64000 setzen
   TCCR1B |= (1<<CS10) => Systemtakt

   Nun zähle ich in der ISR eine Variable hoch bis 250, dann habe ich
   250*64000=16.000.000. Also 1 Sekunde.

2. OCR1A auf 62500 setzen
   TCCR1B |= (1<<CS12) = Takt = 16.000.000 / 256 = 62500

   Nun zähle ich immer bis 62500 und brauche in der ISR nicht mehr
   irgendwelche Variablen hochzuzählen.

von funkuhrpersönlich (Gast)


Lesenswert?

eine Funkuhr ist sehr genau

von Michael U. (amiga)


Lesenswert?

Hallo,

wenn der Timer im CTC-Mode läuft ist das doch fast völlig uninteressant.

Wenn z.B. alle 10ms ein Timer-IRQ ausgelöst wird dann passiert der auch 
alle 10ms.
Wenn jetzt die IRQ-Routine für den Zähler bis 100 (1s) ein paar Takte 
später ausgeführt wird, dann wird die aktuelle Sekunde etwas später 
aktualisiert werden. Der Timer selbst läuft davon unbeeindruckt ja 
weiter und löst pünktlich 10ms später den nächsten IRQ aus.

Die IRQ-Routine darf natürlich nicht länger als 10ms dauern, sonst wird 
der nächste IRQ verpasst, aber das soll sie sowieso nie.

Gruß aus Berlin
Michael

von Peter D. (peda)


Lesenswert?

Jürgen Hems wrote:
> Hallo,
> um eine sehr genaue Uhrzeit zu bekommen, ist es ja denke ich besser,
> wenn möglichst wenige ISR vorkommen, da hier ja wieder Taktzyklen
> verloren gehen.

Das wäre schlimm, wenn dem so wäre.
Man muß die Interrupts nur so programmieren, daß die Einsprungzeit und 
Verzögerungen durch andere Interrupts keine Rolle spielen.
Entweder Hardware-Reload bzw. Clear on Compare oder Addition des Timers 
zur gewünschten Verkürzung.
Dann kann man soviele Interrupts verwenden, bis der Arzt kommt.


>    Nun zähle ich immer bis 62500 und brauche in der ISR nicht mehr
>    irgendwelche Variablen hochzuzählen.

Du kannst es versuchen, aber ich hatte bisher noch nie einen Quarz mit 
genau 16.000.000Hz.
Man muß daher für Uhrenanwendungen noch Korrekturwerte addieren (z.B. je 
Sekunde).


Peter

von Falk B. (falk)


Lesenswert?

@ Jürgen Hems (misteret)

>um eine sehr genaue Uhrzeit zu bekommen, ist es ja denke ich besser,
>wenn möglichst wenige ISR vorkommen, da hier ja wieder Taktzyklen
>verloren gehen.

Falsch, wie Peter bereits bemerkte. Eine ISR verschluckt keine Takte, 
wenn sie richtig programmiert ist. Siehe Interrupt.

>   Nun zähle ich in der ISR eine Variable hoch bis 250, dann habe ich
>   250*64000=16.000.000. Also 1 Sekunde.

Siehe AVR - Die genaue Sekunde / RTC

MFG
Falk

von Peter (Gast)


Lesenswert?

Hoi Hoi!
Ich nutze einen Compare Match Interrupt für eine RTC und schreibe das 
ganze in ein Array, der Interrupt wird alle 0.01 Sekunden ausgelöst:
1
ISR(TIMER1_COMPA_vect) {
2
rtc[2]++;
3
  // hunderstel sek
4
  if (rtc[2] > 99 ) {
5
    rtc[2] = 0;
6
    rtc[1]++;
7
  }
8
  // sekunden
9
  if (rtc[1] > 59 ){
10
    rtc[1] = 0;
11
    rtc[0]++;
12
  }
13
  // minuten
14
  if (rtc[0] > 9 ){
15
    rtc[0] = 0;
16
  }
17
}
18
19
void rtc_start() {
20
  sei();
21
  OCR1A = 19999;
22
  TCCR1B = 0b00001010;
23
  TIMSK |= 0b00010000;
24
}

Wie gut meine Lösung ist... ka, für mich macht sie was sie soll ;)
Du kannst dir auch das Array sparen und nur einen 16Bit Zähler 
inkrementieren mit den hunderstel sekunden. Dann kannst du aber nur max 
~10 Minuten erfassen.
Nach 9 Minuten wird bei dem o.g. Code wieder von vorn angefangen zu 
zählen, bei mir ist das gewollt, das ist ja aber leicht zu ändern.

Mfg,
Peter

von eProfi (Gast)


Lesenswert?

Es genügt, die Sekunden jede Sekunde zu bearbeiten:
ISR(TIMER1_COMPA_vect) {
rtc[2]++;
  // hunderstel sek
  if (rtc[2] > 99 ) {
    rtc[2] = 0;
    rtc[1]++;
    // sekunden
    if (rtc[1] > 59 ){
      rtc[1] = 0;
      rtc[0]++;
      // minuten
      if (rtc[0] > 9 ){
        rtc[0] = 0;
      }
    }
  }
}


oder wie ich schreiben würde:
ISR(TIMER1_COMPA_vect){
  if (++rtc[2] > 99 ){rtc[2] = 0;
    if (++rtc[1] > 59 ){rtc[1] = 0;
      if (++rtc[0] > 9 ){rtc[0] = 0;}
    }
  }
}


oder eine komplette Uhr mit Datum und Schaltjahr bis 2099:
dm[12]={31,28,31,30,31,30,31,31,30,31,30,31};//ohne Schaltjahr
ISR(TIMER1_COMPA_vect){
  if(++rtc[6] > 99 ){rtc[6] = 0;//hundertstel
    if(++rtc[5] > 59 ){rtc[5] = 0;//Sek
      if(++rtc[4] > 59 ){rtc[4] = 0;//Min
        if(++rtc[3] > 23 ){rtc[3] = 0;//Std
          if(++rtc[2] > dm[rtc[1]]){rtc[2] = 0;//Tag
            if(++rtc[1] > 11){rtc[1] = 0;//Mon
              if(++rtc[0] & 3){dm[2]=28;}else{d[2]=29;}//Jahr
            }
          }
        }
      }
    }
  }
}

ungetestet, aus dem Stegreif getippt

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.