DCF-Dekodierung in C (mit PIC-Mikrocontroller, Elektronik)


zurück zu Elektronik, Homepage


4. Software

Die Aufgabe der PIC-Software besteht bei der DCF-Dekodierung aus mehreren Teilaufgaben:

  1. In kurzen Zeitabständen (ca. alle 4ms) das vom DCF-Empfangsmodul (DCF1) erzeugte Signal abtasten. Daraus entweder ein Low, ein High oder eine neue Minute ermitteln. Kann aus den Abtastungen keines dieser drei Fälle ermittelt werden, so handelt es sich um einen Telegrammfehler.
  2. Die empfangenen Low- und High-Pegel zwischenspeichern.
  3. Bei jeder neuen Minute aus den gespeicherten Werten entsprechend Tabelle die Zeit- und Datumswerte zusammensetzen und in entsprechenden Registern sichern.
  4. Das soeben ermittelte Telegramm mit dem Telegramm der vorhergehenden Minute vergleichen. Die soeben ermittelte Minute muss dabei um 1 größer als die vorhergehende Minute sein, und die soeben ermittelten Werte für die Stunde, den Tag, den Monat, das Jahr und den Wochentag müssen mit den Werten des vorhergehenden Telegramms übereinstimmen. Achtung: Bei dieser einfachen Überprüfung wird der Übergang von z. B. 13:59 auf 14:00 als falsch gewertet, da sich hier die Stunde ändert, und auch die Minute um mehr als 1. Würden hier alle möglichen Übergänge berücksichtigt, dann würde dieses Unterprogramm noch umfangreicher als es ohnehin schon ist. Durch diese Vereinfachung dauert die Synchronisierung im schlimmsten Fall nur eine Minute länger.
  5. Parallel zur DCF-Uhr eine reine Softwareuhr erzeugen. Diese Softwareuhr ist gültig, wenn keine korrekte Zeit vom DCF-Empfangsmodul empfangen wird. Mit anderen Worten. Die Softwareuhr wird ständig mit einer gültig dekodierten "DCF-Zeit" synchronisiert. Dies gilt natürlich auch für die Datumsinformationen.
nach oben

4.1. Das Dekodierverfahren

Der PIC-I/O-Eingang, an dem das DCF-Empfangsmodul (mit einer Anpass-Schaltung) angeschlossen ist, wird zyklisch (ca. alle 4 ms) vom Unterprogramm DCF_Routine abgefragt. Als Zeitbasis für den 4-ms-Takt dient der Timer-0-Interrupt. Dieser kann je nach Anwendung entweder so eingestellt werden, dass er alle 4 ms einen Interrupt auslöst, oder er wird so eingestellt dass er z. B. alle 500µs oder alle 1ms einen Interrupt erzeugt und ein Zählregister zählt die notwendige Anzahl an Interruptaufrufen bis zu einer Zeitbasis von 4 ms. Hier in dieser Dokumentation wird der Einfachheit halber die erstere Variante verwendet. Der Aufruf des Unterprogramms DCF_Routine erfolgt hier aber nicht von der ISR (Interrupt-Service-Routine), sondern vom Hauptprogramm. Die ISR setzt nur alle 4 ms ein Flag zur Kennzeichnung, dass das Hauptprogramm das Unterprogramm DCF_Routine aufrufen soll.

Die Aufgabe des Unterprogramms DCF_Routine besteht nun darin, aus dem vom DCF-Empfangsmodul empfangenen Datenstrom die Informationen LOW, HIGH und den Minutenwechsel (also das Ausbleiben der 59. Sekunde) gemäß dem im Abschnitt 2 (Grundlagen zu DCF) gewonnen Erkenntnisse zu dekodieren. Für diese Informationen befinden sich im DCF-Statusregister (cDCF_Status) entsprechende Flags. Siehe Abschnitt 4.2 (Benötigte Register, Konstanten und Portdefinition für die DCF-Dekodierung)
Ein weiteres Register (cDCF_Hilfsregister) beinhaltet den Zustand des DCF-Eingangs 4 ms vor dem Aufruf des Unterprogramms DCF_Routine. Mit Hilfe des aktuellen Zustands und des Zustands vor 4 ms kann nun erkannt werden, ob sich der Pegel am DCF-Eingang geändert hat.

