2015
HOME
Arduino - DHT11
Arduino - Rheinturmuhr mit DCF77


Zeitzeichensender ohne Bibliothek mit dem Arduino dekodieren
DCF77 - Daten im Schneckentempo
Mit etwa 1 Bit pro Sekunde laufen die Daten über den Zeitzeichensender für Mittel-Europa ein. An anderer Stelle wurde hier die Rheinturmuhr mit Funkzeit versehen. Bibliotheken machen das Leben oft einfacher, aber es kann auch reizvoll sein kurze übersichtliche Routinen zu benutzen, um damit etwas herum zu spielen.

Das Datenformat von DCF77 ist übersichtlich. Ein DCF-Modul empfängt die Langwellenfrequenz und liefert an seinem Ausgang die Impulse des Sendesignals. Dabei wird zwischen langen und kurzen Impulsen unterschieden. Ein langer Impuls entspricht einer logischen "1". In der 59. Sekunde fehlt der Impuls als Minutentrennung und als Zeichen, dass die bis dahin übertragenen Daten (59 Bit) eingetroffen sind.


Wer möchte, der kann sich über web-sdr das Signal anhören. Als Browser eignet sich Firefox, wegen des HTML5-Sounds. Es ist zu hören, was so ein DCF-Modul leisten muss, um klare Signale zur Auswertung zu erhalten - je nach Tageszeit. Die DCF77-Auswertung ist/war ebenfalls 'live' im Netz zu sehen unter www.dcf77logs. Allerdings ist das alles keine Echtzeit.

Die Dekodierung hier läuft mit dem DCF-Modul von Pollin in Echtzeit. UKW/FM-Radio mit Nachrichtensender oder ein Funkwecker laufen synchron zum Datenstrom - ohne Netz und doppelten Boden.
Eine kleine Test-Schaltung mit Piezo-Beeper und LED geben einen akustischen und optischen Eindruck des Informations-Flusses. Es geht subjektiv eine gewisse Ruhe von den Sekunden-Signalen aus - 1 bps halt.

Der Arduino erhält das Signal direkt vom Modul. Die Testschaltung ist nicht n

otwendig, sie ist nur ein Zeitgeber, der auch ohne weitere Mikrocontroller funktioniert. Mit etwas Training hört man die Bits einfach heraus.

Als globale Variablen werden die Wochentage, verschiedene Zeiten, sowie ein Pufferspeicher für 60 Bit angelegt. Aus Bequemlichkeit wird pro Bit ein Integerplatz verschwendet, das macht die Anzeigeroutine durchschaubarer. Weiterhin noch 80 Zeichen für Ausgaben, eine Zählvariable für die Sekunden und der Bitspeicher b.

Im setup() wird Pin 2 als Eingang geschaltet und Pin 13 als Ausgang. Die eingebaute LED soll ebenfalls den Sekundenimpuls anzeigen. Schließlich wird gewartet bis der Eingang eine "1" meldet. Jetzt kann die loop() übernehmen.

#define DCF77PIN 2 //Egal welcher Pin

char *Tag[] = {"Basteltag", "Montag", "Dienstag","Mittwoch",
               "Donnerstag","Freitag","Samstag","Sonntag"};
int tUp,tDown,T,ti,tp,b,i,buffer[60];
char s[80];

void setup() 
{Serial.begin(9600);
 pinMode(DCF77PIN, INPUT);
 pinMode(13, OUTPUT);
 while(!digitalRead(DCF77PIN));   //wait for __/
}

Den Zeitpunkt der aufsteigenden Flanke speichert tUp, die LED geht an. Bis zur abfallenden Flanke wird in der while-Schleife gewartet, danach enthält tDown, den Zeitpunkt der abfallenden Flanke. Mit der nächsten aufsteigenden Flanke ist die Sekunde um und dieser Zeitpunkt liegt temporär in der Variablen T. Nach den Berechnungen von Impulsdauer ti, Impulspause tp, sowie der Periodendauer T wird entschieden, ob überhaupt ein gültiger Impuls vorliegt.

Wenn die Zeit T im erwarteten Bereich von 750 ms bis 1250 ms liegt ist dies der Fall. Entsprechend kann dann das Bit gesetzt werden, wenn die Impulspause zwischen 750 ms und 850 ms lag. Entschieden wird anhand der Pausenzeit, da zumindest hier weniger Störungen bei LOW-Pegel auftraten. Wenn der Sekundenzähler i im gültigen Bereich (0 bis 59) liegt, wird das Bit an der entsprechenden Stelle abgelegt und der Sekundenzähler erhöht. Bei einer Periodendauer größer als 1500 ms, liegt vermutlich die 59. Sekunde mit dem fehlenden Impuls vor. Somit wären die Daten komplett und stehen zur Ausgabe zur Verfügung. Schließlich wird der Sekundenzähler zurückgesetzt.

void loop() 
{tUp = millis();                  //pos. Flanke
 digitalWrite(13, HIGH);          //Echo
 while(digitalRead(DCF77PIN));    //wait for \__
 tDown = millis();                //neg. Flanke
 digitalWrite(13, LOW);           //Echo
 while(!digitalRead(DCF77PIN));   //wait for __/
 T = millis();                    //Eine Periode um
 //Sekunde ist vorbei
 ti = tDown - tUp;                //Impulsdauer 100/200
 tp = T - tDown;                  //Impulspause 900/800
 T  = T - tUp;                    //Periodendauer 1000
 if(T > 750 && T < 1250)          //Bit isolieren 
 {b=(tp > 750 && tp < 850) ? 1:0; //0 oder 1 via tp
  if(i>=0 && i<60)buffer[i++]=b;  //bit ablegen
  AusgabeA();
 }
 if (T >1500)//59.-0. Sekunde --> Minute vorbei
 {AusgabeB();
  i=0;
 }
}

Die beiden Ausgaben A und B holen sich die Informationen aus dem Puffer. Die Bitanordnung ist z.B. hier beschrieben.

AusgabeA wird jede Sekunde aufgerufen und zeigt den aktuellen Speicherstand. Das ist nicht die aktuelle Uhrzeit, da die Übertragung ja gerade läuft. Das soeben dekodierte Bit wird ebenfalls ausgegeben, so könnte das Gehör trainiert werden. Bit 21 bis 27 enthalten die Minuten-Daten, AusbabeA zeigt den Wechsel sozusagen live.

Erst am Ende der Minute sind alle Daten vollständig gültig und entsprechen der richtigen Zeit.

AusgabeB zeigt zur vollen Minute den Wochentag in Klartext, sowie die funkgenauen Zeitangaben, falls wenige Störungen vorlagen.

void AusgabeA()
{ sprintf(s,
  "%01d%01d.%01d%01d.20%01d%01d - %01d%01d:%01d%01d:%02d %d",
            buffer[40]+buffer[41]*2, //Tag Zehner
            buffer[36]+buffer[37]*2+buffer[38]*4+buffer[39]*8,
            buffer[49],              //Monat Zehner
            buffer[45]+buffer[46]*2+buffer[47]*4+buffer[48]*8,
                                     //Jahr Zehner
            buffer[54]+buffer[55]*2+buffer[56]*4+buffer[57]*8,
            buffer[50]+buffer[51]*2+buffer[52]*4+buffer[53]*8,
            buffer[33]+buffer[34]*2, //Stunde Zehner
            buffer[29]+buffer[30]*2+buffer[31]*4+buffer[32]*8,
            buffer[25]+buffer[26]*2+buffer[27]*4, //Minute Zehner
            buffer[21]+buffer[22]*2+buffer[23]*4+buffer[24]*8,
            i,b); //Sekunde
  Serial.println(s);
}

void AusgabeB()
{sprintf(s,
  "\n %s, der %01d%01d.%01d%01d.20%01d%01d um %01d%01d:%01d%01d Uhr.\n",
            Tag[buffer[42]+buffer[43]*2+buffer[44]*4],
            buffer[40]+buffer[41]*2,
            buffer[36]+buffer[37]*2+buffer[38]*4+buffer[39]*8,
            buffer[49],
            buffer[45]+buffer[46]*2+buffer[47]*4+buffer[48]*8,
            buffer[54]+buffer[55]*2+buffer[56]*4+buffer[57]*8,
            buffer[50]+buffer[51]*2+buffer[52]*4+buffer[53]*8,
            buffer[33]+buffer[34]*2,
            buffer[29]+buffer[30]*2+buffer[31]*4+buffer[32]*8,
            buffer[25]+buffer[26]*2+buffer[27]*4,
            buffer[21]+buffer[22]*2+buffer[23]*4+buffer[24]*8);
 Serial.println(s);
}

Der Gesamtsketch ist hier abrufbar.

Auf Fehlerabfragen wird in der Dekodierung weitgehend verzichtet, um den Quelltext möglichst kurz zu halten. Es aber auch werden Prüfbits übertragen, die wie die Nutzdaten im Puffer liegen und entsprechend auswertbar sind. Eine Echtzeitdarstellung erfordert zwei Puffer und lässt sich aus obigen Zeilen ableiten. Alles zusammen bekommt dann Dimensionen, die einer Bibliothek nicht unähnlich sind, die es aber schon mehrfach gibt ...

Einige weitere Varianten können bei Interesse hier und hier abgeholt werden.


Weitere Software
.
Startseite Bücher Software Digital RTV Musik Kontakt

Für Inhalt und weitere Verzweigung externer Links sind die Betreiber der dortigen Seiten verantwortlich - H.-J. Berndt