Forum: Mikrocontroller und Digitale Elektronik DS3231 : Ungenauigkeit SQW 1kHz


von Stefan S. (sschultewolter)


Lesenswert?

Hallo,

da ich es bislang noch nicht hinbekommen habe, die Kommunikation 
zwischen Atmega328P(später Attiny85) und DS3231 zu realisieren,
habe ich den SQW des DS3231 auf 1024Hz eingestellt über die Register RS1 
und RS2.

Nun habe ich die Zeit eine halbe Stunde laufen lassen mit einer 
seriellen Ausgabe zur Kontrolle.

Was mir aufgefallen ist, dass die Zeit um 2min/30min nachgeht.

Im Datenblatt habe ich keine Infos gefunden, ob der Ausgang des RTCs 
ebenfalls Temperaturkompensiert ist.

Der Atmega328P wird genutzt mit einem Resonator mit 5V bei 16MHz. Der 
DS3231 nutzt auch die Vcc von 5V.
1
void time_init(void)
2
{
3
  DDRD &= ~(1 << DDD2);
4
  //PORTD |= (1 << PORTD2);      // Pull-Up aktivieren
5
6
  // (0 << ISCx1) | (0 << ISCx0)    LOW-Level am Pin löst den Interrupt aus
7
  // (0 << ISCx1) | (1 << ISCx0)    Jede Änderung am Pin löst den Interrupt aus
8
  // (1 << ISCx1) | (0 << ISCx0)    Eine fallende Flanke löst den Interrupt aus
9
  // (1 << ISCx1) | (1 << ISCx0)    Eine steigende Flanke löst den Interrupt aus
10
  EICRA |= (1 << ISC00) | (1 << ISC01);
11
  EIMSK |= (1 << INT0);
12
  sei();
13
}
1
ISR(INT0_vect)
2
{
3
  if(++freq_1024 == 1024)
4
  {
5
    freq_1024 = 0;
6
    if(++second == 60)
7
    {
8
      second = 0;
9
      if(++minute == 60)
10
      {
11
        minute = 0;
12
        if(++hour == 24) hour = 0;
13
        
14
        if(hour >= 12) {
15
          hour12 -= 12;
16
          isAm = 0;
17
        }
18
        else
19
        {
20
          hour12 = hour;
21
          isAm = 1;
22
        }
23
      }
24
    }
25
  }
26
}

von Thorsten S. (thosch)


Lesenswert?

Stefan S. schrieb:
> da ich es bislang noch nicht hinbekommen habe, die Kommunikation
> zwischen Atmega328P(später Attiny85) und DS3231 zu realisieren,
> habe ich den SQW des DS3231 auf 1024Hz eingestellt über die Register RS1
> und RS2.
Den Satz verstehe ich jetzt nicht wirklich.
Um den Ausgang SQW auf 1024Hz einzustellen, muß die I2C-Kommunikation 
zwischen dem µC und dem DS3231 doch funktionieren! Was hast du dann 
nicht hinbekommen?

> Was mir aufgefallen ist, dass die Zeit um 2min/30min nachgeht.
Da liegt ein generelles Problem vor...
Sperrst du im Hauptprogramm an irgendeiner Stelle mal die Interrupts für 
mehr als maximal ein paar Hundert µs?
Das wäre im Zweifelsfalle tödlich, weil du dann Interrupts verpaßt, was 
naturgemäß zu einem Nachgehen deiner Interrupt-Uhr führt.
Achja: Wenn du eh nur an Sekunden interessiert bist, warum setzt du dann 
den SQW Ausgang nicht auf 1Hz auf (RS1 = 0, RS2 = 0) und sparst dir 1023 
Interrupts pro Sekunde?
Davon abgesehen würde ich für die Uhrzeit einfach die Echtzeit-Register 
des DS3231 auslesen, die muß man Dank der Pufferbatterie auch nicht nach 
jedem Power Up neu stellen, dafür ist so'ne RTC schließlich da! ;-)

> Im Datenblatt habe ich keine Infos gefunden, ob der Ausgang des RTCs
> ebenfalls Temperaturkompensiert ist.
Selbstverständlich ist er das, geht auch aus dem Blockschaltbild im 
Datenblatt (S. 8) hervor. Alles andere wäre ja auch sinnbefreit.

> Der DS3231 nutzt auch die Vcc von 5V.
5V-Betrieb ist laut Datenblatt zwar noch zulässig, aber der DS3231 ist 
für nominell 3V3 ausgelegt.