Das Hauptprogramm prüft nun ständig die Flags bDCF_Neue_Sekunde (wird zusätzlich zu bDCF_Low bzw. bDCF_High gesetzt, wenn eine gültige Sekunde empfangen wurde) und bDCF_Neue_Minute, und ruft die Unterprogramme DCF_UP_Sekunde bzw. DCF_UP_Minute auf. Die Aufgabe des Unterprogramms DCF_UP_Sekunde ist es, die empfangenen Low- und High-Pegel in den Register cDCF_Telegramm1 bis cDCF_Telegramm8 zwischenzuspeichern.
Die Aufgabe des Unterprogramms DCF_UP_Minute ist etwas umfangreicher: Zunächst die Zeit und das Datum aus den in den Registern cDCF_Telegramm1 bis cDCF_Telegramm8 zwischengespeicherten Werten entsprechend Tabelle 4 zusammensetzen. Anschließend die soeben gewonnen Zeit- und Datumsinformationen mit den Zeit- und Datumsinformationen der vorhergehenden Minute vergleichen. Die Zeit- und Datumswerte der soeben empfangenen Minute sind nur dann gültig, wenn sich die Minute um maximal 1 von der vorhergehenden Minute unterscheidet, während sich die restlichen Zeit- und Datumsinformationen mit denen der vorhergehenden Minute nicht unterscheiden. Dies ist nur eine einfache Überprüfung, die aber manche richtigen Telegramme als falsch auswertet. Siehe Abschnitt 4.3 (Unterprogramme für die DCF-Dekodierung)

Parallel zur Dekodierung des DCF-Eingangs erzeugt das Unterprogramm DCF_Innere_Uhr eine reine Softwareuhr. Für diesen Zweck ist eine genaue 1-Sekunden-Zeitbasis notwendig. Diese Zeitbasis wird von der schon erwähnten Timer-0-ISR (Interrupt Service Routine) zusätzlich zur 4ms-Zeitbasis erzeugt. Auch für diese Zeitbasis wird in der ISR ein entsprechendes Flag gesetzt, und das Hauptprogramm ruft das Unterprogramm DCF_Innere_Uhr auf, wenn dieses Flag gesetzt ist. Diese zusätzliche Softwareuhr mag auf dem ersten Blick unnötig erscheinen. Es hat sich aber gezeigt, dass ein DCF-Empfang oft auch über eine längere Zeit nicht möglich ist. In diesem Fall würde die Uhr "stehen" bleiben. Diese Zeit wird mit einer zusätzlichen Softwareuhr so überbrückt, dass der Betrachter der Uhr davon nichts bemerkt.

nach oben

4.2. Benötigte Register, Konstanten und Portdefinition für die DCF-Dekodierung

Register:
Für die DCF-Dekodierung sind neben einigen internen Registern (SFR, Spezielle Funktions-Register) noch eine ganze Menge eigener Register notwendig:

cDCF_Status:
Statusregister für die DCF-Dekodierung. Dieses Register beinhaltet folgende Bits:
Zusammensetzung von cDCF_Status
cDCF_Hilfsregister:
Hilfsregister für die DCF-Dekodierung. Dieses Register beinhaltet folgende Bits:
Zusammensetzung von cDCF_Hilfsregister
cDCF_Puls, cDCF_Pause:
Zählregister zur Ermittlung der Pulsdauer bzw. Pausendauer bei der DCF-Dekodierung (Anmerkung: Bei diesen beiden Registern handelt es sich um statische Register im Unterprogramm DCF_Routine)
Puls und Pause
cDCF_Telegramm1 - cDCF_Telegramm8:
In diese Register wird das empfangene, neue DCF-Telegramm im Sekundentakt eingelesen. Beginnt eine neue Minute, so werden diese Register ausgewertet und in die entsprechenden Register kopiert, z.B. in das Register cDCF_Minute_BCD.
cDCF_Minute_BCD:
Beinhaltet die dekodierte, aktuelle Minute im BCD-Format.
cDCF_Stunde_BCD:
Beinhaltet die dekodierte, aktuelle Stunde im BCD-Format.
cDCF_Tag_BCD:
Beinhaltet den dekodierten, aktuellen Tag im BCD-Format.
cDCF_Monat_BCD:
Beinhaltet den dekodierten, aktuellen Monat im BCD-Format.
cDCF_Jahr_BCD:
Beinhaltet das dekodierte, aktuelle Jahr im BCD-Format, wobei nur die Einer- und die Zehnerstelle im DCF-Telegramm enthalten sind. Die Hunderter- und die Tausenderstelle befinden sich nicht im DCF-Telegramm.
cDCF_Wochentag:
Beinhaltet den dekodierten, aktuellen Wochentag, wobei folgende Tabelle gilt:
Wochentag
cDCF_Zusatzinfos:
Beinhaltet weitere, folgende Informationen, die im DCF-Telegramm enthalten sind:
Zusammensetzung von cDCF_Zusatzinfos
cDCF_Minute_Alt:
Beinhaltet die empfangene Minute des DCF-Telegramms, welches mit der vorangegangenen Minute empfangen wurde. Diese wird zur Überprüfung des neuen DCF-Telegramms verwendet.
cDCF_Stunde_Alt:
Beinhaltet die empfangene Stunde des DCF-Telegramms, welches mit der vorangegangenen Minute empfangen wurde. Diese wird zur Überprüfung des neuen DCF-Telegramms verwendet.
cDCF_Tag_Alt:
Beinhaltet den empfangenen Tag des DCF-Telegramms, welcher mit der vorangegangenen Minute empfangen wurde. Dieser wird zur Überprüfung des neuen DCF-Telegramms verwendet.
cDCF_Monat_Alt:
Beinhaltet den empfangenen Monat des DCF-Telegramms, welcher mit der vorangegangenen Minute empfangen wurde. Dieser wird zur Überprüfung des neuen DCF-Telegramms verwendet.
cDCF_Jahr_Alt:
Beinhaltet das empfangene Jahr des DCF-Telegramms, welches mit der vorangegangenen Minute empfangen wurde. Dieses wird zur Überprüfung des neuen DCF-Telegramms verwendet.
cDCF_Wochentag_Alt:
Beinhaltet den empfangenen Wochentag des DCF-Telegramms, welcher mit der vorangegangenen Minute empfangen wurde. Dieser wird zur Überprüfung des neuen DCF-Telegramms verwendet.
cUhr_Sekunde:
Sekundenzähler der inneren quarzgesteuerten Uhr. (Wird mit jedem gültigen DCF-dekodierten Wert synchronisiert).
cUhr_Minute:
Minutenzähler der inneren quarzgesteuerten Uhr. (Wird mit jedem gültigen DCF-dekodierten Wert synchronisiert).
cUhr_Stunde:
Stundenzähler der inneren quarzgesteuerten Uhr. (Wird mit jedem gültigen DCF-dekodierten Wert synchronisiert).
cDatum_Wochentag:
Wochentagszähler der inneren quarzgesteuerten Uhr. (Wird mit jedem gültigen DCF-dekodierten Wert synchronisiert).
cDatum_Tag:
Tageszähler der inneren quarzgesteuerten Uhr. (Wird mit jedem gültigen DCF-dekodierten Wert synchronisiert).
cDatum_Monat:
Monatszähler der inneren quarzgesteuerten Uhr. (Wird mit jedem gültigen DCF-dekodierten Wert synchronisiert).
cDatum_Jahr:
Jahreszähler der inneren quarzgesteuerten Uhr. (Wird mit jedem gültigen DCF-dekodierten Wert synchronisiert).

Konstanten:
Bei einem LOW dauert die Absenkung des Trägers zwischen 80ms und 120ms, für ein HIGH dauert die Absenkung des Trägers zwischen 160ms und 240ms. Die Konstanten KONSTDCFLMIN, KONSTDCFLMAX, KONSTDCFHMIN und KONSTDCFHMAX dienen zur Ermittlung eines LOW oder eines HIGH.
Das Unterprogramm DCF_Routine wird alle 4ms aufgerufen, daher ergeben sich für diese Konstanten folgende Werte:

                KONSTDCFLMIN:   20   (20 x 4ms = 80ms)
                KONSTDCFLMAX:   30   (30 x 4ms = 120ms)
                KONSTDCFHMIN:   40   (40 x 4ms = 160ms)
                KONSTDCFHMAX:   60   (60 x 4ms = 240ms)
    

Es kann erforderlich sein, dass bei einer Anwendung die PIC-Taktfrequenz erhöht werden muss. In diesem Fall kann es notwendig sein, diese Konstanten anzupassen.

Die Konstante KONSTDCFNEUEMIN wird wür die Erkennung einer neuen Minute benötigt. Zur Erinnerung: Eine neue Minute wird im DCF-Telegramm durch das Ausbleiben der 59. Sekunde definiert.

Die Konstanten sind in der Datei DCF.H definiert (Listing 1):

Konstanten für die DCF-Dekodierung

Portdefinition:
Im Allgemeinen wird bei jeder Anwendung der Eingangspin für die DCF-Dekodierung an einem anderen Portpin verwendet. Damit dies in der Software nur an einer Stelle berücksichtigt werden muss befindet sich in der Software eine Portdefinition für den DCF-Eingang (Datei: DCF.H, Listing 2).

Portdefinition für die DCF-Dekodierung
Achtung:
Beim Initialisieren des PIC-Mikrocontroller (bei mir im Unterprogramm Init) muss dieser Portpin als Eingang konfiguriert werden. Siehe Demonstrationsbeispiel (Abschnitt 5)
nach oben

4.3. Unterprogramme für die DCF-Dekodierung

Zur DCF-Dekodierung sind 4 Unterprogramme notwendig:

Weiters das Unterprogramm DCF_Innere_Uhr. Dieses Unterprogramm sorgt dafür, dass, wenn kein gültiges DCF-Telegramm empfangen werden kann, die Uhrzeit trotzdem jede Sekunde aktualisiert wird. Ist für eine längere Zeit kein korrekter DCF-Empfang möglich, so würden die Minuten, die Stunden, die Tage usw. "stehen" bleiben, da im Unterprogramm DCF_UP_Minute nur gültige DCF-Telegramme übernommen werden.

Ein großes Plus des mikroC-Compilers ist, dass die globalen Register, die in einer C-Datei definiert sind, nicht von Unterprogrammen (oder vom Hauptprogramm) aus anderen C-Dateien benutzt werden können. Dadurch entsteht eine Art Datenkapselung, und "ungewollte" Registermanipulationen werden dadurch vermieden. Der mikroC-Compiler erzeugt eine Fehlermeldung, falls versucht wird ein globales Register aus einer anderen C-Datei anzusprechen.
Bei der DCF-Dekodierung sind aber die Uhrzeit und das Datum, sowie andere nützliche Flags und Variablen in solchen Registern abgelegt. Damit vom Hauptprogramm oder von Unterprogrammen der Inhalt dieser Register gelesen werden kann, sind eine Reihe von Unterprogrammen notwendig, die als Rückgabeparameter den Inhalt des gewünschten Registers an das aufrufende Programm zurückgeben. Die folgende Liste zeigt diese Unterprogramme.

Unterprogramm DCF_Init:
Das Unterprogramm DCF_Init hat die Aufgabe die für die DCF-Dekodierung notwendigen globalen Register zu initialisieren.

Listing 3 zeigt die Realisierung dieses Unterprogramms.

Unterprogramm DCF_Init

Unterprogramm DCF_Routine:
Das Unterprogramm DCF_Routine ist für die DCF-Dekodierung die wichtigste Komponente und muss ca. alle 4 ms aufgerufen werden.

Flussdiagramm DCF_Routine

Die Beschreibung dieses Unterprogrammes erfolgt mit Hilfe eines Flussdiagrammes (Abbildung 7). Die Aufgabe des Unterprogramms DCF_Routine besteht darin aus den Abtastungen des DCF-Eingangspins, die alle 4ms erfolgen, herauszufinden, ob ein Low, ein High oder ein Minutenwechsel gesendet wurde. Dazu wird bei jedem Aufruf des Unterprogramms DCF_Routine entweder das statische Zählregister cDCF_Puls oder das statische Zaehlregister cDCF_Pause um 1 erhöht (inkrementiert), wenn sich der Pegel vom DCF-Eingang zum vorhergehenden Aufruf dieses Unterprogramms nicht veraendert hat. Ist der DCF-Eingang Low (also logisch 0), so wird das Zählregister cDCF_Puls um 1 erhöht, ist der DCF-Eingang High (also logisch 1), so wird das Zählregister cDCF_Pause um 1 erhöht. Beide Zählregister können maximal den Wert 255 aufnehmen, was einer Zeit von 1020 ms (oder 1,02 Sekunden) entspricht (= 255 x 4ms).
Unterscheidet sich der aktuelle Pegel des DCF-Eingangs mit dem Pegel vom vorhergehenden Aufruf, so spricht man von einer Flanke, wobei hier zwischen einer fallenden und einer steigenden Flanke unterschieden werden muss. Bei einer steigenden Flanke (der aktuelle Pegel des DCF-Eingangs ist logisch 1), wird das statische Zählregister cDCF_Pause gelöscht. Anschließend erfolgt eine Auswertung des statischen Zählregisters cDCF_Puls. Beinhaltet dieses Zählregister einen Wert zwischen den Konstanten KONSTDCFHMIN und KONSTDCFHMAX, so wurde ein High des DCF-Telegramms ermittelt. Im DCF-Statusregister (cDCF_Status) werden daher die Flags bDCF_High und bDCF_Neue_Sekunde gesetzt. Das Flag bDCF_Neue_Sekunde dient als Zeichen einer neu empfangenen und gültigen Sekunde. Beinhaltet das Zählregister cDCF_Puls einen Wert zwischen den Konstanten KONSTDCFLMIN und KONSTDCFLMAX, so wurde ein Low des DCF-Telegramms ermittelt. Im DCF-Statusregister (cDCF_Status) werden daher die Flags bDCF_Low und bDCF_Neue_Sekunde gesetzt. Das Flag bDCF_Neue_Sekunde dient auch hier als Zeichen einer neu empfangenen und gültigen Sekunde. Beinhaltet das statische Zählregister cDCF_Puls einen Wert der weder zwischen den Konstanten KONSTDCFHMIN und KONSTDCFHMAX noch zwischen den Konstanten KONSTDCFLMIN und KONSTDCFLMAX liegt, so handelt es sich um einen Übertragungsfehler. In diesem Fall werden die Fehlerflags bDCF_Fehler und bDCF_Bitfehler im DCF-Statusregister (cDCF_Status) gesetzt. Das Flag bDCF_Neue_Sekunde wird hier aber nicht gesetzt, da es sich in diesem Fall um keine gültige Sekunde handelt. Das Fehlerflag bDCF_Fehler wird erst bei der Erkennung einer neuen Minute wieder gelöscht.
Bei einer fallenden Flanke (der aktuelle Pegel des DCF-Eingangs ist logisch 0) wird nur das statische Zählregister cDCF_Puls gelöscht.
Entsprechend dem im Abschnitt 2 (Grundlagen zu DCF) beschriebenen Protokoll erfolgt in der 59. Sekunde keine Absenkung des Trägers. Da es also in der 59. Sekunde keine fallende Flanke gibt, gibt es auch keine steigende Flanke. Das Zählregister cDCF_Pause "läuft über", da es nur einen Zählbereich von 0 bis 255 besitzt. Dieser Überlauf wird hier ausgenützt. Zur Bestimmung einer neuen Minute bzw. zur Bestimmung des Telegrammbeginns. Ist das Fehlerflag bDCF_Fehler gesetzt, so wird es nun gelöscht. War es nicht gesetzt, so wird das Flag bDCF_Neue_Minute im DCF-Hilfsregister (cDCF_Hilfsregister) gesetzt.

Im Flussdiagramm (Abbildung 7) erfolgt in den grau hinterlegten Bereichen das Setzen oder Rücksetzen der zur weiteren Verwendung notwendigen Übergabeflags im DCF-Statusregister (cDCF_Status). Die Unterprogramme DCF_UP_Sekunde und DCF_UP_Minute greifen auf diese Flags zu.

Listing 4 zeigt die Realisierung dieses etwas umfangreicheren Unterprogramms.

Unterprogramm DCF_Routine (Teil 1)
Unterprogramm DCF_Routine (Teil 2)

Unterprogramm DCF_UP_Sekunde:
Das Unterprogramm DCF_UP_Sekunde hat die Aufgabe, je nachdem ob das Bit bDCF_Low oder das Bit bDCF_High gesetzt ist dieses Bit dem Telegramm (Register cDCF_Telegramm1 bis cDCF_Telegramm8) hinzuzufügen.

Vorgehensweise:
Ist das Flag bDCF_Low (im Register cDCF_Status) gesetzt das Carryflag (im SFR5 STATUS) löschen. Ist das Flag bDCF_High (ebenfalls im Register cDCF_Status) gesetzt, das Carryflag setzten. Dieses Carryflag nun dem Telegramm hinzufügen. Dieser Vorgang erfolgt mit einem so genannten Schiebebefehl. Dabei werden alle Bits des Registers cDCF_Telegramm1 auf die nächst höhere Position verschoben. (Bit 6 wandert ins Bit 7, Bit 5 wandert ins Bit 6 usw. Bit 0 wandert ins Bit 1). Der Inhalt vom Carryflag wandert ins Bit 0. Der Inhalt von Bit 7 wird ins Carryflag geschoben. Bei den Register cDCF_Telegramm2 bis cDCF_Telegramm6 erfolgt der selbe Vorgang. (Der Inhalt von Bit 7 des Registers cDCF_Telegramm1 wird ins Carry geschoben, und das Carry aber weiter in das Bit 0 des Registers cDCF_Telegramm2). Achtung: Diese Schiebebefehle sind nur als Assembler-Anweisungen verfügbar. Daher sind diese Befehle in einem asm-Block (Zeilen 306 bis 315).

Anmerkung:
Die beiden Flags bDCF_Low und bDCF_High können nie gleichzeitig gesetzt sein. Es ist nur möglich, dass entweder nur bDCF_Low oder nur bDCF_High gesetzt ist, aber nie beide gleichzeitig.

Wichtig:
Dieses Unterporgramm wird durch ein gesetztes Botschaftsflag aufgerufen. Dieses Botschaftsflag muss daher wieder gelöscht werden (Zeile 319).

Listing 5 zeigt die Realisierung dieses Unterprogramms.

Unterprogramm DCF_UP_Sekunde

Unterprogramm DCF_UP_Minute:
Das Unterprogramm DCF_UP_Minute hat folgende Aufgaben:

  1. Datum, Uhrzeit und die Zusatzinformationen aus den Registern cDCF_Telegramm1 bis cDCF_Telegramm6 zusammensetzen.
  2. Das so eben ermittelte Telegramm mit dem Telegramm der vorhergehenden Minute vergleichen. Die so eben ermittelte Minute muss dabei um 1 größer als die vorhergehende Minute sein, und die so eben ermittelten Werte füer die Stunde, den Tag, den Monat, das Jahr und den Wochentag müssen mit den Werten des vorhergehenden Telegramms übereinstimmen. ACHTUNG: Bei dieser einfachen Überprüfung wird der Übergang von z. B. 13:59 auf 14:00 als falsch gewertet, da sich hier die Stunde ändert, und auch die Minute um mehr als 1. Würden hier alle möglichen Übergänge berücksichtigt, dann würde dieses Unterprogramm noch umfangreicher als es ohnehin schon ist werden. Durch diese Vereinfachung dauert die Synchronisierung im ungünstigsten Fall nur eine Minute länger.
  3. Das alte Datum bzw. die alte Uhrzeit (von der vorhergehenden Minute) durch das neue Datum bzw. die Uhrzeit ersetzen. Dies ist für die Überprüfung des nachsten Telegramms notwendig.
  4. Wenn das neu empfangene Datum bzw. die neu empfangene Uhrzeit gültig ist, die BCD-kodierten Datums- bzw. Uhrzeitkomponenten in eine binäre Form umwandeln und damit die mitlaufende Uhr synchronisieren. Das Flag bDCF_Sync im Register cDCF_Status setzen. Dieses gesetzte Flag kennzeichnet, dass die mitlaufende Uhr mit der DCF-Uhr synchronisiert ist.
Wichtig:
Dieses Unterporgramm wird durch ein gesetztes Botschaftsflag aufgerufen. Dieses Botschaftsflag muss daher wieder gelöscht werden (Zeile 455).

Listing 6 zeigt die Realisierung dieses etwas umfangreicheren Unterprogramms.

Unterprogramm DCF_UP_Minute (Teil 1)
Unterprogramm DCF_UP_Minute (Teil 2)

Unterprogramm DCF_Innere_Uhr:
Für den Fall dass kein gültiges DCF-Telegramm empfangen werden kann sorgt das Unterprogramm DCF_Innere_Uhr dafür, dass die Uhrzeit trotzdem jede Sekunde aktualisiert wird. Ist für eine längere Zeit kein korrekter DCF-Empfang möglich, so würden die Minuten, die Stunden, die Tage usw. "stehen" bleiben, da ja im Unterprogramm DCF_UP_Minute nur gültige DCF-Telegramme übernommen werden. Dieses Unterprogramm wird also parallel zu den Unterprogrammen für die DCF-Dekodierung aufgerufen.

