• Hallo Zusammen, Aufgrund der aktuellen Situation setzten wir die Möglichkeit aus, sich mit Gmail zu registrieren. Wir bitten um Verständnis Das RCMP Team

Anleitung Arduino mit DCF77-Modul und RTC Echtzeituhr DS3231

BAXL

Admin
Mitarbeiter
Arduinoprojekte benötigen oft das genaue Datum und die genaue Uhrzeit. Der Arduino hat zwar einen internen Timer, den man aber nicht wirklich gut für solche Zwecke verwenden kann. Als Alternativen gibt es Uhrenmodule (RTC - DS1302 oder DS3231), die aber oft auch nur mehr schlecht als recht funktionieren. Das DS3231 ist zwar schon sehr genau, weil es Schwankungen der Quarzfrequenz durch eine Temperaturmessung kompensiert, beim DS1302 hat man mit größeren Abweichungen zu kämpfen, hauptsächlich, wenn diese häufig abfragt werden. Besonders unangenehm ist es, wenn diese Module ihre Zeit komplett vergessen oder mit der Zeit komplett falsch gehen. Nicht zu vergessen die im Moment noch aktuellen Zeitumstellungen. Eine weitere Alternative ist die Uhrzeit aus dem GPS-Signal zu ziehen, dazu gibt des den Bericht Arduino - Zeitabgleich mit GPS-Modul

Für einen regelmäßigen Zeitabgleich eignen sich DCF77-Module, d.h., dass im normalen Programmablauf die Zeit aus einem RTC-Modul gezogen, dieses aber in gewissen Zeitabständen mit der "Atomuhr" synchronisiert wird. Normalerweise kommt es nicht auf ein paar Sekunden Abweichung an, sollte die Abweichung aber größer werden, sollte schon eine Korrektur erfolgen. Eine manuelle Korrektur erfordert leider einigen Umstand, sei es, dass man das RCF-Modul abklemmt und an einem zweiten Arduino neu stellt, oder indem man irgendeine Routine implementiert, bei der man mit Tastern umständlich neu hantiert.

Für meine Zwecke habe ich ein ELV Modul gekauft, das bereits einen belastbaren Ausgang bietet (open collector) und mit Spannungen zwischen 12,V und 15V betrieben werden kann.



Die Beschaltung gestaltete sich entsprechend einfach, weil ich zusätzlich nur einen 10 kiloOhm Widerstand von +5V auf den Signalpin legen musste. Erwähnenswert ist dabei, dass das Signal durch diese Schaltung invertiert wird. Das ist wichtig, wenn man den Pin mit einem Arduinoprogramm auswertet. Es gibt eine Vielzahl Librarys, die einem die Arbeit erleichtern, man muß bei meinem speziellen Modul dem Programm allerdings bei der Initialisierung mitteilen, dass das Signal invertiert ist. Dazu setzt man einfach einen zusätzlichen Parameter, aber dazu später mehr.

Für den Fall, dass ein Quellcode aus diesem Thema verwendet wird und der Compiler Fehler meldet, empfehle ich hier mal reinzugucken:
Fehlermeldungen wegen unterschiedlicher Softwarestände der Libs oder Arduino GUIs
 
Zuletzt bearbeitet:

BAXL

Admin
Mitarbeiter
Für den Betrieb dieser Schaltung verwende ich ein Beispielprogramm von der Seite https://netcoast.ch/DCF77/DCF77.html. Das programm wurde von mir noch um die Ausgabe auf einem 20x4 LCD-Display erweitert.

Auf der Seite rahner-edu.de findet sich auch etwas mehr zum technischen Hintergrund der Signale zur Zeitübermittlung.

C++:
//Beispielcode um einen Arduino Nan Clone mit DCF77 Modul von ELV zu verbinden und Zeit auszulesen.
//Mutationen durch slaps313 - 2018
//DCF77.h und TimeLib.h wurden ohne Anpassungen verwendet.
//DCF77 Bibliothek wurde von hier erhalten: http://thijs.elenbaas.net/downloads/?did=1
//TimeLib.h Bibliothek wurde von hier erhalten: https://github.com/PaulStoffregen/Time
//Die Sketch-Vorlage wurde von hier geladen (hier werden auch andere Module behandelt): https://www.issb.de/mw/index.php/Test_elektronischer_Funkuhren-Module_(DCF77)_am_Mikroconcroller

#include "DCF77.h" //Alle DCF77 Funktionen laufen ueber diese Bibliothek.
#include "TimeLib.h" //Time.h hat bei mir nie funktioniert, habe TimeLib.h eingebunden, dann gehts.

