Alles hat eine genaue Zeit - DCF77 mit dem Arduino

Wir haben schon einige Uhren gebaut, entweder wurde die Zeit auf Basis manueller Eingaben und Wartezeiten, von NTP oder mit einer RTC-Modul berechnet. Heute möchten wir euch eine neue Möglichkeit der "Zeitgewinnung" vorstellen und zwar über DCF77.

Der DCF77 Sender:

In Mainflingen bei Frankfurt am Main steht ein Langwellensender für 77,5kHz. Dieser Sender sendet mit 50.000W die aktuelle Uhrzeit kodiert einmal pro Minute.

Dieser Sender und das Signal wird als DCF77 bezeichnet. Die Bezeichnung DCF77 ist das dem Sender zur internationalen Identifikation zugewiesene Rufzeichen.

Mit einem entsprechenden Empfangsmodul (z.B. pollin.de 810054) kann das Signal in einem Umkreis von bis zu 2000km um Mainflingen empfangen und dekodiert werden.

Zur Information, in anderen Ländern werden andere Zeitzeichensender eingesetzt, mit unterschiedlichen Frequenzen:

Rufzeichen Standort Frequenzen
Beta Russland 25 kHz
BPC China 68,5 kHz
BPL China 100 kHz
BPM China, Lintong (Xi’an) 2,5 MHz, 5 MHz, 10 MHz, 15 MHz
CHU Kanada, Ottawa 3,330 MHz, 7,850 MHz, 14,670 MHz
DCF77 Deutschland, Mainflingen 77,5 kHz
IBF Italien, Turin 5 MHz
JJY Japan, Berg Ōtakadoya 40 kHz
JJY Japan, Berg Hagane 60 kHz
MIKES Finnland, Espoo 25 MHz
MSF Großbritannien, Anthorn 60 kHz
RBU Russland, Taldom 66,66 kHz
RTZ Russland, Irkutsk 50 kHz
RWM Russland, Moskau 4,996 MHz, 9,996 MHz, 14,996 MHz
TDF Frankreich, Allouis 162 kHz
WWV USA, Fort Collins 2,5 MHz, 5 MHz, 10 MHz, 15 MHz, 20 MHz
WWVB USA, Fort Collins 60 kHz
WWVH USA, Hawaii, Kekaha 2,5 MHz, 5 MHz, 10 MHz, 15 MHz
YVTO Venezuela, Caracas 5 MHz

 

Aufbau des DCF77 Signals:

Der DCF77 Sender sendet in 60 Minuten mehrere Informationen.

Die Informationen werden in Sekundenimpulse kodiert. Ein High Impuls von 100ms (900ms LOW) bedeutet eine 0 und ein High Impuls von 200ms (800ms LOW) eine 1. Diese "Binäre" Kodierung kann anschließend in Datum und Uhrzeit, zusätzlich MESZ/MEZ und Wetterdaten zurückgerechnet werden.

Es werden 59 Bits übertragen, mit folgender Bedeutung:

Bit Bedeutung Wert
0 Start neuer Minute (immer 0)
1 verschlüsselte
Wetterdaten
2
3
4
5
6
7
8
9
10
11
12
13
14
15 Rufbit
16 Umstellung MEZ/MESZ
17 MESZ
18 MEZ
19 Schaltsekunde
20 Start Zeitinformation (immer 1)
21 Minute 1
22 2
23 4
24 8
25 10
26 20
27 40
28 Parität Minute
29 Stunde 1
30 2
31 4
32 8
33 10
34 20
35 Parität Stunde
36 Datum Tag 1
37 2
38 4
39 8
40 10
41 20
42 Wochentag 1
43 2
44 4
45 Datum Monat 1
46 2
47 4
48 8
49 10
50 Datum Jahr 1
51 2
52 4
53 8
54 10
55 20
56 40
57 80
58 Parität Datum

 

Aufgrund dieser Informationen können wir ein Arduino-Sketch erstellen:

Unseren DCF77 Empfänger schließen wir auf Pin 2 des Arduino an. 

Arduino-Sketch:

#define STATUS_PIN LED_BUILTIN
#define DCF_PIN 2
 
int HIGH_Start = 0;
int HIGH_Ende = 0;
int HIGH_Zeit = 0;
int LOW_Start = 0;
int LOW_Ende = 0;
int LOW_Zeit = 0;
 
