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 Epoxidharz, eine wasserdichte Sache

Hinterlasse einen Kommentar

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

Erforderliche Angabe