Der SQW-Ausgang des DS3231 ist Open Drain. Daher die fallende Flanke 
nehmen, dann paßt die Flankensteilheit auf jeden Fall.
1
void time_init(void)
2
{
3
  DDRD &= ~(1 << DDD2);
4
  //PORTD |= (1 << PORTD2);      // Pull-Up aktivieren
5
6
  // (0 << ISCx1) | (0 << ISCx0)    LOW-Level am Pin löst den Interrupt aus
7
  // (0 << ISCx1) | (1 << ISCx0)    Jede Änderung am Pin löst den Interrupt aus
8
  // (1 << ISCx1) | (0 << ISCx0)    Eine fallende Flanke löst den Interrupt aus
9
  // (1 << ISCx1) | (1 << ISCx0)    Eine steigende Flanke löst den Interrupt aus
10
  EICRA |= (1 << ISC00) | (0 << ISC01);  // Fallende Flanke von SQW nehmen!
11
  EIMSK |= (1 << INT0);
12
  sei();
13
}

Zeig mal deine komplette Schaltung! Was hast du als Pullup an SQW dran?

Toggel doch mal einen Port-Pin in der ISR, und hänge ein Scope an SQW 
vom DS3231 sowie an diesen Toggle-Pin. Trigger auf SQW.
Dann siehst du recht schnell, ob der µC jeden Interrupt bearbeitet.

Achja, nur der Vollständigkeit halber: Keramische Abblock-Kondensatoren 
sind doch wohl hoffentlich an jedem VCC/GND Pin-Paar direkt an jedem IC 
verbaut?
Der DS3231 braucht unbedingt einen guten Abblock-C, laut Datenblatt von 
100n bis 1µ. Fehlt der, geht die Uhr komplett falsch.

: Bearbeitet durch User
von Stefan S. (sschultewolter)


Lesenswert?

Thorsten S. schrieb:
> Stefan S. schrieb:
>> da ich es bislang noch nicht hinbekommen habe, die Kommunikation
>> zwischen Atmega328P(später Attiny85) und DS3231 zu realisieren,
>> habe ich den SQW des DS3231 auf 1024Hz eingestellt über die Register RS1
>> und RS2.
> Den Satz verstehe ich jetzt nicht wirklich.
> Um den Ausgang SQW auf 1024Hz einzustellen, muß die I2C-Kommunikation
> zwischen dem µC und dem DS3231 doch funktionieren! Was hast du dann
> nicht hinbekommen?
Habe noch einen anderen Sketch vom Arduino gehabt, mit dem ich die SQW 
Frequenz einstellen kann.

>> Was mir aufgefallen ist, dass die Zeit um 2min/30min nachgeht.
> Da liegt ein generelles Problem vor...
> Sperrst du im Hauptprogramm an irgendeiner Stelle mal die Interrupts für
> mehr als maximal ein paar Hundert µs?
> Das wäre im Zweifelsfalle tödlich, weil du dann Interrupts verpaßt, was
> naturgemäß zu einem Nachgehen deiner Interrupt-Uhr führt.
Im Einsatz kommt die LightWeight WS2812B Libary. Die hat soweit dieses 
Verhalten :(

> Achja: Wenn du eh nur an Sekunden interessiert bist, warum setzt du dann
> den SQW Ausgang nicht auf 1Hz auf (RS1 = 0, RS2 = 0) und sparst dir 1023
> Interrupts pro Sekunde?
Ich brauche die 1024 Hz nicht, jedoch benötige ich diese, um ein 64Hz 
Signal zu erzeugen. Soll heißen die Leds werden alle 64 bzw 32mal pro 
Sekunde aktualisiert.

Die Zeit zwischen jeder Sekunde zu nehmen und daraus die 64 Hz zu bilden 
brachte mir immer mal wieder Probleme, dass der Fade nicht ganz sauber 
verlief.

> Davon abgesehen würde ich für die Uhrzeit einfach die Echtzeit-Register
> des DS3231 auslesen, die muß man Dank der Pufferbatterie auch nicht nach
> jedem Power Up neu stellen, dafür ist so'ne RTC schließlich da! ;-)
Ja, ist der Sinn von dem IC ;) Wenns gehen würde. Problem ist aber dann 
die Synczeit, das in dme Moment die Uhr falsch bzw. Leds falsch 
angezeigt werden und es zu einem Sprung kommt.

>> Im Datenblatt habe ich keine Infos gefunden, ob der Ausgang des RTCs
>> ebenfalls Temperaturkompensiert ist.
> Selbstverständlich ist er das, geht auch aus dem Blockschaltbild im
> Datenblatt (S. 8) hervor. Alles andere wäre ja auch sinnbefreit.
Ja, das war die Frage. Das Schaltbild habe ich gesehen, wusste aber 
nicht,
ob die Control Logic/Divider diesen dann auch entsprechend anpasst. Nun 
gut, jetzt weiß ichs.

>> Der DS3231 nutzt auch die Vcc von 5V.
> 5V-Betrieb ist laut Datenblatt zwar noch zulässig, aber der DS3231 ist
> für nominell 3V3 ausgelegt.
Habe derzeit keine Spannungsversorgung mit 3V3 auf dem Board, bzw. 
keinen passenden Spannungsregler. Ein großen Stepdown-Regler wollte ich 
dafür jetzt nicht umbedingt verwenden. Später werde ich schauen, wie ich 
das löse.

Vermutlich ein kleinen Linearregler und den Attiny/Atmega mit 3V3 und 
8MHz betrieben sowie einen Pegelwandler (Transistor) an einem Ausgang 
für 5V DATA Signal der WS2812B

> Der SQW-Ausgang des DS3231 ist Open Drain. Daher die fallende Flanke
> nehmen, dann paßt die Flankensteilheit auf jeden Fall.
>
>
1
> void time_init(void)
2
> {
3
>   DDRD &= ~(1 << DDD2);
4
>   //PORTD |= (1 << PORTD2);      // Pull-Up aktivieren
5
> 
6
>   // (0 << ISCx1) | (0 << ISCx0)    LOW-Level am Pin löst den Interrupt 
7
> aus
8
>   // (0 << ISCx1) | (1 << ISCx0)    Jede Änderung am Pin löst den 
9
> Interrupt aus
10
>   // (1 << ISCx1) | (0 << ISCx0)    Eine fallende Flanke löst den 
11
> Interrupt aus
12
>   // (1 << ISCx1) | (1 << ISCx0)    Eine steigende Flanke löst den 
13
> Interrupt aus
14
>   EICRA |= (1 << ISC00) | (0 << ISC01);  // Fallende Flanke von SQW 
15
> nehmen!
16
>   EIMSK |= (1 << INT0);
17
>   sei();
18
> }
>
> Zeig mal deine komplette Schaltung! Was hast du als Pullup an SQW dran?
Schaltbild müsste ich Eagle anfertigen, jedoch lohnt sichs vielleicht 
kaum, weil derzeit wenig extern Beschaltet ist.
Ich habe am SQW einen 10k Pull-Up gesetzt.

> Toggel doch mal einen Port-Pin in der ISR, und hänge ein Scope an SQW
> vom DS3231 sowie an diesen Toggle-Pin. Trigger auf SQW.
> Dann siehst du recht schnell, ob der µC jeden Interrupt bearbeitet.
Ein Osziloskop fehlt mir ;(, steht noch auf der Nice-To-Have-Liste.
Wobei die Interupts dauerhaft gezählt wurden, wenn ich die WS2812B nicht 
eingebunden hab.

> Achja, nur der Vollständigkeit halber: Keramische Abblock-Kondensatoren
> sind doch wohl hoffentlich an jedem VCC/GND Pin-Paar direkt an jedem IC
> verbaut?
> Der DS3231 braucht unbedingt einen guten Abblock-C, laut Datenblatt von
> 100n bis 1µ. Fehlt der, geht die Uhr komplett falsch.
Am DS3231 hängt wie auch beim Atmega pro Vcc/Gnd ein Kerko mit 0,1µF

von Stefan S. (sschultewolter)


Lesenswert?

Den Interrupt habe ich inzwischen auf
1
  // (1 << ISCx1) | (0 << ISCx0)    Eine fallende Flanke löst den Interrupt aus
2
  // (1 << ISCx1) | (1 << ISCx0)    Eine steigende Flanke löst den Interrupt aus
3
  EICRA |= (1 << ISC01) | (0 << ISC00);
An der Auswertung, wie erwartet, ändert es bei mir nichts. Die Interrupt 
Lösung hat ja auch bereits als steigende Flanke genauso funktioniert.

Das Problem bei mir ist die WS2812B Ansteuerung. Die Ansteuerung der 
WS2812B erfolgt sobald meine ISR 16mal durchlaufen ist.
1
#define FREQ_64    freq_1024/16
1
  while (1)
2
  {
3
    static int last_minute;
4
    if(minute != last_minute)
5
    {
6
      last_minute = minute;
7
      printf("%02d:%02d:%02d\n", hour, minute, second);
8
    }
9
    
10
    static int last_freq_64;
11
    if(FREQ_64 != last_freq_64)
12
    {
13
      last_freq_64 = FREQ_64;
14
      leds_clock3(hour12, minute, second, FREQ_64);
15
    }
16
  }

Würde es eventuell Sinn machen, einen zB. Attiny85 (wäre der kleinste 
den ich daheim liegen hab) zu nutzen, um die Interupts zu zählen und nur 
alle 16Takte einen Ausgang zu toggeln, sodass der eigentliche 
Attiny/Atmega nur noch 64 mal in der Sekunde in den Interupt geht? Das 
beschreiben der Leds erfolgt ja zeitnah nach der ISR. Ansonsten ist da 
nichts blockierendes im Code, der der die loop verzögert.

Jedoch ist die Zeit von ~1ms scheinbar nicht ausreichend, um den Led 
Strip (60Leds) zu beschreiben. Was für Optionen stehen mir hier zur 
Verfügung? Gibt es einfache Bausteine,

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.