Genaue Uhr - Frequenzteiler

OP #1035689
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.
#1035762
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
#1035776
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
#1036245
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
Gast #1036357
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
Gast #1036589
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren