Alles heeft een exacte tijd - DCF77 met de Arduino

We hebben al verschillende klokken gebouwd, ofwel werd de tijd berekend op basis van manuele ingangen en wachttijden, door NTP of met een RTC-module.Vandaag willen we u voorstellen aan een nieuwe mogelijkheid van "time-wining" via DCF77.

De DCF77 zender:

In Mainflingen bij Frankfurt am Main is er een lange golf zender voor 77,5kHz.Deze zender stuurt de huidige tijd één keer per minuut met 50.000W.

Deze zender en het signaal worden DCF77 genoemd.De naam DCF77 is het roepnaam dat aan de zender is toegekend voor internationale identificatie.

Met een bijbehorende ontvangstmodule (bv. pollen.de 80054(b) het signaal kan worden ontvangen en gedecodeerd binnen een straal van tot 2000km rond mainflings.

Voor informatie worden in andere landen andere tijdsignaalstations gebruikt, met verschillende frequenties:

Oproep Locatie Frequenties
Bèta. Rusland 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 Canada, Ottawa 3330 MHz, 7850 MHz, 14670 MHz
DCF77 Duitsland, Leipzig 77,5 kHz
IBF Italië, Turijn 5 MHz
JY Japan, Berg 40 kHz
JY Japan, berg Hagane 60 kHz
MIKES Finland, Espoo 25 MHz
MKB Verenigd Koninkrijk, Anthorn 60 kHz
RBU Rusland, Taldom 66,66 kHz
BT Rusland, Irkutsk 50 kHz
RWM Rusland, Moskou 4996 MHz, 9996 MHz, 14996 MHz
TDF. Frankrijk, Allouis 162 kHz
WWW Verenigde Staten, Dallas 2,5 MHz, 5 MHz, 10 MHz, 15 MHz, 20 MHz
WWVB Verenigde Staten, Dallas 60 kHz
WWW Verenigde Staten, San Francisco 2,5 MHz, 5 MHz, 10 MHz, 15 MHz
YVTO Venezuela, Caracas 5 MHz

 

Structuur van het DCF77-signaal:

De DCF77 zender stuurt meer informatie over 60 minuten.

De informatie is gecodeerd in seconden.Een hoge puls van 100ms (900ms LOW) betekent een 0 en een hoge puls van 200ms (800ms LOW) betekent a 1.Deze "binaire" codering kan dan worden herberekend in datum en tijd, naast MEZ/MEZ en weersgegevens.

59 bits worden overgedragen met de volgende betekenis:

Beetje Betekenis Waarde
0 Nieuwe minuut starten (altijd 0)
1 versleuteld
WeerName
2
3
4
5
6
7
8
9
10
11
12
13
14
15 Rufbit.
16 conversie MEZ/MESZ
17 VLEES
18 MEZ
19 Wisselen
20 Start tijdinformatie (altijd 1)
21 Notulen 1
22 2
23 4
24 8
25 10
26 20
27 40
28 Minute pariteit
29 Uur 1
30 2
31 4
32 8
33 10
34 20
35 Paritaire tijd
36 Datum dag 1
37 2
38 4
39 8
40 10
41 20
42 Wekelijks 1
43 2
44 4
45 Datum van de maand 1
46 2
47 4
48 8
49 10
50 Datum Jaar 1
51 2
52 4
53 8
54 10
55 20
56 40
57 80
58 Datum gelijkheid

 

Op basis van deze informatie kunnen we een Arduino schets maken:

We verbinden onze DCF77 ontvanger met Pin 2 van de Arduino.

Arduino-Sketch.

35; definieer STATUS PIN BUILTIN LED
35; definieer DCF PIN 2
 
int HOGE start = 0;
int HOGE EIND = 0;
int HOGE TIJD = 0;
int Laag begin = 0;
int LOW einde = 0;
int Lage tijd = 0;
 
Bool. Signaal = Vals;
Bool. Nieuw = Vals;
int BIT = -1;
int TIJD[65];
int Tijdstip van het uur;
int Tijdstip van minuten;
int Tijd tot dag;
int TIJD/MAAND;
int TIJD VAN JAAR;
int TIJD Weekend;
int PAR STUDE;
int PAR MINUTE;
int PAR BEGIN;
 
Leeg setup() {   Serie.start(115200);   PinMode(DCF PIN, INPUT);   PinMode(STATUS PIN, UITVOER);   Serie.Afdrukken(Synchronisatie);
}
 
Leeg ren() {   indien (BIT > 60) {Nieuw = Vals;}   int DCF SIGNAAL = digitalileComment(DCF PIN);      indien (DCF SIGNAAL == HOGE && Signaal == Vals) {     Signaal = waar;      HOGE start = millis();      LOW einde = HOGE start;       Lage tijd = LOW einde - Laag begin;           indien (Nieuw == waar) {       PrintDescription(BIT);       Serial.print("Bit");        serie.print (BIT);        »Serial.print (");        TIJD[BIT] = (BIT tijd(Lage tijd));       Serie.print (TIJD[BIT]);       Serial.println ();     }     sm {       Serie.print(".");     }   }     indien (DCF SIGNAAL == LOW && Signaal == waar) {     Signaal = Vals;      HOGE EIND = millis();       Laag begin = HOGE EIND;      HOGE TIJD = HOGE EIND - HOGE start;        NEUMINUTE(Lage tijd);   }
}
 
int BIT tijd (int Lage tijd) {    indien (Lage tijd >= 851 && Lage tijd <= 950) {Terugkeer 0;}     indien (Lage tijd >= 750 && Lage tijd <= 850) {Terugkeer 1;}    indien (Lage tijd <= 350) {BIT-=1;Terugkeer "";}
}

Leeg NEUMINUTE (int Lage tijd) {   indien (Lage tijd >= 1700) {     BIT = 0;     Nieuw = waar;     Tijdstip van het uur = TIJD[29]*1+TIJD[30]*2+TIJD[31]*4+TIJD[32]*8+TIJD[33]*10+TIJD[34]*20;     Tijdstip van minuten = TIJD[21]*1+TIJD[22]*2+TIJD[23]*4+TIJD[24]*8+TIJD[25]*10+TIJD[26]*20+TIJD[27]*40;     PAR STUDE = TIJD[35];     PAR MINUTE = TIJD[28];     Tijd tot dag = TIJD[36]*1+TIJD[37]*2+TIJD[38]*4+TIJD[39]*8+TIJD[40]*10+TIJD[41]*20;     TIJD/MAAND = TIJD[45]*1+TIJD[46]*2+TIJD[47]*4+TIJD[48]*8+TIJD[49]*10;     TIJD VAN JAAR = 2000+TIJD[50]*1+TIJD[51]*2+TIJD[52]*4+TIJD[53]*8+TIJD[54]*10+TIJD[55]*20+TIJD[56]*40+TIJD[57]*80;     PAR BEGIN = TIJD[20];               Serie.Afdrukken();     Serie.Afdrukken("*****************************");     Serie.print ("Tijd:);     Serie.Afdrukken();     Serie.print (Tijdstip van het uur);     Serie.print (":");     Serie.print (Tijdstip van minuten);     Serie.Afdrukken();     Serie.Afdrukken();     Serie.print ("Datum:);     Serie.Afdrukken();     Serie.print (Tijd tot dag);     Serie.print (".");     Serie.print (TIJD/MAAND);     Serie.print (".");     Serie.print (TIJD VAN JAAR);     Serie.Afdrukken();     Serie.Afdrukken("*****************************");        } sm {BIT++;}
}
 
Leeg PrintDescription(int BitNumberName) {   schakelaar (BitNumberName) {     geval  0: Serie.Afdrukken("n35; START MINUTE (IMMER 0)"); breuk;     geval  1: Serie.Afdrukken("\35; JURIDISCHE GEGEVENS"); breuk;     geval 15: Serie.Afdrukken("\35; RUFBIT"); breuk;     geval 16: Serie.Afdrukken("n35; MEZ/MEsz"); breuk;     geval 17: Serie.Afdrukken("n35; MESZ"); breuk;     geval 18: Serie.Afdrukken("\35; MEZ"); breuk;     geval 19: Serie.Afdrukken("\35; KORT-TERM"); breuk;     geval 20: Serie.Afdrukken("n35; INLEIDING TIME INFORMATIE (IMMER 1)"); breuk;     geval 21: Serie.Afdrukken("n35;MINUTEN"); breuk;     geval 28: Serie.Afdrukken("n35; MINUTE PARITATE"); breuk;     geval 29: Serie.Afdrukken("\35; STUDIES");breuk;     geval 35: Serie.Afdrukken("n35; PARITATE STUDIE"); breuk;     geval 36: Serie.Afdrukken("n35;TAG"); breuk;     geval 42: Serie.Afdrukken("\35; Weekend"); breuk;     geval 45: Serie.Afdrukken("\35; MONTH"); breuk;     geval 50: Serie.Afdrukken("n35;JAAR"); breuk;     geval 58: Serie.Afdrukken("n35;PARITATDATUM"); breuk;   }
}

Als uitvoer in de Serial Monitor krijgen we nu de bitsequentie en de berekende tijd.

 

Nu kunt u ook DCF77 gebruiken voor uw projecten.Veel plezier.

Für arduinoGrundlagen software

11 Kommentare

Joschua

Joschua

Danke für den Tollen Code.
Ich hatte anfangs das Problem das bei mir keine DCF77 Library funktioniert hatte.
Aber mit diesem Code hat fast alles problemlos funktioniert.
Das einzige was ich ändern musste waren die folgenden werte. (Bereits geändert)
if (LOW_Zeit >= 821 && LOW_Zeit <= 950) {
return 0;
}
if (LOW_Zeit >= 750 && LOW_Zeit <= 820) {
return 1;
}
if (LOW_Zeit <= 350) {
BIT -= 1;
return "";
}

Bei diesen werten sollte man einfach ausprobieren bis es bei einem passt.

Max

Max

Ich nochmal. Schade das du die Parity-Bits in deinem Code zwar liest gar nicht verwendest. Ich habe das NEUEMINUTE etwas abgeändert, nun checkt es die 3 Parität-bits, baut noch Hürden für den Wertebereich mit ein (z.B. keine Minute über 59 erlaubt) und für das erfüllen des DCF_stable bit muss noch 3x das selbe Ergebnis hintereinander empfangen werden (ohne Minute, die kann mit dem DCF_minute bit schon vorher verwendet werden):

void NEUMINUTE (int LOW_Zeit) {
int temp_min=0; //save bit count of minute part of ZEIT
int temp_hour=0;//save bit count of hour part of ZEIT
int temp_year=0;//save bit count of year part of ZEIT

if (LOW_Zeit >= 1700) { BIT = 0; ZEIT_STUNDE = ZEIT29 * 1 + ZEIT30 * 2 + ZEIT31 * 4 + ZEIT32 * 8 + ZEIT33 * 10 + ZEIT34 * 20; ZEIT_MINUTE = ZEIT21 * 1 + ZEIT22 * 2 + ZEIT23 * 4 + ZEIT24 * 8 + ZEIT25 * 10 + ZEIT26 * 20 + ZEIT27 * 40; PAR_STUNDE = ZEIT35; PAR_MINUTE = ZEIT28; ZEIT_WOCHENTAG = ZEIT42 * 1 + ZEIT43 * 2 + ZEIT44 * 4; ZEIT_TAG = ZEIT36 * 1 + ZEIT37 * 2 + ZEIT38 * 4 + ZEIT39 * 8 + ZEIT40 * 10 + ZEIT41 * 20; ZEIT_MONAT = ZEIT45 * 1 + ZEIT46 * 2 + ZEIT47 * 4 + ZEIT48 * 8 + ZEIT49 * 10; ZEIT_JAHR = 2000 + ZEIT50 * 1 + ZEIT51 * 2 + ZEIT52 * 4 + ZEIT53 * 8 + ZEIT54 * 10 + ZEIT55 * 20 + ZEIT56 * 40 + ZEIT57 * 80; PAR_BEGINN = ZEIT20; //DCF PAR bit is calculatet ‘even’, so we need to add 1 temp_min=ZEIT21 + ZEIT22 + ZEIT23 + ZEIT24 + ZEIT25 + ZEIT26 + ZEIT27+PAR_MINUTE+1; temp_hour=ZEIT29 + ZEIT30 + ZEIT31 + ZEIT32 + ZEIT33 + ZEIT34+PAR_STUNDE+1; temp_year=ZEIT50 + ZEIT51 + ZEIT52 + ZEIT53 + ZEIT54 + ZEIT55 + ZEIT56 + ZEIT57+PAR_BEGINN+1; //bitread only reads one specific bit – since we fiddeld with the temp value, even/odd decides if its valid or false if ((bitRead(temp_min, 0)) && (bitRead(temp_hour, 0)) && (ZEIT_STUNDE <= 23) && (ZEIT_STUNDE >= 0) && (ZEIT_MINUTE <= 60) && (ZEIT_MINUTE >= 0) && (ZEIT_TAG <= 31) && (ZEIT_TAG >= 1) && (ZEIT_MONAT <= 12) && (ZEIT_MONAT >= 1) && (ZEIT_JAHR <= 2040) && (ZEIT_JAHR >= 2020) && (ZEIT_WOCHENTAG <= 7) && (ZEIT_WOCHENTAG >= 1 )) { DCF_minute= true; //check if there is rubbish in the signal: Store last 3 values of year, month, day, weekday. Only if all three are equal, neueMinute is set to true if ((bitRead(temp_year, 0)) && (ZEIT_JAHR_veryoldZEIT_JAHR_old) && (ZEIT_JAHR_veryoldZEIT_JAHR) && (ZEIT_MONAT_veryoldZEIT_MONAT_old) && (ZEIT_MONAT_veryoldZEIT_MONAT) && (ZEIT_TAG_veryoldZEIT_TAG_old) && (ZEIT_TAG_veryoldZEIT_TAG) && (ZEIT_WOCHENTAG_veryoldZEIT_WOCHENTAG_old) && (ZEIT_WOCHENTAG_veryoldZEIT_WOCHENTAG)&& (ZEIT_STUNDE_veryoldZEIT_STUNDE_old) && (ZEIT_STUNDE_veryoldZEIT_STUNDE)) { DCF_stable = true; } else { DCF_stable = false; } } else { DCF_minute_hook = false; } ZEIT_JAHR_veryold=ZEIT_JAHR_old; ZEIT_JAHR_old=ZEIT_JAHR; ZEIT_MONAT_veryold=ZEIT_MONAT_old; ZEIT_MONAT_old=ZEIT_MONAT; ZEIT_TAG_veryold=ZEIT_TAG_old; ZEIT_TAG_old=ZEIT_TAG; ZEIT_WOCHENTAG_veryold=ZEIT_WOCHENTAG_old; ZEIT_WOCHENTAG_old=ZEIT_WOCHENTAG; ZEIT_STUNDE_veryold=ZEIT_STUNDE_old; ZEIT_STUNDE_old=ZEIT_STUNDE; } else { BIT++; }

}

Max

Max

Vielen Dank fr den tollen Code, der ist wirklich leicht nachzuvollziehen und gut in das eigene Projekt zu intregrieren. Ich werkle noch an einer Fehlerkorrektur um die ganzen bit-Kipper raus zu bekommen, aber es zeigt schonmal zu 70% aller Fälle eine genaue Zeit an :)

Uli G.

Uli G.

Hallo ich würde gerne den ESP8266 benutzen.
wenn ich den Anruino ins Board wähle, wird das Übersetzen und Kompilieren abgeschlossen.
Benutze ich aber im Board den ESP8266 bekomme ich an der Zeile:

if (LOW_Zeit <= 350) {BIT-=1;return ""; den Fehler : invalid conversion from ‘const char*’ to ‘int’ [-fpermissive] was kann ich tun?
WO

WO

Info für Thomas:
Veriablendeklaration:
int ZEIT_SEKUNDE;
Hallo Thomas
Behelfsweise Variable “ZEIT_SEKUNDE” in funktion einfügen und dieser die Bitnummer+1 zuweisen.
Allerdings: Sekunde 59 dauert dann 2 Sekunden!
void PrintBeschreibung(int BitNummer) {
ZEIT_SEKUNDE = BitNummer+1;

Für eine exakte Sekundenanzeige 58, 59 muss der Code wohl etwas tiefergehend erweitert werden.
WO

Thomas

Thomas

funktioniert tatelos. Möchte auf Basis dieses Sketches eine NIXIE Uhr aufbauen. Mir fehlen die Sekundenanzeige. Da ich Programmieranfänger bin wäre ich dankbar wenn mir Jemand Tips geben könnte wie der Seketch zecks Sekndenanzeige zu erweitern ist.

Danke

Gunther Jordan

Gunther Jordan

Leider ist der Fehler, den Jörg Schnur letztes Jahr aufgezeigt hat immernoch drin.
Weiterhin ist eine ganz wichtige Information unterschlagen: Sekunde 59 wird nicht markiert! D.h. in dieser Sekunde wird das Sendesignal nicht moduliert, weder eine “1” noch eine “0” gesendet. DARAN erkennt der Empfänger den Beginn der vollen Minute! Und nicht etwa an der “0” am Anfang…
Die Umstellung zwischen Sommer und Normalzeit sowie die Schaltsekunde werden 1 Stunde im Voraus angezeigt, im Falle der Schaltsekunde ist die 59. Sekunde eine “0” und die 60. Sekunde wird keine Marke gesendet.

Ein Nutzer

Ein Nutzer

Der Sketch setzt bei meinem Modul (Conrad BN641138) vorraus, dass das Signal am invertierenden Ausgang abgegriffen wird.
Um dieses zu umgehen und den normalen DCF Ausgang auf Pin3 am Modul zu verwenden, kann man auch folgende Zeile:

int DCF_SIGNAL = digitalRead(DCF_PIN);

durch dieses ersetzen:

int DCF_SIGNAL_inverted = digitalRead(DCF_PIN);
int DCF_SIGNAL = (!DCF_SIGNAL_inverted);

Anschließend läuft der Sketch ohne Probleme!

Jörg Schnur

Jörg Schnur

Danke für die super Informationen. Müßte es nicht 60 Sekunden heißen im Satz “Der DCF77 Sender sendet in 60 Minuten mehrere Informationen.”?

Mertke

Mertke

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

Fred

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.

Einen Kommentar hinterlassen

Alle Kommentare werden vor der Veröffentlichung moderiert

Aanbevolen blog berichten

  1. Installeer ESP32 nu van de raad van bestuur
  2. Lüftersteuerung Raspberry Pi
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1
  4. ESP32 - das Multitalent
  5. OTA - Over the Air - ESP Programmeren via Wi-Fi