bool Signal = false;
bool neueMinute = false;
int BIT = -1;
int ZEIT[65];
int ZEIT_STUNDE;
int ZEIT_MINUTE;
int ZEIT_TAG;
int ZEIT_MONAT;
int ZEIT_JAHR;
int ZEIT_WOCHENTAG;
int PAR_STUNDE;
int PAR_MINUTE;
int PAR_BEGINN;
 
void setup() {
  Serial.begin(115200);
  pinMode(DCF_PIN, INPUT);
  pinMode(STATUS_PIN, OUTPUT);
  Serial.println("Syncronisierung");
}
 
void loop() {
  if (BIT > 60) {neueMinute = false;}
  int DCF_SIGNAL = digitalRead(DCF_PIN);
  
  if (DCF_SIGNAL == HIGH && Signal == false) {
    Signal = true; 
    HIGH_Start = millis(); 
    LOW_Ende = HIGH_Start;  
    LOW_Zeit = LOW_Ende - LOW_Start; 
    
    if (neueMinute == true) {
      PrintBeschreibung(BIT);
      //Serial.print("Bit"); 
      //Serial.print (BIT); 
      //Serial.print (": "); 
      ZEIT[BIT] = (BIT_Zeit(LOW_Zeit));
      Serial.print (ZEIT[BIT]);
      //Serial.println ();
    }
    else {
      Serial.print(".");
    }
  }
 
  if (DCF_SIGNAL == LOW && Signal == true) {
    Signal = false; 
    HIGH_Ende = millis();  
    LOW_Start = HIGH_Ende; 
    HIGH_Zeit = HIGH_Ende - HIGH_Start; 
 
    NEUMINUTE(LOW_Zeit);
  }
}
 
int BIT_Zeit (int LOW_Zeit) {
   if (LOW_Zeit >= 851 && LOW_Zeit <= 950) {return 0;} 
   if (LOW_Zeit >= 750 && LOW_Zeit <= 850) {return 1;}
   if (LOW_Zeit <= 350) {BIT-=1;return "";}
}

void NEUMINUTE (int LOW_Zeit) {
  if (LOW_Zeit >= 1700) {
    BIT = 0;
    neueMinute = true;
    ZEIT_STUNDE = ZEIT[29]*1+ZEIT[30]*2+ZEIT[31]*4+ZEIT[32]*8+ZEIT[33]*10+ZEIT[34]*20;
    ZEIT_MINUTE = ZEIT[21]*1+ZEIT[22]*2+ZEIT[23]*4+ZEIT[24]*8+ZEIT[25]*10+ZEIT[26]*20+ZEIT[27]*40;
    PAR_STUNDE = ZEIT[35];
    PAR_MINUTE = ZEIT[28];
    ZEIT_TAG = ZEIT[36]*1+ZEIT[37]*2+ZEIT[38]*4+ZEIT[39]*8+ZEIT[40]*10+ZEIT[41]*20;
    ZEIT_MONAT = ZEIT[45]*1+ZEIT[46]*2+ZEIT[47]*4+ZEIT[48]*8+ZEIT[49]*10;
    ZEIT_JAHR = 2000+ZEIT[50]*1+ZEIT[51]*2+ZEIT[52]*4+ZEIT[53]*8+ZEIT[54]*10+ZEIT[55]*20+ZEIT[56]*40+ZEIT[57]*80;
    PAR_BEGINN = ZEIT[20];

    
    
    Serial.println();
    Serial.println("*****************************");
    Serial.print ("Uhrzeit: ");
    Serial.println();
    Serial.print (ZEIT_STUNDE);
    Serial.print (":");
    Serial.print (ZEIT_MINUTE);
    Serial.println();
    Serial.println();
    Serial.print ("Datum: ");
    Serial.println();
    Serial.print (ZEIT_TAG);
    Serial.print (".");
    Serial.print (ZEIT_MONAT);
    Serial.print (".");
    Serial.print (ZEIT_JAHR);
    Serial.println();
    Serial.println("*****************************");
    

  } else {BIT++;}
}
 