#define DCF_PIN 2 // Verbindung zum DCF77 Arduino UNO PIN
#define DCF_INTERRUPT 0 // Interrupt number associated with pin
#define PIN_LED 13 // Status von der Verbindung an LED-PIN 13

// Librarys für LCD-Display
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 20, 4); //Hier wird festgelegt um was für einen Display es sich handelt.

//time_t time;
// DCF77 DCF = DCF77(DCF_PIN, DCF_INTERRUPT); // Dieser Eintrag sollte für andere Module aktiviert werden...
// für das DCF-Modul von ELV muss das Signal invertiert werden, deshalb so:
DCF77 DCF = DCF77(DCF_PIN, DCF_INTERRUPT, false); // false für invertiertes Signal
// wurde ein gueltiges Signal gefunden
bool g_bDCFTimeFound = false;

void setup()
{
pinMode(PIN_LED, OUTPUT);
Serial.begin(9600);

lcd.init(); //Im Setup wird der LCD gestartet
lcd.backlight(); //Hintergrundbeleuchtung einschalten (lcd.noBacklight(); schaltet die Beleuchtung aus).

DCF.Start();
lcd.setCursor(0, 3); // Spalte, Zeile,  0, 0 entspricht 1. Spalte oder 1. Zeile
lcd.print("DCF77 mit LCD V1.0");
Serial.println("Warte auf DCF77 Zeit... ");
Serial.println("Es dauert in den meisten faellen mindestens 2 Minuten bis die Zeit aktualisiert wird.");
}

void loop()
{
// delay(950);
// das Signal wird nur alle 5 Sekunden abgefragt
delay(5000);

digitalWrite(PIN_LED, HIGH);
delay(50);
digitalWrite(PIN_LED, LOW);

time_t DCFtime = DCF.getTime(); // Check if new DCF77 time is available
if (DCFtime != 0)
{
Serial.println("Aktuelle Zeit wurde empfangen!");
setTime(DCFtime);
g_bDCFTimeFound = true;

}

// die Uhrzeit wurde gesetzt, also LED nach kurzer Zeit ein
if (g_bDCFTimeFound)
{
delay(50);
digitalWrite(PIN_LED, HIGH);
}
digitalClockDisplay();
}

void digitalClockDisplay()
{
// Anzeigen der Zeit auf dem 20x4 LCD-Display

lcd.setCursor(0, 0);
if (hour()<10){lcd.print("0");}
lcd.print(hour()); lcd.print(":");
if (minute()<10){lcd.print("0");}
lcd.print(minute()); lcd.print(":");
if (second()<10){lcd.print("0");}
lcd.print(second());

lcd.setCursor(0, 1);
if (day()<10){lcd.print("0");}
lcd.print(day()); lcd.print(".");
if (month()<10){lcd.print("0");}
lcd.print(month()); lcd.print(".");
lcd.print(year());

// Anzeigen der Zeit auf dem seriellen Monitor am PC
Serial.print(hour());
printDigits(minute());
printDigits(second());
Serial.print(" ");
Serial.print(day());
Serial.print(" ");
Serial.print(month());
Serial.print(" ");
Serial.print(year());
Serial.println();
}

void printDigits(int digits)
{
// Kleines Skript um bei Minuten und Sekunden eine 0 vornean zu stellen
Serial.print(":");
if(digits < 10)
Serial.print('0');
Serial.print(digits);
}
Monitorausgabe ohne Display:



Die komplette Schaltung mit Display sieht so aus:

 
Zuletzt bearbeitet:

BAXL

Admin
Mitarbeiter
Jetzt kommt der schwierigere Teil des Projektes, nämlich der Abgleich einer angeschlossenen Echtzeituhr (RTC). Dafür sind mehrere Strategien, auch in Kombination, denkbar.

  1. Die RTC wird zum ersten Mal in Betrieb genommen und hat noch keine brauchbare Zeiteinstellung.
  2. Die RTC wurde bereits gestellt, hat aber eine signifikante Abweichung bei den Sekunden, bzw. schon in den Minuten.
  3. Die RTC hat die Uhrzeit "vergessen" und muß neu gestellt werden.
  4. Es hat eine Umstellung von Sommer- auf Winterzeit gegeben, oder umgekehrt.

Weil die Abfrage der DCF77 Zeit Rechenzeit abfordert ist es ineffizient den Abgleich permanent durchzuführen, zumal wenige Sekunden Abweichung für die meisten Anwendungsfälle tolerierbar sind. Ich denke 10 Sekunden Differenz ist noch akzeptabel. Eine Überprüfung pro Stunde reicht vollkommen aus, es sei denn, die RTC liefert eine Zeit, oder ein Datum, das offensichtlich nicht stimmen kann (Plausibilitätsprüfung). Wahrscheinlich ist es sogar genug, nur einmal pro Tag zu synchronisieren.

Die Abgleichroutine wird damit aufwändig genug. Das Ganze muß sich noch gut in den übrigen Programmablauf einfügen und darf nicht stören.
 

BAXL

Admin
Mitarbeiter
Neuer Zwischenstand.

Parallel zur DCF77 Uhr läuft jetzt eine RTC DS3231. Das Programm wurde derart modifiziert, dass die Uhrzeiten der DCF (1. Zeile) und der RTC-Uhr(2. Zeile) angezeigt werden. Weiterhin wird angezeigt, ob das DCF-Signal ausgewertet wird (Zeile 3) und wann die letzte Synchonisation statt gefunden hat (unterste Zeile 4). Es wird nicht mehr bei jedem gültigen DCF-Empfang die RTC neu gestellt, sondern nur noch wenn die Schaltung neu gestartet wurde und die RTC "verstellt" ist und dann immer in einem vordeffinierten Zeitabstand (aktuell alle 2 Minuten). Der nächste Schritt wird die Verlängerung des Intervalls sein und dass die DCF-Signalauswertung in der Zeit zwischen den Aktualisierungen deaktiviert wird.



Das momentane, funktionierende Programm sieht so aus:

C++:
//Code um einen Arduino Nano Clone mit DCF77 Modul von ELV zu verbinden und Zeit auszulesen.
//Zur Überbrückung von Empfangsstörungen, bzw. wenn die DCF-Signalauswertung deaktiviert wird,
//steht eine RTC DS3231 parat, die parallel läuft

//DCF77.h und TimeLib.h wurden ohne Anpassungen verwendet.
//DCF77 Bibliothek wurde von hier erhalten: http://thijs.elenbaas.net/downloads/?did=1
//TimeLib.h Bibliothek wurde von hier erhalten: https://github.com/PaulStoffregen/Time
//Die Sketch-Vorlage wurde von hier geladen (hier werden auch andere Module behandelt): https://www.issb.de/mw/index.php/Test_elektronischer_Funkuhren-Module_(DCF77)_am_Mikroconcroller


// Librarys für DCF77 Funkuhrmodul
#include "DCF77.h" //Alle DCF77 Funktionen laufen ueber diese Bibliothek.
#include "TimeLib.h" //Time.h hat bei mir nie funktioniert, habe TimeLib.h eingebunden, dann gehts.

#define DCF_PIN 2 // Verbindung zum DCF77 Arduino UNO PIN
#define DCF_INTERRUPT 0 // Interrupt number associated with pin
#define PIN_LED 13 // Status von der Verbindung an LED-PIN 13

// DCF77 DCF = DCF77(DCF_PIN, DCF_INTERRUPT); // Dieser Eintrag sollte für andere Module aktiviert werden...
// für das DCF-Modul von ELV muss das Signal invertiert werden, deshalb so:

DCF77 DCF = DCF77(DCF_PIN, DCF_INTERRUPT, false); // false für invertiertes Signal
bool g_bDCFTimeFound = false; // wurde ein gueltiges DCF77 Signal gefunden?

// Librarys für LCD-Display
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 20, 4); //Hier wird festgelegt um was für einen Display es sich handelt.

// Library für RTC DS3231
// Das Uhrenmodul wird angeschlossen A4 - SDA, A5 - SCL
// (Jahr, Monat, Tag, Stunde, Minute, Sekunde)
// rtc.adjust(DateTime(2019, 1, 21, 3, 0, 0));

#include "RTClib.h"
RTC_DS3231 rtc; // Es wird eine Objekt rtc aus der Klasse RTC_3231 der RTClib.h erstellt


// Variablen für die Auswertung und den Abgleich der Zeiten
byte ErstStart = 1;
byte DCFaktiv = 0;
byte DCFZeitOK = 0;
long Intervall = 120000; // Abfrageintervall 2 Minuten
long UpdateTimer = 0; // Zwischenspeicher für die Wartezeit

void setup()
{
pinMode(PIN_LED, OUTPUT);
Serial.begin(9600); // Seriellen Monitor starten

DCF.Start(); // DCF Uhr starten
DCFaktiv=1; // Merker, dass das DCF77 Signal ausgerwetet wird, man kann das mit DCF.Stop(); anhalten

rtc.begin(); // RTC DS3231 starten

lcd.init(); //Im Setup wird der LCD gestartet
lcd.backlight(); //Hintergrundbeleuchtung einschalten (lcd.noBacklight(); schaltet die Beleuchtung aus).
lcd.setCursor(0, 3); // Spalte, Zeile,  0, 0 entspricht 1. Spalte oder 1. Zeile
lcd.print("DCF77 RTC LCD V1.0");
lcd.setCursor(0, 2); // Spalte, Zeile,  0, 0 entspricht 1. Spalte oder 1. Zeile
lcd.print("DCF77 aktiv: "); lcd.print(DCFaktiv);

Serial.println("Warte auf DCF77 Zeit... ");
Serial.println("Es dauert meistens ca. 2 Minuten bis die Zeit aktualisiert ist");
}

void loop()
{
// das Signal wird nur alle 5 Sekunden abgefragt
delay(5000);

digitalWrite(PIN_LED, HIGH);
delay(50);
digitalWrite(PIN_LED, LOW);

DCFZeitOK = 0; // noch kein gültiges DCF-Telegramm empfangen
time_t DCFtime = DCF.getTime(); // Prüfen ob eine neue DCF77 Zeit verfügbar ist

  if (DCFtime != 0)
  {
    Serial.println("Aktuelle Zeit wurde empfangen!");
    setTime(DCFtime);
    g_bDCFTimeFound = true;
    DCFZeitOK=1;
  }

  // die Uhrzeit wurde gesetzt, also LED nach kurzer Zeit ein
  if (g_bDCFTimeFound)
  {
    delay(50);
    digitalWrite(PIN_LED, HIGH);
  }

if ((DCFZeitOK=1)&&(year()>2019)&&(((millis()-UpdateTimer) > Intervall)) )
{
  ErstStart = 0;
  // Wenn eine gültige DCF77 Zeit vorliegt, das DCF Jahr > 2019 und Intervall vergangen ist, die RTC aktualisieren
  RTCUpdate();
  UpdateTimer = millis();
  lcd.setCursor(0, 3); // Spalte, Zeile,  0, 0 entspricht 1. Spalte oder 1. Zeile
  lcd.print("Sync: ");
  DateTime now = rtc.now();
  //Stunde = (now.hour()); Minute = (now.minute()); Sekunde = (now.second());
  if (now.hour() <10){lcd.print("0");} lcd.print(now.hour()); lcd.print(":");
  if (now.minute() <10){lcd.print("0");} lcd.print(now.minute()); lcd.print(":");
  if (now.second() <10){lcd.print("0");} lcd.print(now.second());  lcd.print("    ");
}

digitalClockDisplay(); // DCF77 Zeit anzeigen
RTCClockDisplay(); // RTC- Zeit anzeigen
}

void RTCUpdate()
{


// (Jahr, Monat, Tag, Stunde, Minute, Sekunde)
// rtc.adjust(DateTime(2019, 1, 21, 3, 0, 0));
Serial.println("Stelle RCT neu! ");
Serial.print(hour());
printDigits(minute());
printDigits(second());
Serial.print(" ");
Serial.print(day());
Serial.print(" ");
Serial.print(month());
Serial.print(" ");
Serial.print(year());
Serial.println();
   // Datum und Uhrzeit der FCF77 in RTC übertragen
   rtc.adjust(DateTime(year(), month(), day(), hour(), minute(), second()));
}

void RTCClockDisplay()
{
  // Anzeigen der RTC-Zeit auf dem 20x4 LCD-Display
  int Stunde; int Minute; int Sekunde;
  int Tag; int Monat; int Jahr;

  DateTime now = rtc.now();
  Stunde = (now.hour()); Minute = (now.minute()); Sekunde = (now.second());
  Jahr = (now.year()); Monat = (now.month()); Tag = (now.day());

  lcd.setCursor(0, 1);
  if (Stunde <10){lcd.print("0");} lcd.print(Stunde); lcd.print(":");
  if (Minute <10){lcd.print("0");} lcd.print(Minute); lcd.print(":");
  if (Sekunde <10){lcd.print("0");} lcd.print(Sekunde); lcd.print(" ");

  //lcd.setCursor(0, 1);
  if (Tag <10){lcd.print("0");} lcd.print(Tag); lcd.print(".");
  if (Monat <10){lcd.print("0");}lcd.print(Monat); lcd.print(".");
  lcd.print(Jahr);
}

void digitalClockDisplay()
{
// Anzeigen der Zeit auf dem 20x4 LCD-Display

lcd.setCursor(0, 0);
if (hour()<10){lcd.print("0");} lcd.print(hour()); lcd.print(":");
if (minute()<10){lcd.print("0");} lcd.print(minute()); lcd.print(":");
if (second()<10){lcd.print("0");}lcd.print(second()); lcd.print(" ");

//lcd.setCursor(0, 1);
if (day()<10){lcd.print("0");} lcd.print(day()); lcd.print(".");
if (month()<10){lcd.print("0");} lcd.print(month()); lcd.print(".");
lcd.print(year());

// Anzeigen der Zeit auf dem seriellen Monitor am PC
Serial.print(hour());
printDigits(minute());
printDigits(second());
Serial.print(" ");
Serial.print(day());
Serial.print(" ");
Serial.print(month());
Serial.print(" ");
Serial.print(year());
Serial.println();
}

void printDigits(int digits)
{
// Kleines Skript um bei Minuten und Sekunden eine 0 vorne an zu stellen
Serial.print(":");
if(digits < 10)
Serial.print('0');
Serial.print(digits);
}
Komplette Schaltung:

 
Zuletzt bearbeitet:

BAXL

Admin
Mitarbeiter
Das Programm aus Post #5 ist jetzt einen ganzen Tag durchgelaufen. Es gab keine Probleme und die RTC wurde zuverlässig alle 2 Minuten aktualisiert. Es gab auch keine Unregelmäßigkeiten beim Betrieb sowohl am PC als auch an einem USB-Netzteil. Ich erwähne das, weil ich bei vielen Berichten über Probleme von "unsauberen" Schaltnetzteilen gelesen habe. Die DCF77 Antenne war im 1. OG stets waagrech in südwest Richtung ausgerichtet und lag quasi 1m neben meinem PC.

Zwischenzeitlich ist ein zweites Projekt für eine genaue Zeitbasis dazugekommen, die Verwendung der GPS-Satellitendaten. In jedem GPS-Signal steckt auch die genaue UTC-Uhrzeit, diese Information kann man aus dem übrigen serellen Datenstrom herausfiltern und ebenfalls zum Stellen der Uhrzeit verwenden. In einem anderen Projekt stelle ich das vor: Arduino - Zeitabgleich mit GPS-Modul
 
Zuletzt bearbeitet:

crazysky

Neuer Benutzer
Das ist ja super! Genau so etwas habe ich gesucht. Gibt es inzwischen schon einer Version mit einem stündlichen Abgleich?
Grüße
 

BAXL

Admin
Mitarbeiter
Das ist ja super! Genau so etwas habe ich gesucht. Gibt es inzwischen schon einer Version mit einem stündlichen Abgleich?
Grüße
Hallo Crazysky,

wie oft Du den Abgleich machen willst, kannst Du im Programm ganz einfach selbst einstellen.
Dazu muß nur die Zeile
long Intervall = 120000; // Abfrageintervall 2 Minuten
entsprechend angepasst werden in
long Intervall = 3600000; // Abfrageintervall 60 Minuten

Ein kürzeres Intervall ist bei einer Digitalanzeige aber kein Drama, weil die Anzeige direkt wieder da ist. Analoge Uhren, also mit Zeigern, haben idR. längere Intervalle, teilweise sogar nur einmal am Tag. Das ist aber dem Umstand geschuldet, das dafür der Minutenzeiger 12x die Runde machen muß. Das ist störend, weil in der Zeit die Uhrzeit nicht abgelesen werden kann und die Uhr Laufgeräusche macht. Hinzu kommt der höhere Stromverbrauch für die Mechanik beim Umstellen. Ich würde bei einer Digitalanzeige das Intervall deshalb nicht länger als eine Stunde und nicht kürzer als zwei Minuten machen. Wenn der DCF77-Empfänger als Zeit-Basis dient, ist kürzer als 2 Minuten sowieso sinnlos, weil nur jede Minute das aktuelle Zeitsignal empfangen wird.

Edit:

Bei meiner Variante mit GPS-Modul mache ich einen Abgleich sogar erst, wenn ich eine Abweichung von 1s habe.
Arduino - Zeitabgleich mit GPS-Modul
 
Zuletzt bearbeitet:

crazysky

Neuer Benutzer
Hallo,

vielen Dank für die schnelle Antwort!
Ich habe eher schlechte Erfahrungen gemacht, mit so großen intervall-Zahlen. Ich habe mit der Hilfe aus einem anderen Forum eine elegantere Lösung gestern erfolgreich eingebaut.
Hierbei wird zu jeder vollen Stunde einmal abgeglichen.

Code:
static byte stdMerker = 255;


if ((DCFZeitOK=1)&&(year()>2019)&&(hour()!=stdMerker) )
{
  Serial.println("Bedingungen für das Synchroniseren der Zeit sind erfüllt");
  ErstStart = 0;
  Serial.print("Merker derzeit:");
  Serial.println(stdMerker);
  // Wenn eine gültige DCF77 Zeit vorliegt, das DCF Jahr > 2019 und die aktuelle Stunde ungleich derjenigen ist, die im Merker noch hinterlegt ist, wird die RTC aktualisiert
  RTCUpdate();
  DateTime now = rtc.now();
  Serial.println("Merker neu setzen");
  stdMerker = hour();
}
else
{
  Serial.print("Bedingungen für das Synchroniseren der Zeit sind NICHT erfüllt");
  Serial.println();
}
Gruß
 

BAXL

Admin
Mitarbeiter
Das sieht doch gut aus. Jeder gestaltet sein Programm nach eigenen Wünschen und Anforderungen. Wichtig ist nur, dass man eine übersichtliche und verständliche Basis hat, die nicht mit unnötigen Gadgets überladen ist. Es fällt schon schwer genug sich in ein fremdes Programm reinzudenken, da machen trickreiche Speziallösungen das Verständnis zusätzlich schwer. Weiterhin viel Erfolg. Wenn Du Fragen hast, Du weißt ja wo Du uns findest :)
Auf jeden Fall vielen Dank für Deine Rückmeldung und die konstruktive Ergänzung.

Gruß
BAXL
 
Zuletzt bearbeitet:

MAVHH

Mitglied
Hallo, ich habe ein Problem mit dem Code von # 5.

Die Synchronisation wird ausgeführt ... aber nur, wenn ich den LCD.Print-Teil von digitalClockDisplay () und RTCClockDisplay () auskommentiere. Ich habe RTCClockDisplay () geändert, um die RTC-Zeit an Serial.print zu senden. Ich sehe also, dass die RTC-Zeit von der DCF erfolgreich aktualisiert wurde.

Es gibt kein Problem mit den anderen LCD.Print commands!

Ich habe keine Ideen mehr... Irgendwelche Ideen?

Hier ist meine Version des Codes (mit LCD.Print auskommentiert) - Es funktioniert ... außer natürlich, dass die Uhr auf dem LCD angezeigt wird.:

C++:
#include "DCF77.h"
#include "TimeLib.h"
#include "RTClib.h"
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

RTC_DS1307 rtc;
LiquidCrystal_I2C lcd(0x27, 20, 4);

#define DCF_PIN 2             // Connection pin to DCF 77 device
#define DCF_INTERRUPT 0         // Interrupt number associated with pin

bool g_bDCFTimeFound = false; // wurde ein gueltiges DCF77 Signal gefunden?

#define PIN_LED 13// Status LED-PIN 13

time_t time;
DCF77 DCF = DCF77(DCF_PIN, DCF_INTERRUPT);

byte ErstStart = 1;
byte DCFaktiv = 0;
byte DCFZeitOK = 0;
long Intervall = 120000; // Abfrageintervall 2 Minuten 1sec
long UpdateTimer = 0; // Zwischenspeicher für die Wartezeit

void setup() {
  pinMode(PIN_LED, OUTPUT);
  Serial.begin(9600);
  DCF.Start(); // DCF Receiver start
  rtc.begin(); // RTC start
  lcd.begin(); // LCD start
  Serial.println("Waiting for DCF77 time ... ");
  Serial.println("It will take at least 2 minutes until a first update can be processed.");
  lcd.backlight(); // Backlight on.
  lcd.setCursor(0, 3); // Set cursor location. (column, row)
  lcd.print("---DCF77 RTC TEST---");
}