Vorgehensweise:
Die Sekunden (Register cUhr_Sekunde) um 1 erhöhen. Beinhaltet dieses Register nun den Wert 60, so beginnt eine neue Minute. Daher die Sekunden löschen und die Minuten (Register cUhr_Minute) um 1 erhöhen. Beinhaltet dieses Register nun den Wert 60, so beginnt eine neue Stunde. Daher die Minuten löschen und die Stunden (Register cUhr_Stunde) um 1 erhöhen. Beinhaltet dieses Register nun den Wert 24, so beginnt ein neuer Tag. Daher die Stunden löschen. Ist das Mitzählen des Datums notwendig, so muss nun ein Register für den Tag (z.B. cDatum_Tag) um 1 erhöht werden und dieses überprüft werden, wobei diese Prüfung nun nicht mehr so einfach ist, da ja jeder Monat unterschiedlich viele Tage besitzt. Erschwerend kommt auch noch hinzu, dass auch die Schaltjahre miteinbezogen werden müssen!

Wichtig:
Dieses Unterprogramm muss jede Sekunde (z.B. vom Hauptprogramm) aufgerufen werden.

Listing 7 zeigt die Realisierung dieses Unterprogramms.

Unterprogramm DCF_Innere_Uhr

Unterprogramme zum Lesen von Uhrzeit, Datum und diversen Zusatzinformationen:
Die Uhrzeit, das Datum, sowie andere nützliche Informationen sind in globalen Registern gesichert. Diese globalen Register können nur vom Quellcode in der Datei DCF.C verändert und gelesen werden. Das Hauptprogramm, oder andere Unterprogramme benötigen aber diese Informationen. Daher sind einige Unterprogramme notwendig, die als Rückgabeparameter nur den Inhalt dieser Register beinhalten. Durch diesen Mechanismus wird verhindert, dass Programmteile Datenregister (ungewollt) verändern. Dieser Mechanismus wir in der Informatik auch Datenkapselung genannt.

Die Listings 8 bis 26 zeigen diese sehr einfachen Unterprogramme.

Unterprogramm DCF_Get_Sekunde
Unterprogramm DCF_Get_Minute
Unterprogramm DCF_Get_Stunde
Unterprogramm DCF_Get_Tag
Unterprogramm DCF_Get_Monat
Unterprogramm DCF_Get_Jahr
Unterprogramm DCF_Get_Wochentag
Unterprogramm DCF_Get_Status
Unterprogramm DCF_Is_Low
Unterprogramm DCF_Is_High
Unterprogramm DCF_Is_Bitfehler
Unterprogramm DCF_Is_Fehler
Unterprogramm DCF_Is_Sync
Unterprogramm DCF_Get_Zusatzinfos
Unterprogramm DCF_Is_ResAntenne
Unterprogramm DCF_Is_Zeitumstellung
Unterprogramm DCF_Is_Sommerzeit
Unterprogramm DCF_Is_Winterzeit
Unterprogramm DCF_Is_Schaltsekunde

Unterprogramme zum Lesen der Botschaftsflags für die Abarbeitung der Unterprogramme DCF_UP_Sekunde und DCF_UP_Minute:
Die für die DCF-Dekodierung wichtigen Unterprogramme DCF_UP_Sekunde (Listing 6) und DCF_UP_Minute (Listing 6) werden nur bei einer vollen Sekunde bzw. bei einer vollen Minute abgearbeitet. Die zwei Botschaftsflags bDCF_Neue_Sekunde und bDCF_Neue_Minute müssen daher mit Hilfe der Unterprogramme DCF_Is_Neue_Sekunde (Listing 27) und DCF_Is_Neue_Minute (Listing 28) im Hauptprogramm abgefragt werden. Denn auch hier gilt das Prinzip der Datenkapselung, da diese zwei Botschaftsflags im Unterprogramm DCF_Routine (Listing 4, in der Datei DCF.C) gesetzt werden. Anmerkung: Diese beiden Botschaftsflags werden automatisch in den Unterprogrammen DCF_UP_Sekunde bzw. DCF_UP_Minute zurückgesetzt.

Unterprogramm DCF_Is_Neue_Sekunde
Unterprogramm DCF_Is_Neue_Minute

Das Demonstrationsbeispiel (im Abschnitt 5) zeigt dies an einem konkreten, praktischen Beispiel.

nach oben

5 SFR steht für Special Function Register. Diese Register haben vom Mikrocontroller-Hersteller klar definierte Aufgaben, und sind im Datenblatt des Mikrocontrollers beschrieben

nach oben


zurück zu Elektronik, Homepage

Autor: Stefan Buchgeher
Erstellt: 21. Februar 2010
Letzte Änderung: 25. März 2010