DCF77 DCF1 Arduino Pollin : Und die Zeit tickt

Der sendet immer und hört nicht auf, das Signal ist also immer da, nur dessen Stärke ändert sich. Pro Sekunde übermittelt der Sender uns ein Bit, das Bit kann entweder 0 oder 1 sein.
Will der Sender uns eine 0 mitteilen, erhöht er am Anfang einer Sekunde die Sendeleistung 100ms lang, will er uns eine 1 mitteilen, erhöht er die Sendeleistung am Anfang einer Sekunde (1000ms) für 200ms.

Ein neuer Signalzyklus beginnt immer am Anfang einer neuen Minute.
Es werden also immer 60 Bits übertragen, von 0 bis 59.
In diesen Bits stecken die Informationen die wir brauchen um unsere Uhr zu stellen und noch ein paar andere.
Mit Hilfe des DCF77-Empfangsmodul können wir die Signalstärken-Änderung für uns digital lesbar machen.
Will uns das Modul z.B. mitteilen das ein Bit den Wert 1 hat, ist unser Pin am Arduino 200ms auf HIGH, bei einer 0 ist er nur 100ms auf HIGH.
Da die Übertragung eines Bits immer 1000ms dauert ergibt sich folgendes :

Sender übermittelt eine 1 : PIN 200ms HIGH, 800ms LOW
Sender übermittelt eine 0 : PIN 100ms HIGH, 900ms LOW

Eine Sekunde ist immer dann zu Ende wenn ein Wechsel zwischen LOW und HIGH stattfindet. Die Grafik veranschaulicht das evtl. besser :

DCF77 Signal

Das folgende Programm veranschaulicht wie der Start einer neuen Minute zu finden ist :

Ich habe es extra genau so geschrieben damit auch ein Anfänger nachvollziehen kann was es macht ich erwähne das nur für die Nerds, die nun auf den Stuhl klettern und mit den Armen zappeln.

/* DCFPulse
* Ralf Bohnen, 2013
* This example code is in the public domain.
*/

#define BLINKPIN 13
#define DCF77PIN 2

int SignalHIGHStart = 0;
int SignalHIGHEnde = 0;
int SignalHIGHZeit = 0;
int SignalLOWStart = 0;
int SignalLOWEnde = 0;
int SignalLOWZeit = 0;

bool Signal = false;
bool neueMinute = false;
int bitnr = -1;

void setup() {
    Serial.begin(9600);
    pinMode(DCF77PIN, INPUT);
    pinMode(BLINKPIN, OUTPUT);
    Serial.println("Warte auf Start einer neuen Minute...");
}

void loop() {

    int pinValue = digitalRead(DCF77PIN); //Wert am PIN einlesen

    if (pinValue == HIGH && Signal == false) { //PIN ist HIGH, vorher war kein HIGH
        Signal = true;
        SignalHIGHStart = millis();
        SignalLOWEnde = SignalHIGHStart;
        SignalLOWZeit = SignalLOWEnde - SignalLOWStart;

        //DEBUG Ausgabe nach Serial
        if (neueMinute) {PrintBeschreibung(bitnr);
        Serial.print("BitNr.:"); Serial.print (bitnr);
        Serial.print (" Wert :"); Serial.print (werteBitAus(SignalHIGHZeit));
        Serial.println (" ");
        }
    } //ENDE (pinValue == HIGH && Signal == false)

    if (pinValue == LOW && Signal == true) { //PIN ist LOW vorher war HIGH
        Signal = false;
        SignalHIGHEnde = millis();
        SignalLOWStart = SignalHIGHEnde;
        SignalHIGHZeit = SignalHIGHEnde - SignalHIGHStart;

        feststellenObNeueMinute(SignalLOWZeit);
    } //ENDE (pinValue == LOW && Signal == true)

} //END LOOP

//Gebe den Wert zurück den das Bit aufgrund der HIGH Zeit-Länge haben muss
int werteBitAus (int SignalHIGHZeit) {
    //mit den Zeiten ein wenig größzügig sein, die schwanken um den Optimalwert
    if (SignalHIGHZeit >= 90 && SignalHIGHZeit <= 110) {return 0;}
    if (SignalHIGHZeit >= 190 && SignalHIGHZeit <= 210) {return 1;}
}

//Wenn LOW Zeit größer 1750ms dann neue Minute BitNummer auf 0 setzen,
//ansonsten BitNummer hochzählen
void feststellenObNeueMinute (int SignalLOWZeit) {
    //auch hier ein wenig Luft lassen bei der Zeit.
    if (SignalLOWZeit >= 1750) {
        bitnr = 0; neueMinute = true;
        } else {
            bitnr++; }
    }

void PrintBeschreibung(int BitNummer) {
switch (BitNummer) {
    case 0: Serial.println("\n### S T A R T N E U E M I N U T E"); break;
    case 1: Serial.println("\n### CODIERTE WETTERDATEN"); break;
    case 15: Serial.println("\n### RUFBIT RESERVEANTENNE"); break;
    case 16: Serial.println("\n### ANKUENDIGUNG UMSTELLUNG MEZ/MESZ"); break;
    case 17: Serial.println("\n### 0 = MEZ | 1 = MESZ"); break;
    case 18: Serial.println("\n### 0 = MESZ | 1 = MEZ"); break;
    case 19: Serial.println("\n### 1 = SCHALTSEKUNDE AM ENDE DER STUNDE"); break;
    case 20: Serial.println("\n### BEGIN ZEITINFORMATION (IMMER 1)"); break;
    case 21: Serial.println("\n### BEGIN MINUTEN"); break;
    case 28: Serial.println("\n### PARITAET MINUTE"); break;
    case 29: Serial.println("\n### BEGIN STUNDE");break;
    case 35: Serial.println("\n### PARITAET STUNDE"); break;
    case 36: Serial.println("\n### BEGIN KALENDERTAG"); break;
    case 42: Serial.println("\n### BEGIN WOCHENTAG"); break;
    case 45: Serial.println("\n### BEGIN MONATSNUMMER"); break;
    case 50: Serial.println("\n### BEGIN JAHR"); break;
    case 58: Serial.println("\n### PARITAET DATUM"); break;
    }
}

Zusammen mit dem o.a. Programm und der Tabellen auf  der Wiki Seite könnt Ihr schon die Zeit von Hand ausrechnen oder einfach weiter lesen, denn auf der nächsten Seite schreiben wir ein Programm um die Zeit anzuzeigen, dort klären wir dann auch wie man mit Fehlern in der Übertragung zurecht kommt.

Als Grundlage für unser Programm reden wir kurz noch über die Sicherheit des Signal, damit meine ich nicht Sicherheit im Sinne von Hacker Angriffen, sondern die Korrektheit des empfangenen Signals.

Dazu ein kleiner Auszug aus der Bittabelle, wir sehen Bitnummer 20 bis 28, dieser Block ist für die Übertragung der Minute zuständig:

Bit Nr. Bedeutung
21 Minute
(Einer)
1 min
22 2 min
23 4 min
24 8 min
25 Minute
(Zehner
10 min
26 20 min
27 40 min
28 Parität Bit in diesem Fall = 1

Die grün markierten Bitnummern waren HIGH, nehmen wir an es war die elfte Stunde, dann wären es nun genau : 11:32:00 Uhr

Sekunden werde nicht übertragen, die sind mit Ausnahme einer Schaltsekunde immer 0.

Parität :
Eine Arte Kontrolle der übertragenen Bits stellen Parität-Bits dar, die am Ende des Minuten, Stunde und Datumblocks übertragen werden.
Wir haben es hier mit einer „geraden“ oder auch „Even-Parität“  zu tun.
Das bedeutet :
Ist die Summe der Bits die den Wert 1 haben im Block gerade, so ist die Parität 0, ist die Summe der Bits im Block ungerade so hat das Parität-Bit den Wert 1, wie in unserem Beispiel oben.

Es gibt noch weitere Kontrollmöglichkeiten :

  • das Bitnummer 0 hat immer den Wert 0
  • die Bits 17 und 18 sind immer verschränkt, ist Bit 17 =  0, so ist Bit 18 = 1 und umgekehrt
  • Bitnummer 20 ist immer 1
  • ist die Summe der Minuten > 59 haben wir offensichtlich einen Fehler
  • usw..

Des weiteren könnt man noch auf unser Programm bezogen die HIGH, LOW Zeiten auswerten.

Auf der offiziellen Arduino Seite wird eine schöne Library vorgestellt, diese werden wir nun nutzen um die Systemzeit des Arduino mit dem DCF77 Signal zu synchronisieren.

Die Library bekommt man hier : http://thijs.elenbaas.net/downloads

Nach Installation der Library könnt Ihr folgenden Code verwenden :

/* DCF77_SerialTimeOutput
* Ralf Bohnen, 2013
* This example code is in the public domain.
*/

#include "DCF77.h"
#include "Time.h"

char time_s[9];
char date_s[11];

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

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

void setup() {
    Serial.begin(9600);
    DCF.Start();
    Serial.println("Warte auf Zeitsignal ... ");
    Serial.println("Dies kann 2 oder mehr Minuten dauern.");
}

void loop() {

    delay(1000);
    time_t DCFtime = DCF.getTime(); // Nachschauen ob eine neue DCF77 Zeit vorhanden ist
    if (DCFtime!=0)
    {
        setTime(DCFtime); //Neue Systemzeit setzen
        Serial.print("Neue Zeit erhalten : "); //Ausgabe an seriell
        Serial.print(sprintTime());
        Serial.print(" ");
        Serial.println(sprintDate());
    }
//---> hier könnte man die Ausgabe auch auf ein LCD schicken.
}

char* sprintTime() {
    snprintf(time_s,sizeof(time_s),"%.2d:%.2d:%.2d" , hour(), minute(), second());
    time_s[strlen(time_s)] = '\0';
    return time_s;
}

char* sprintDate() {
    snprintf(date_s,sizeof(date_s),"%.2d.%.2d.%.4d" , day(), month(), year());
    date_s[strlen(date_s)] = '\0';
    return date_s;
}

Ich würde mal sagen wir sind nun durch mit dem Thema DCF77.
Wie immer hoffe ich das Ihr alles wie gewünscht zum laufen gebracht habt, bis zum nächsten mal.

Das könnte dich auch interessieren …

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.