void loop()
{
  delay(1000);
  time_t DCFtime = DCF.getTime(); // Check if new DCF77 time is available
 
  if (DCFtime != 0)
  {
    Serial.println("Time is updated");
    setTime(DCFtime);
    g_bDCFTimeFound = true;
    DCFZeitOK = 1;
  }

  if (g_bDCFTimeFound)   //If time is set, set LED.
  {
    delay(50);
    digitalWrite(PIN_LED, HIGH);
  }

  if ((DCFZeitOK = 1) && (year() > 2019) && (((millis() - UpdateTimer) > Intervall)) )
  {
    ErstStart = 0;
    // Wenn eine gültige DCF77 Zeit vorliegt, das DCF Jahr > 2019 und Intervall vergangen ist, die RTC aktualisieren
    RTCUpdate();
    UpdateTimer = millis();
    lcd.setCursor(0, 2); // Spalte, Zeile,  0, 0 entspricht 1. Spalte oder 1. Zeile
    lcd.print("Last Sync: ");
    DateTime now = rtc.now();
    //Stunde = (now.hour()); Minute = (now.minute()); Sekunde = (now.second());
    if (now.hour() < 10) {
      lcd.print("0");
    } lcd.print(now.hour()); lcd.print(":");
    if (now.minute() < 10) {
      lcd.print("0");
    } lcd.print(now.minute()); lcd.print(":");
    if (now.second() < 10) {
      lcd.print("0");
    } lcd.print(now.second());  lcd.print("    ");
  }
 
  digitalClockDisplay();
  RTCClockDisplay();
 
}

void RTCUpdate()
{
  Serial.println("RTC Reset!");
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(" ");
  Serial.print(day());
  Serial.print(" ");
  Serial.print(month());
  Serial.print(" ");
  Serial.print(year());
  Serial.println();
  // RTC time and date set from DCF77
  rtc.adjust(DateTime(year(), month(), day(), hour(), minute(), second()));
}

void RTCClockDisplay()
{
  DateTime rtcnow = rtc.now();

  int ss = rtcnow.second();
  int mm = rtcnow.minute();
  int hh = rtcnow.hour();
  int dd = rtcnow.day();
  int MM = rtcnow.month();
  int yyyy = rtcnow.year();

  Serial.print("RTC: ");
  Serial.print(hh);
  Serial.print(":");
  Serial.print(mm);
  Serial.print(":");
  Serial.print(ss);
  Serial.print("  ");

  //Display RCT time to LCD
  /*
    lcd.setCursor(0, 0);
    if (hh < 10) {
    lcd.print("0");
    } lcd.print(hh); lcd.print(":");
    if (mm < 10) {
    lcd.print("0");
    } lcd.print(mm); lcd.print(":");
    if (ss < 10) {
    lcd.print("0");
    } lcd.print(ss); lcd.print(" ");

    if (dd < 10) {
    lcd.print("0");
    } lcd.print(dd); lcd.print(".");
    if (mm < 10) {
    lcd.print("0");
    } lcd.print(MM); lcd.print(".");
    lcd.print(yyyy);
  */
}


void digitalClockDisplay() {
  // digital clock display of the time
  /*
    lcd.setCursor(0, 0);
    if (hour() < 10) {
      lcd.print("0");
    } lcd.print(hour()); lcd.print(":");
    if (minute() < 10) {
      lcd.print("0");
    } lcd.print(minute()); lcd.print(":");
    if (second() < 10) {
      lcd.print("0");
    } lcd.print(second()); lcd.print(" ");

    if (day() < 10) {
      lcd.print("0");
    } lcd.print(day()); lcd.print(".");
    if (month() < 10) {
      lcd.print("0");
    } lcd.print(month()); lcd.print(".");
    lcd.print(year());
  */
  Serial.print("DCF: ");
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(" ");
  Serial.print(day());
  Serial.print(" ");
  Serial.print(month());
  Serial.print(" ");
  Serial.print(year());
  Serial.println();
}

void printDigits(int digits) {
  // utility function for digital clock display: prints preceding colon and leading 0
  Serial.print(":");
  if (digits < 10)
    Serial.print('0');
  Serial.print(digits);
}
 

MAVHH

Mitglied
Es ist ein 20x4 / i2c. Genau so #5. Das Display funktioniert... es zeigt die 'LAST sync: hh:mm:ss' von Void Loop an... Wenn ich die Live-Uhren durch Entkommentieren aktiviere, Uhren läuft an die LCD, aber funktioniert die Synchronisierung nicht mehr...
 

BAXL

Admin
Mitarbeiter
Ich schreibe sowas nur ungerne aber um Genaueres sagen zu können bräuchte ich schon mindestens ein Foto, um zu sehen was Du überhaupt alles angeschlossen hast und wie.
Ist das nur das DCF77 Modul mit dem Nano, oder ist da auch das normale Uhrenmodul dran, und wenn ja, welches? Du hast Die Schaltung vor Augen und brütest schon Stunden daran, ich sehe nur ein paar Zeilen Text und muß mir alles zusammenreimen.
 

