DCF77 - einfach erklärt

Das DCF77-Zeitsignal ist nicht kompliziert, leicht zu entschlüsseln und wenn man einen fertigen Empfänger verwendet auch elektronisch für jeden Anfänger zu handhaben. Diese Empfänger haben quasi alle Elektronikhändler für unter 10€ im Angebot, sie funktionieren alle ähnlich und liefern am Ausgang des Empfängerschaltkreises fertig aufbereitete und TTL-kompatible Digitalimpulse, die den aufmodulierten Zeitimpulsen des Funksignals entsprechen. Man muß also keinerlei Schwingkreise selbst zu bauen und benötigt keinerlei HF-Kenntnisse.

Meistens findet man aber zur Erklärung des Signals nur einen Link auf eine "
Zeitscheibe", mit der nicht jeder auf Anhieb was anfangen kann.
Deshalb nachfolgend der Versuch einer möglichst simplen Erklärung was das bedeutet, wie man es auswertet und welche Probleme häufig auftreten.

Wie wertet man diese Impulse aus:

Empfängt das Antennenmodul ein DCF77-Signal liefert es Ausgang genau jede Sekunde ein Impuls, der zwischen 100ms und 200ms lang ist. Der kürzere 100ms-Impuls entspricht einer logischen 0, der 200ms-Impuls entspricht einer logischen 1. Startet man also bei der postiven Flanke eines Impulses einen Timer, kann dieser den Signalzustand nach 150ms direkt in eine Variable speichern, die dann entweder 0 oder 1 ist und damit dem gesendeten Bit entspricht.

Der DCF77-Sender liefert so eine serielle Folge von 58 Bits, die immer zu jeder vollen Minute neu startet und sich jede Minute wiederholt.
Bis man ein komplettes Datenpaket empfangen hat vergehen also im ungünstigsten Fall fast 2 Minuten, da die erste Minute nach dem Einschalten ja nicht vollständig empfangen wurde.

Wie erkennt man den Beginn eines Datenpaketes?

Ganz einfach: daß 59ste Datenbit fehlt! Während man also zwischen beliebigen Datenbits immer nur eine Pause < 1 Sekunde hat, ist die Pause nach dem letzten/vor dem ersten Bit > 1 Sekunde, sogar mindestens 1,8 Sekunden lang.
Um den Datenpaketanfang herauszufinden kann man den Timer, der nach 150ms den Bitzustand ermittelt, einfach weiterzählen lassen. Mitten in Datenpaketen wird dieser spätesten alle Sekunde zurückgesetzt und kann keine Werte größer 900ms annehmen. Direkt vor Beginn eines neuen Datenpaketes zählt dieser jedoch aufgrund des fehlenden 59sten Bits bis zu 1800ms hoch.
Hat der Zählerstand also z.B. 1500ms überschritten kann man einen Bit-Zähler zurücksetzen und weiß, daß das nächste empfangene Bit das Bit Nr.1 eines neuen Paketes ist und daß dann genau eine neue Minute beginnt. Diesen Zeitpunkt werde ich im Folgenden als Synchronisationspunkt bezeichnen.

Hinweis: Alle empfangenen Zeitinfomationen beziehen sich auf den Beginn der folgenden Minute!
Alle eingelesenen Zeiten sollten also erstmal nur in temporäre Variablen geschrieben erst zum Synchronisationspunkt übertragen/ausgegeben werden.
Bascom enthält z.B. vorgefertigte DCF77-Routinen und ein Beispielprogramm, das einem alle Einzeldaten direkt nach Empfang, also immer zu früh ausgeben - darum die Daten der richtigen Minute zuzuordnen muß man sich selber kümmern, auf diese Problematik wird meines Wissens in der Dokumentation aber auch nicht hingewiesen!


Wie finde ich die Zeitinfomationen aus dem Datenpaket heraus?

Hierbei kann jetzt die "
Zeitscheibe" behilflich sein, die einem die Bedeutung der Bits veranschaulichen soll. Die wesentlichen Daten habe ich nachfolgend mal zusammengefasst:

Die Sekunde gibt es im Protokoll garnicht - wie auch, wenn ein Datenpaket eine knappe Minute braucht... Um die Sekunden mitzuzählen setzt man einfach eine Sekundenvariable im Synchronisationspunkt auf 0 und zählt diese bei jedem weiteren, eintreffenden Impuls hoch. Praktisch: den Sekundenwert kann man damit später gleich als Index/Pointer für die Bits des Datenpaketes benutzen! Wegen des fehlenden, 59sten-Bits springt die Uhr dann natürlich von Sekunde 58 auf 0 um. Das Problem könnte man beheben, indem der Timer die Sekundenvariable bei Zählwert 1000ms ebenfalls um eins hochzählt. Allerdings ist aus später erklärten Gründen dringend zu einer separaten Softclock zu raten und dann ist die Sekundenkorrektur überflüssig.

Die Minute findet man in den Bits 21 bis 27 in BCD-Codierung. D.h. die ersten 4 Bit (Nibble) zeigen die Einerstelle an, die oberen Bits geben die Zehnerstelle als Binärzahl an. Wenn man sich damit auskennt ist es simpel die Bits einfacheiner Variablen zuzuordnen, die man durch eine Standardfunktion von BCD in andere Zahlenfomate umwandeln kann. Um es auch für Anfänger verständlich zu halten will ich das aber einfach als Additionsverfahren erklären:

Zu jedem Bit gehören Zahlenwerte, die man einfach aufaddiert, wenn das entsprechende Bit = 1 ist. Also einfach eine temporäre Minutenvariable vorher irgendwann auf 0 setzen (z.B. bei Bit 20, dem Startbit) und dann einfach nach Liste bis Bit 27 die Einzelwerte aufaddieren.

Minute = 0
Bit 21: Minute + 1
Bit 22: Minute + 2
Bit 23: Minute + 4
Bit 24: Minute + 8
Bit 25: Minute + 10
Bit 26: Minute + 20
Bit 27: Minute + 40

Die Stunde, den Kalendertag, den Monat und das Jahrt findet man in den folgenden Bits und diese werden genauso berechnet wie der Minutenwert. Stunde und Kalendertag haben Maximalwerte von 24 bzw. 31, sind damit immer < 40 (24 und 31) und ist deshalb nur 6 Bits lang, und benötigen nur jeweils 6 Bits, der Monat mit 12 als Maximalwert kommt sogar mit nur 5 Bits aus. Die Jahresangabe stellt nur die letzten beiden Ziffern des aktullen Jahrhunderts, also z.B. eine 09 für 2009. Da innerhalb eines Jahrhunderts Werte bis 99 möglich sind ist die Jahresangabe um ein 8tes Bit erweitert, daß dem Dezimalwert 80 entspricht:

Stunde = 0
Bit 29: Stunde + 1
Bit 30: Stunde + 2
Bit 31: Stunde + 4
Bit 32: Stunde + 8
Bit 33: Stunde + 10
Bit 34: Stunde + 20

Tag = 0
Bit 36: Tag + 1
Bit 37: Tag + 2
Bit 38: Tag + 4
Bit 39: Tag + 8
Bit 40: Tag + 10
Bit 41: Tag + 20

Monat = 0
Bit 45: Monat + 1
Bit 46: Monat + 2
Bit 47: Monat + 4
Bit 48: Monat + 8
Bit 49: Monat + 10

Jahr = 0
Bit 51: Jahr + 1
Bit 52: Jahr + 2
Bit 53: Jahr + 4
Bit 54: Jahr + 8
Bit 55: Jahr + 10
Bit 56: Jahr + 20
Bit 57: Jahr + 40
Bit 58: Jahr + 80


Weitere Daten:

Paritybits: Am Ende des Minutenpaketes (Bit 28) des Stundenpakets (Bit 35) und des gesamten Datums (Bit 58) findet man Paritybits zur Fehlerprüfung des letzten Blocks. Wie man Paritybits prüft findet man überall im Netz, für mich hat es sich aber als zu unsicheres Kriterium zum Prüfen der Übertragung erwiesen, weshalb ich nicht näher darauf eingehe.

Wochentag: der Wochentag, beginnend mit 1 für Montag ist zwischen dem Kalendertag und dem Monat in den Bits 42; 43; 44 nach bekanntem Schema enthalten.

Sommerzeit: Ist Bit 15 = 1 erfolgt am Ende der aktuellen Stunde eine Zeitumstellung. Bit 17 = 0 gibt Normalzeit an, Bit 17 = 1 gibt Sommerzeit an. Bit 18 ist einfach invertiert zu Bit 17.

Schaltsekunde: Ist Bit 19 = 1 wird am Ende der aktuellen Stunde eine Schaltsekunde eingefügt - ist nur alle paar Jahre der Fall.

Sonstiges: In den Bits 1-14 können Katastrohenwarnungen enthalten sein, oder Wetterdaten. Um die Wetterdaten zu entschlüsseln muß man aber eine Lizenz besitzen. Das Bit 15 ist ein "Rufbit" womit der DCF77-Sender bei Problemen Techniker alarmiert, die ihn reparieren. Diese Bits vor Bit 20 werden in den meisten Anwendungen ignoriert. Bit0 und Bit20 sind Startbits, Bit 0 ist immer 0 und Bit 20 ist immer 1



Wie ein µC-Programm einer DCF77-Uhr aufgebaut sein könnte:

- man programmiert sich einen frei laufenden Timer, der z.B. alle 10ms eine eigene Subroutine ausführt

Jetzt programmiert man sich zunächst eine frei laufende Uhr (Softclock) in den Timer, die die Anzahl der Timeraufrufe aufaddiert, und ist diese = 100 eine Skundenvariable inkrementiert (um 1 hochzählt), bei 60 Sekunden eine Minutenvariable incrementiert usw. Die Zeit dieser Uhr ist die einzig relevante und nur diese wird später angezeigt/ausgegeben. Auf die Variablen dieser Uhr wird nachfolgend nicht weiter eingegangen und alle Variablennamen beziehen sich auf Zwischenvariablen, die mit der Softclock nichts zu tun haben und nicht verwechselt werden dürfen.

- nun schließt man den Antennenimpuls an einen Hardwareinterrupteingang an (Pullup einschalten!) und definiert sich eine entsprechende Subroutine, die bei der ersten Flanke eines eintreffenden Impulses ausgeführt wird. In dieser Routine inkrementiert man eine Sekundenvariable und setzt eine Hundersttelsekundenvariable auf 0 - mehr nicht.

Diese Hundertstelsekundenvariable inkrementiert man ebenfalls bei jedem Timeraufruf und prüft sie dort am einfachsten mit If-Abfragen auf folgende Zustände:

= 15: bedeutet 150ms des Eingangsimpulses sind vergangen und der Signalzustand des Eingangssignalpins kann als logische 0 oder 1 gelesen werden. Welches Bit der oben angegebenen Bittabelle man gerade am Wickel hat sagt einem die Sekundenvariable, die bei jedem Impuls automatisch inkrementiert wurde. Je nach Bedeutung des Bits addiert man nun die angegbenen Listenwerte zu den entsprechende Zeitvariablen für Minute, Stunde, Tag usw. hinzu, oder schreibt den Bitzustand einfach in enstprechende BCD-Variablen (wenn man das versteht).

> 1500: bedeutet daß bei der nächsten Signalflanke eine neue Minute /ein neues Datenpaket beginnt, dies also ein Synchronisationspunkt ist und die Sekundenvariable auf 0 gesetzt werden muß.

Das war es prinzipiell: gibt man jetzt die DCF77-Zeitvariablen z.B. mit jedem Sekundentakt (Impuls) auf dem Bildschirm aus, dann sieht man die emfangenen "Rohwerte" und sieht, wie sich z.B. der Minutenwert bei jeder Sekunde zwischen 21 und 27 neu berechnet, danach aber konstant bleibt während andere Variablen gerade geändert werden. Theoretisch könnten diese Zwischenwerte schon beim jeweils nächsten Synchronisationspunkt (also am Ende eines kompletten Datenpaketes) in die Softclock übernommen werden - wenn da nicht die vielen Empfangsfehler wären... Worauf man die DCF77-Zeiten prüfen sollte bevor man sie in die Softclock übernimmt folgt im Asnchluss:


Übertragungsfehler und Kausalitätsprüfung:

Impulszählung: Man kann zum Synchronistationszeitpunkt einfach gucken, ob seit dem letzten tatsächlich 58 Impulse eingetroffen sind. Mancher wird sich wundern wie häufig das nicht so ist!
Pakete, bei denen das nicht stimmt könnte man prinzipiell als falsch verwerfen, wenn man allerdings nur an der Uhrzeit und nicht am Datum interessiert ist verwirft man damit auch Pakete bei denen Minuten-/Stundeninfomationen noch korrekt empfangen wurden, sich aber beim Datum ein Fehler eingeschlichen hat.

Parityüberprüfung: Das DCF77-Zeitsignal liefert selbst 3 Paritybits mit, die man zur Prüfung der empfangenen Daten benutzen kann. Allerdings kann ein Paritybit immer nur 2 Zustände besitzen 0 oder 1 und ist demnach bei Übertragungsfehlern in ca. 50% der Fälle auch zufällig richtig. D.h. bei Prüfung aller 3 Paritybits, daß eines von 8 fehlerhaften Datenpaketen trotzdem immernoch zufällig als korrekt anzeigt wird - nicht sehr sicher! Oft interessiert nur die Uhrzeit, man begnügt sich mit den beiden Paritybits von Minuten- und Stundenblock und verzichtet auf Prüfung des Datumsblocks - und hat schon eine Fehlerwahrscheinlichkeit von 1:4!

Man könnte die Sicherheit etwas verbessern, indem man die Parity mehrerer Datenpakete in Folge prüft und nur wenn mehrere korrekt waren von richtigen Daten ausgeht. Allerdings ist jedes einzelne ist mit einer Wahrscheinlichkeit von 1:8 falsch, d.h. bei x Datenpaketen steigt die Fehlersicherheit auch nur in einfacher Ordnung um Faktor x.
Die Parity-Prüfung wird in Datenübertragungssystemen deshalb nur als einfache Erstkontrolle verwendet, um eindeutig falsche Datenpakete sofort herauszufiltern. Sie ist aber ungenügend sicher um zu beweisen, daß ein Datenpaket wirklich korrekt war. In der EDV benutzt man deshalb zur Erhöhung der Sicherheit andere Varianten wie Checksummenprüfung u.a. die mögl. viele Daten einbeziehen. Das DCF77-Signal liefert solche Fehlerprüfungsmöglichkeiten nicht - braucht es aber auch nicht, weil sich die Möglichkeit etwas viel besseren bietet:

Kausalitätsprüfung: Völlig anders als bei den meisten anderen Datenübertragungssystemen bietet ein stetig gesendetes Zeitsignal einen erheblichen Vorteil: hat man ein Paket gelesen weiß man schon im voraus, wie das nächste aussehen müßte! Eines steht unter normalen Raum/Zeit-Bedingungen nämlich fest: nach einer Minute ist man ca. eine Minute älter!
D.h. der Minutenwert jedes Datenpaketes muß innerhalb einer Stunde immer genau um 1 größer sein als beim letzten Datenpaket. Die Wahrscheinlichkeit, daß ein fehlerhaftes Datenpaket damit zufällig genau um 1 größer ist beschränkt sich damit nicht etwa nur auf 1:60 - sondern beträgt sogar 1:100, da bei Fehlern beide Stellen der Sekunde von 0-9 ergeben könnten. Diese Prüfung liefert beim Stundenumschlag dafür natürlich auch sicher immer einen Fehler, was ist bei Verwendung einer Softclock quasi egal ist.

Man kann die Fehlersicherheit noch erhöhen, indem man nicht nur die Minuten einer Stunde berücksichtigt, sondern die Stunden hinzunimmt. D.h. man berechnet zunächst wieviele Minuten der Tag schon alt ist: Stunden x 60 + Minuten. Da hier alle 4 Digits stimmen müssen, ergibt sich eine Fehlerwahrscheinlichkeit von 1:10000 und das ist schon brauchbar!
Wenn man das Datum auswerten will empfiehlt es sich dieses auch hinzuzuziehen und einfach alle Dezimalstellen von Jahr, Monat, Tag, Stunde und Minute hintereinander zu schreiben - auch dieser Wert muß bei jedem Folgenden Datenpaket um genau 1 größer sein als beim letzten Paket und das liefert lediglich beim Stunden-/Tages-/Monats-/Jahreswechsel prinzipbedingte Fehler, dafür aber extrem große Sicherheit.

Kommt es einem nicht darauf an, daß sich die Uhr unbedingt schnell synchronisiert kann man natürlich auch über 3, 4 oder nochmehr Minuten hinweg prüfen, ob alle Datenpakete jeweils korrekt eine Minute mehr als das letzte angezeigt haben und die Fehlerwahrscheinlichkeit sinkt in Potenz der Anzahl! D.h. die Wahrscheinlichkeit, daß 3 aufeinanderfolgende, falsche Tagesminutenwerte genau so emfangen wurden, daß die Werte zufällig genau aufeinaderfolgen beträgt schon ohne Berücksichtigung des Datums 1:100000000...
Ausreichend, würde ich sagen und gut genug um sich die Paritätsprüfung und Impulszählung gleich ganz zu sparen!

Aber man muß aufpassen: treibt man es zu weit, synchronisiert sich die Uhr nach dem Einschalten über mehrere Stunden hinweg oder gleich garnicht mehr, weil zu häufig ein falsches Datenpaket dazwischenflutscht. Nach meinen einführenden Behauptungen, daß of mal 9 von 10 Datenpaketen unbrauchbar sind, dürfte eine solche Variante garnicht mehr synchronisieren. Allerdings habe ich bei praktischen Tests festgestellt, daß die Störeinflüsse über den Tag hinweg stark variieren, daß zeitweise extrem häufig Fehler auftreten, während gelegentlich gleich 10-20 Pakete korrekt empfangen werden. Das hängt möglicherweise mit der zufälligen, zeitgleichen Reduzierung äußerer Störquellen zusammen, ermöglicht aber auch bei erhöhten Anforderungen eine gelegentliche Synchronisation der Uhr.

Ich habe es mal mit einer 5-Minuten-Folgenprüfung ausgetestet und diese Prüfung hat die Uhr gerade 2-3mal in 24h bestanden, entsprechend würde sich die Softclock nach dem Einschalten z.B. erst nach 8-12 Stunden synchronisieren! Wieviel sicherheit für euch sinnvoll erscheint bleibt Euch überlassen und hängt auch von der Empfangsqualität in Eurer Gegend ab. Rein rechnerisch sollten 2-3 sinnvoll aufeinanderfolgende Zeitwerte aber völlig ausreichen, um das zuletzt empfangene als definitiv korrekt zu verarbeiten und die Softclock danach zu stellen.

Die häufigsten Fehler, wenn das Programm nicht funktioniert:




Diese Datei wird momentan noch bearbeitet und sollte täglich etwas "fertiger" werden...