void PrintBeschreibung(int BitNummer) {
  switch (BitNummer) {
    case  0: Serial.println("\n# START MINUTE (IMMER 0)"); break;
    case  1: Serial.println("\n# WETTERDATEN"); break;
    case 15: Serial.println("\n# RUFBIT"); break;
    case 16: Serial.println("\n# MEZ/MESZ"); break;
    case 17: Serial.println("\n# MESZ"); break;
    case 18: Serial.println("\n# MEZ"); break;
    case 19: Serial.println("\n# SCHALTSEKUNDE"); break;
    case 20: Serial.println("\n# BEGIN ZEITINFORMATION (IMMER 1)"); break;
    case 21: Serial.println("\n# MINUTEN"); break;
    case 28: Serial.println("\n# PARITAET MINUTE"); break;
    case 29: Serial.println("\n# STUNDE");break;
    case 35: Serial.println("\n# PARITAET STUNDE"); break;
    case 36: Serial.println("\n# TAG"); break;
    case 42: Serial.println("\n# WOCHENTAG"); break;
    case 45: Serial.println("\n# MONAT"); break;
    case 50: Serial.println("\n# JAHR"); break;
    case 58: Serial.println("\n# PARITAET DATUM"); break;
  }
}

Als Ausgabe im Serial Monitor bekommen wir nun die Bitfolge und die berechnete Uhrzeit.

 

Nun könnt ihr auch DCF77 für eure Projekte verwenden. Viel Spass.

Letzter Artikel Anycubic i3 Mega

Kommentar

Mertke - April 23, 2019

Hallo, ein super Sketch. Der beste den ich bis jetzt hatte.
Ich bastel an einer Bewässerungsanlage mit 16 Ausgängen und 2 Zeiten pro Tag mit einer RTC DS3231. Ich hätte gerne eine zusätzliche DCF 77 Zeit.
Ich habe ein Modul von Pollin mit 3,3V und dahinter einen Verstärker mit Cmos IC 4093
(http://amateurfunkbasteln.de/dcf77/ )
Leider funktioniert bei mir nur ein keiner Teil und nur nach ändern der LOW Zeiten.
//if (LOW_Zeit >= 851 && LOW_Zeit <= 950) {return 0;} Original
if (LOW_Zeit >= 751 && LOW_Zeit <= 950) {return 0;} meine Eingabe
//if (LOW_Zeit >= 750 && LOW_Zeit <= 850) {return 1;} Original
if (LOW_Zeit >= 450 && LOW_Zeit <= 750) {return 1;} meine Eingabe
if (LOW_Zeit <= 350) {BIT-=1;return "";}
Auf dem seriellen Monitor kommt nur die Anzeige
Syncronisierung
18:54:22.126 ………… Die Urzeit funktioniert aber kein Datum

Ich nutze einen Arduino UNO am digitalen Pin 2 mit externem 10KOHM Widerstand gegen 5Volt. Anzeigen möchte ich die Uhrzeit auf einem Display 16×2 oder 20×4

Um Störimpulse zu verringern habe ich einen Festspannungsregler L4940V5 mit 5Volt aufgebaut an einem 12V AKKU
Wenn ich diese 5 Volt nutze habe ich aber keinen seriellen Monitor mehr.

Ich habe einige Schwierigkeiten mit dem Programmieren und lerne immer ein bischen mehr. Meistens versthe ich langsam die Beispiele und ändere den Sketch dann für mich um.

Ich würde mich über jede Hilfe sehr freuen
schönen Abend
Fredy

Fred - Dezember 18, 2018

Hallo, guter Sketch zur Abfrage der Zeit und auch für einen Laien wie mich nachvollziehbar. Ich hab in gleich getestet nachdem ich ihn im Netz gefunden hatte. Mein DCF77 Modul hat sofort funktioniert. Probleme gab es aber beim kopieren des Sketches mit der Kopierfunktion in die Arduino-IDE. Beim Kompilieren kamen jede Menge stray ‘\’ Fehlermeldungen. Erst durch Laden des Textes in Notepad++ (ANSI-Kodierung) und entfernen einiger komischer Zeichen funktionierte es dann. Ich würde auch gern noch wissen, wozu die Status-LED (Pin13) gedacht war. Gratuliere AZ-Delivery zu den vielen guten Beispielen, weiter so.

Hinterlasse einen Kommentar

Kommentare müssen vor der Veröffentlichung überprüft werden

Erforderliche Angabe