MAVHH

Mitglied
Klar verstanden! Und richtig - Ich habe den Code und die Schaltplan jetzt sicherlich zu viele Stunden lang angestarrt!

Ich habe einen TinyRTC DS1307, das I2C 4x20 LCD und einen CANAduino DCF77 Empfänger. Ich denke der Schaltplan ist genau wie #5 oben (außer dem DS1307 anstelle des DS3231)... Aber fange ich jetzt an, an mir selbst zu zweifeln! Ich werde ein Foto teilen, wenn ich nach der Arbeit zu Hause bin. Vielleicht gelöst das Problem heute Abend einfach daran, dass ich letzte Nacht geschlafen habe!

Ich werde das Update später senden.

Danke dir.
 

BAXL

Admin
Mitarbeiter
Beim DS1307 und DS3231 gibt es Unterschiede bei der Bedienung. Du solltest das mal checken.
RTC3231 Echtzeituhr für Arduino mit Praxisbeispiel

// RTC based on the DS1307 chip connected via I2C and the Wire library
enum Ds1307SqwPinMode { OFF = 0x00, ON = 0x80, SquareWave1HZ = 0x10, SquareWave4kHz = 0x11, SquareWave8kHz = 0x12, SquareWave32kHz = 0x13 };

class RTC_DS1307 {
public:
boolean begin(void);
static void adjust(const DateTime& dt);
uint8_t isrunning(void);
static DateTime now();
static Ds1307SqwPinMode readSqwPinMode();
static void writeSqwPinMode(Ds1307SqwPinMode mode);
uint8_t readnvram(uint8_t address);
void readnvram(uint8_t* buf, uint8_t size, uint8_t address);
void writenvram(uint8_t address, uint8_t data);
void writenvram(uint8_t address, uint8_t* buf, uint8_t size);
};

// RTC based on the DS3231 chip connected via I2C and the Wire library
enum Ds3231SqwPinMode { DS3231_OFF = 0x01, DS3231_SquareWave1Hz = 0x00, DS3231_SquareWave1kHz = 0x08, DS3231_SquareWave4kHz = 0x10, DS3231_SquareWave8kHz = 0x18 };

class RTC_DS3231 {
public:
boolean begin(void);
static void adjust(const DateTime& dt);
bool lostPower(void);
static DateTime now();
static Ds3231SqwPinMode readSqwPinMode();
static void writeSqwPinMode(Ds3231SqwPinMode mode);
};
 
Zuletzt bearbeitet:

MAVHH

Mitglied
Also habe ich die Schaltbild und den Code doppelt und dreifach überprüft - es ist identisch mit dem Diagramm in # 5. Die einzige verbleibende Möglichkeit ist der Unterschied in der Funktion des DS3231 und des DS1307. Das ist mir unangenehm, weil ich nicht verstehe, warum es relevant ist ... trotzdem habe ich einen DS3231 bei Amazon bestellt, um ihn morgen zu testen!
 

BAXL

Admin
Mitarbeiter
Hmm, tut mir auch leid, ich habe aber gar nicht erst auf DS1307 gesetzt weil die RTC im Vergleich zum DS3231 mehr Nachteile hat und der Preisunterschied marginal ist. Möglich dass es auch mit dem DS1307 machbar ist, das habe ich aber nie ins Auge gefasst :)

Manchmal sind das auch wirklich unscheinbare Kleinigkeiten auf die man erst kommen muss. Das habe ich mehr als einmal erfahren müssen.
 

MAVHH

Mitglied
Also ... der DS3231 ist angekommen. Die Synchronisierung funktioniert derzeit überhaupt nicht, mit oder ohne "Live Uhr" an LCD anzeigt. Zurück zum DS1307 gewechselt... wie bevor funktioniert die Synchronisierung perfekt, solange auf dem LCD keine "Live-Uhr" angezeigt wird.

Vielleicht ist es einfach Zeit für ein Bier!!!
 

MAVHH

Mitglied
Das Bier hat funktioniert!
i2c-Kabel zwischen LCD und RTC teilweise verdrillt ... Ghosting/Cross-Talk, Die regalmäßig Aktualisierung der LCD für Live-Uhr muss so viel Rauschen erzeugen, dass die RTC-Aktualisierung verwirrt ist! Nachdem die Kabel aufgeräumt sind, ist es voll funktionsfähig!

Danke für die Vorschläge!
 
Top Bottom