Dirk
06.06.2009, 16:03
Hallo Besitzer der Zusatzplatine RP6 CCPRO M128,
die mitgelieferte Library DCF_Lib.cc hat gerade so die basalen Funktionen eines DCF-Decoders. Mit dieser CCPRO BASIC Bibliothek RP6DCFCCLib.cbas wird das besser. Viel Spaß damit.
Demo (DCF_RTC.cbas):
/************************************************** *****************************
* RP6 C-Control PRO M128 Erweiterungsmodul
* ----------------------------------------------------------------------------
* DCF_RTC Demoprogramm 2
* ----------------------------------------------------------------------------
* DCF_RTC: DCF Uhr
* DCF Empfänger erforderlich
* Mega128: DCF-Eingang PE5 (PortE.5, RP6: INT1)
* Der DCF-Eingang kann in RP6DCFCClib.cbas geändert werden.
* erforderliche Library: IntFunc_Lib.cc und neue RP6DCFCClib.cbas (v. 1.xx).
*
* Über den zusätzlich erforderlichen DCF Empfänger (Art-Nr. 641138) wird
* das DCF Signal empfangen.
* Auf dem LCD-Display werden die Zeit und das Datum angezeigt.
* Die LED1 blinkt im Sekundentakt.
*
* Hinweis:
* Für allgemeine Programmierhinweise zur CCPRO schauen Sie sich bitte die
* CCPRO Dokumentation und die zugehörigen Beispielprogramme an!
* Es sei auch nochmals darauf hingewiesen, dass die normalen Beispielprogramme
* für die CCPRO nur zum Teil direkt auf dem RP6-CCPRO Modul laufen.
* Die Anschlussbelegung ist natürlich komplett anders als auf dem
* C-Control Application Board. Auch die LCD Ansteuerung ist leicht anders,
* da hier noch zusätzliche LEDs mit an dem Schieberegister angeschlossen sind.
* --> Die C-Control Beispielprogramme müssen ein klein wenig angepasst
* werden bevor sie auf diesem Modul laufen können!
*
* ************************************************** ***************************
* Der Roboter bewegt sich in diesem Beispielprogramm NICHT und kann
* am Rechner angeschlossen bleiben!
************************************************** ****************************/
' WICHTIG: Immer die RP6CCLib mit einbinden:
#include "../../RP6CCLib/RP6CCLib.cbas"
' Die neue RP6DCFCCLib einbinden:
#include "../../RP6CCLib/RP6DCFCClib.cbas"
Dim irqcnt As Integer ' globale Variablendeklaration
Dim cnt1, alte_sekunde As Byte
Sub main()
' WICHTIG! Immer als erstes aufrufen:
RP6_CCPRO_Init() ' Auf Startsignal warten, LCD und andere Dinge initialisieren !
' ------------------------------------------------------
' Zwei Zeilen Text mit dem LCD anzeigen:
showScreenLCD("RP6 CCPRO M128", "DCF RTC Demo 2!")
' Zweimal piepsen:
beep(200, 300, 100) ' Format: beep (<tonhöhe>, <dauer>, <pause>)
beep(100, 100, 100)
' Text über serielle Schnittstelle ausgeben:
newline() ' Neue Zeile
println(" ________________________")
println(" \\| RP6 ROBOT SYSTEM |/")
println(" \\_-_-_-_-_-_-_-_-_-_/ ")
newline()
println(" Let's go! ")
newline()
' 2 Sekunden Pause:
AbsDelay(2000)
' ------------------------------------------------------
' DCF-Hauptprogramm:
Port_WriteBit(PORT_LED1, PORT_OFF) ' LED1 aus
clearLCD() ' Display löschen
Time_Init() ' Funktionsaufruf zur Festlegung
' von Startzeit und Startdatum.
initDCF() ' Initialisierung des DCF Modus
Irq_SetVect(INT_TIM2COMP, INT_10ms) ' ISR definieren
' Timer2: 10ms Interrupt
Do While True ' Endlosschleife
If cnt1 = 50 Then
Port_WriteBit(PORT_LED1, PORT_OFF) ' LED1 aus
End If
If cnt1 = 100 Then ' Sekundentakt
Port_WriteBit(PORT_LED1, PORT_ON) ' LED1 an
cnt1 = 0
End If
If alte_sekunde <> Sekunde Then
alte_sekunde = Sekunde
#ifndef DEBUG
showCLOCK()
' showSTATUS()
#endif
#ifdef DEBUG
showDEBUGINFO()
#endif
End If
End While
End Sub
' -----------------------------------------------------------------------------
' Festlegung von Startzeit und Startdatum
'
Sub Time_Init()
Sekunde = 0 ' Uhr Startzeit: 12:00:00
Minute = 0
Stunde = 12
Wochentag = 7
Tag = 31 ' Uhr Startdatum: 31.05.2009
Monat = 5
Jahr = 9
End Sub
' -----------------------------------------------------------------------------
' Interrupt Routine
'
Sub INT_10ms()
cnt1 = cnt1 + 1 ' Zähler für Blinken der LED1
decodeDCF() ' DCF77 Decoder
irqcnt = Irq_GetCount(INT_TIM2COMP) ' Interrupt Request Counter
End Sub
' -----------------------------------------------------------------------------
Bibliothek (RP6DCFCClib.cbas), Teil 1:
/* ************************************************** **************************
* _______________________
* \| RP6 ROBOT SYSTEM |/
* \_-_-_-_-_-_-_-_-_-_/ >>> CCPRO M128
* ----------------------------------------------------------------------------
* ----------------------- [c]2009 - Dirk -------------------------------------
* ************************************************** **************************
* File: RP6DCFCClib.cbas
* Version: 1.0 - CCPRO BASIC
* Target: RP6 CCPRO M128 - C-Control PRO M128 @14.7456MHz
* mit optionalem LC-Display 16x2 Zeichen (CONRAD 190911)
* [oder OLED Textdisplay 16x2 Zeichen (CONRAD 197622)]
* und einem DCF77 Empfänger Modul (z.B. CONRAD 641138)
* Author(s): Dirk
* ************************************************** **************************
* Beschreibung:
* Dies ist meine DCF77 Bibliothek für die RP6 CCPRO M128.
* Der DCF-Empfänger wird an PE5 (XBUS INT1, SPI_I/O: Pin 7) der CCPRO M128
* angeschlossen.
*
* ANMERKUNG: Ein 10 kOhm Pulldown-Widerstand (R34) ist auf dem RP6 Mainboard
* mit E_INT1 verbunden und damit auch mit INT1 auf der CCPRO M128.
* Normalerweise haben DCF Empfänger einen open-collector Ausgang
* und benötigen einen PULLUP Widerstand zur korrekten Funktion.
* Der interne Pullup-Widerstand des ATMEGA128 kann den Pulldown-
* Widerstand auf dem RP6 Mainboard nicht kompensieren.
* Deshalb muss man einen PULLUP-Widerstand zwischen +5V und den
* DCF Empfängerausgang legen. Bei meinem DCF Empfänger klappt es
* gut mit einem 2,2 kOhm Widerstand.
*
* ************************************************** **************************
* CHANGELOG FINDEN SIE AM ENDE DIESER DATEI!
* ************************************************** **************************
*/
' Alles nur EINMAL einbinden!
#ifndef __RP6DCFCCLIB__
#define __RP6DCFCCLIB__
/************************************************** ****************************/
' Defines:
' RP6 CCPRO M128 DCF Empfänger Anschluß:
#define DCF_IN 37 ' DCF Eingangs Signale an PortE.5 (RP6: INT1)
' #define DCF_IN 13 ' DCF Eingangs Signal an PortB.5 (SERVO_1 PB5)
#define BIT_0 0x00 ' 0b00000000
#define BIT_1 0x80 ' 0b10000000
#define LETZTESBIT_0 0x40 ' 0b01000000
#define LETZTESBIT_1 0xc0 ' 0b11000000
#define BIT_FEHLER 0x01 ' 0b00000001
/************************************************** ************/
' AUFBAU DES DCF77 TELEGRAMMS:
' Bit 0: DCF Bit 0 (immer 0)
' Bits 1..14: Codierte Wetter Infos (Meteo Time GmbH)
' Bits 15..20 (DCF Flags):
' Flag R: Ruf Bit 15 für PTB Angestellte
' Flag A1: Ankündigung eines Zeitzonenwechsels
' Flag Z1: Zeitzone 1 [0 = MEZ, 1 = MESZ] (Z1 != Z2)
' Flag Z2: Zeitzone 2 [1 = MEZ, 0 = MESZ] (Z2 != Z1)
' Flag A2: Ankündigung einer Schaltsekunde
' Flag S: Start Bit 20 (immer 1)
' Bits 21..27: Minute (BCD)
' Bit 28 [P1]: Minutenparität
' Bits 29..34: Stunde (BCD)
' Bit 35 [P2]: Stundenparität
' Bits 36..41: Tag (BCD)
' Bits 42..44: Wochentag
' Bits 45..49: Monat (BCD)
' Bits 50..57: Jahr (BCD)
' Bit 58 [P3]: Datumsparität
' [Bit 59: Schaltsekundenbit (immer 0)]
/************************************************** ************/
' #define DEBUG ' Debug Modus
' Der Debug Modus dient zum Abgleich der Pausenlängen (PAUSE_xxxMS).
' Das LCD zeigt die vom Decoder erkannten Pausenlängen an. Wenn es
' eine deutliche Abweichung gibt, können die Pausenlängen angepaßt
' werden.
' #define REPARATUR ' Reparatur Modus
' Im Reparatur Modus wird in dieser Programm Version nur eine Er-
' kennung von Spikes ermöglicht. Damit sinkt die Störanfälligkeit.
' In weiteren Programmversionen kann hier ggf. noch eine "echte"
' Reparatur von fehlerhaften DCF Telegrammen erfolgen.
' #define WETTER ' Wetter Infos decodieren
' Wenn man die in den DCF Bits 1..14 enthaltenen Wetter Informationen
' einsehen möchte, muss man das Programm mit definiertem "WETTER"
' kompilieren. Da die Infos verschlüsselt sind, wird man in der Regel
' diese Bits nicht sinnvoll verwenden können.
#define UHRABGLEICH 100 ' Uhr Abgleich (100 x 10ms = 1s)
' Mit "UHRABGLEICH" kann man die Ganggenauigkeit der Software-Uhr beein-
' flussen.
#define PAUSE_800MS 80 ' Bit 1 Pausenlänge
#define PAUSE_900MS 90 ' Bit 0 Pausenlänge
#define PAUSE_1800MS 180 ' Letztes Bit 1 Pausenlänge
#define PAUSE_1900MS 190 ' Letztes Bit 0 Pausenlänge
#define PAUSE_ABWEICHUNG 5 ' Pausenlänge Abweichung
' Das DCF77 Telegramm wird in einer ganzen Minute für die Folgeminute
' übertragen. In jeder Sekunde wird ein DCF Bit codiert. Senderseitig
' wird dazu die Sendeleistung 100ms lang für ein 0-Bit oder 200ms lang
' für ein 1-Bit auf 25% abgesenkt. Danach ist für den Rest der Sekunde
' (900ms bzw. 800ms) Pause, also 100% Sendeleistung. Für einen DCF De-
' coder ist das Ende des Telegramms dadurch erkennbar, dass das letzte
' Bit (DCF Bit 58) eine Pause von 1900ms bzw. 1800ms besitzt. Damit
' können die o.g. 4 Pausendauern (PAUSE_XXXMS) unterschieden werden.
' Da der DCF Decoder alle 10ms aufgerufen wird, wird er etwa 80-mal den
' selben Pegel am Eingang feststellen, wenn die Pause nach einem 1-Bit
' gesendet wird.
' Durch "PAUSE_ABWEICHUNG" wird festgelegt, welche Abweichung vom Soll
' zugelassen wird. Beim Wert 5 erkennt der Decoder ein 1-Bit, wenn er
' zwischen 75- und 84-mal (= 750..840ms) den selben Pegel feststellt.
#define VALIDITAETSSTANDARD 1 ' Validitätszähler Grenze
' (1: Jedes DCF Telegramm nutzen!)
' Als INTAKT gilt ein Telegramm, wenn folgende Bedingungen erfüllt sind:
' 1. DCF Bit 0 ist 0
' 2. DCF Bits 17 und 18 sind ungleich
' 3. DCF Bit 20 ist 1
' 4. Die Paritätsbits 28, 35, 58 enthalten eine korrekte gerade Parität
' 5. Es wurden genau 58 DCF Bits decodiert
' 6. Fall Schaltsekunde: DCF Bit 59 ist 0 und DCF Bit 19 ist 1
' Nicht PLAUSIBEL ist ein Telegramm, wenn Werte außerhalb des möglichen
' Bereichs liegen. Ein Wert von 9 für den Wochentag ist z.B. nicht
' plausibel. Allgemeiner könnte man sagen, dass ein DCF Telegramm nicht
' plausibel ist, wenn es nicht die Folgeminute der aktuellen Minute ab-
' bildet.
' Ein Telegramm ist VALIDE (= gültig), wenn es intakt UND plausibel ist.
' Jedes valide DCF Telegramm wird gezählt. Ist VALIDITAETSSTANDARD 1,
' dann wird jedes valide Telegramm zum Stellen der Uhr verwendet. Man
' kann den Wert erhöhen, wenn man ein Stellen der Uhr nur bei sehr guten
' Empfangsbedingungen erlauben will. Setzt man VALIDITAETSSTANDARD z.B.
' auf 3, dann wird ein Telegramm nur dann zum Stellen der Uhr verwendet,
' wenn es das dritte valide Telegramm in Folge ist.
/************************************************** ****************************/
' Variablen:
Dim Jahr As Byte ' Jahr [0..99]
Dim Monat As Byte ' Monat [1..12]
Dim Wochentag As Byte ' Wochentag [1..7 = MO..SO]
Dim Tag As Byte ' Tag [1..31]
Dim Sommerzeit As Byte ' Zeitzone [0 / 1 = MEZ / MESZ]
Dim Stunde As Byte ' Stunde [0..23]
Dim Minute As Byte ' Minute [0..59]
Dim Sekunde As Byte ' Sekunde [0..59]
#ifdef WETTER
Dim Wetter As Word ' Codierte Wetter Informationen
#endif ' (DCF Bits 1..14; Bit 0 immer 0)
Dim dcfflags As Byte ' DCF Flags (DCF Bits 15..20):
#define FLAG_R 1 ' R: Ruf Bit 15 für PTB Angestellte
#define FLAG_A1 2 ' A1: Ankündigung eines Zeitzonenwechsels
#define FLAG_Z1 4 ' Z1: Zeitzone 1 [0 = MEZ, 1 = MESZ]
#define FLAG_Z2 8 ' Z2: Zeitzone 2 [1 = MEZ, 0 = MESZ]
#define FLAG_A2 16 ' A2: Ankündigung einer Schaltsekunde
#define FLAG_S 32 ' S: Start Bit 20 (immer 1)
Dim dcfstatus As Byte ' Status Flags (Bits 0..5 nur lesen!):
#define STATUS_FEHLER 1 ' Telegramm Fehler
#define STATUS_MINPARITAET 2 ' Minutenparität ok
#define STATUS_STDPARITAET 4 ' Stundenparität ok
#define STATUS_DATPARITAET 8 ' Datumsparität ok
#define STATUS_DCFBIT58 16 ' 58 (oder 59) DCF Bits decodiert
#define STATUS_TELEGRAMMINTAKT 32 ' Telegramm intakt
#define STATUS_UHRGESTELLT 64 ' Uhr einmal gestellt
#define STATUS_DCF_AN 128 ' DCF77 Decoder AN
Dim validitaetszaehler As Byte ' Zähler für intakte und
' plausible DCF Telegramme
Dim validitaetsgrenze As Byte ' Grenze Validitäts Zähler
#ifdef DEBUG
Dim pause_1_laenge As Byte
Dim pause_0_laenge As Byte
Dim letztepause_1_laenge As Byte
Dim letztepause_0_laenge As Byte
#endif
/************************************************** ****************************/
' Funktionen:
/**
* INIT DCF
*
* Unbedingt einmal aufrufen, bevor die DCF77 Funktion benutzt wird!
*
*/
Sub initDCF()
Port_DataDirBit(DCF_IN, 0) ' Port = Eingang
Port_WriteBit(DCF_IN, 1) ' Pullup Widerstand ein
validitaetszaehler = 0 ' Validitätszähler zurücksetzen
validitaetsgrenze = VALIDITAETSSTANDARD ' Grenze setzen
dcfstatus = STATUS_DCF_AN ' DCF77 Decoder AN
End Sub
/**
* DCF DECODER AN
*
* Der DCF77 Decoder wird eingeschaltet.
* Immer wenn ein intaktes DCF Telegramm decodiert wurde, kann die
* Uhr mit den aktuellen DCF Informationen gestellt werden.
*
*/
Sub DCFon()
dcfstatus = dcfstatus Or STATUS_DCF_AN ' Status Bit 7 setzen
End Sub
/**
* DCF DECODER AUS
*
* Der DCF77 Decoder wird ausgeschaltet.
* Die Uhr wird durch die interne Referenz (Timer) betrieben.
*
*/
Sub DCFoff()
' Alle Status Bits löschen, nur Status Bit 6 bleibt unverändert:
dcfstatus = dcfstatus And STATUS_UHRGESTELLT
End Sub
/**
* BCD to DEC
*
* Diese Funktion wandelt einen BCD- in einen Dezimalwert um.
*
*/
Sub BCDtoDEC(bcd As Byte) As Byte
Return (bcd >> 4) * 10 + (bcd And 0x0f)
End Sub
Gruß Dirk
P.S.: Teil 2 der Bibliothek folgt!
die mitgelieferte Library DCF_Lib.cc hat gerade so die basalen Funktionen eines DCF-Decoders. Mit dieser CCPRO BASIC Bibliothek RP6DCFCCLib.cbas wird das besser. Viel Spaß damit.
Demo (DCF_RTC.cbas):
/************************************************** *****************************
* RP6 C-Control PRO M128 Erweiterungsmodul
* ----------------------------------------------------------------------------
* DCF_RTC Demoprogramm 2
* ----------------------------------------------------------------------------
* DCF_RTC: DCF Uhr
* DCF Empfänger erforderlich
* Mega128: DCF-Eingang PE5 (PortE.5, RP6: INT1)
* Der DCF-Eingang kann in RP6DCFCClib.cbas geändert werden.
* erforderliche Library: IntFunc_Lib.cc und neue RP6DCFCClib.cbas (v. 1.xx).
*
* Über den zusätzlich erforderlichen DCF Empfänger (Art-Nr. 641138) wird
* das DCF Signal empfangen.
* Auf dem LCD-Display werden die Zeit und das Datum angezeigt.
* Die LED1 blinkt im Sekundentakt.
*
* Hinweis:
* Für allgemeine Programmierhinweise zur CCPRO schauen Sie sich bitte die
* CCPRO Dokumentation und die zugehörigen Beispielprogramme an!
* Es sei auch nochmals darauf hingewiesen, dass die normalen Beispielprogramme
* für die CCPRO nur zum Teil direkt auf dem RP6-CCPRO Modul laufen.
* Die Anschlussbelegung ist natürlich komplett anders als auf dem
* C-Control Application Board. Auch die LCD Ansteuerung ist leicht anders,
* da hier noch zusätzliche LEDs mit an dem Schieberegister angeschlossen sind.
* --> Die C-Control Beispielprogramme müssen ein klein wenig angepasst
* werden bevor sie auf diesem Modul laufen können!
*
* ************************************************** ***************************
* Der Roboter bewegt sich in diesem Beispielprogramm NICHT und kann
* am Rechner angeschlossen bleiben!
************************************************** ****************************/
' WICHTIG: Immer die RP6CCLib mit einbinden:
#include "../../RP6CCLib/RP6CCLib.cbas"
' Die neue RP6DCFCCLib einbinden:
#include "../../RP6CCLib/RP6DCFCClib.cbas"
Dim irqcnt As Integer ' globale Variablendeklaration
Dim cnt1, alte_sekunde As Byte
Sub main()
' WICHTIG! Immer als erstes aufrufen:
RP6_CCPRO_Init() ' Auf Startsignal warten, LCD und andere Dinge initialisieren !
' ------------------------------------------------------
' Zwei Zeilen Text mit dem LCD anzeigen:
showScreenLCD("RP6 CCPRO M128", "DCF RTC Demo 2!")
' Zweimal piepsen:
beep(200, 300, 100) ' Format: beep (<tonhöhe>, <dauer>, <pause>)
beep(100, 100, 100)
' Text über serielle Schnittstelle ausgeben:
newline() ' Neue Zeile
println(" ________________________")
println(" \\| RP6 ROBOT SYSTEM |/")
println(" \\_-_-_-_-_-_-_-_-_-_/ ")
newline()
println(" Let's go! ")
newline()
' 2 Sekunden Pause:
AbsDelay(2000)
' ------------------------------------------------------
' DCF-Hauptprogramm:
Port_WriteBit(PORT_LED1, PORT_OFF) ' LED1 aus
clearLCD() ' Display löschen
Time_Init() ' Funktionsaufruf zur Festlegung
' von Startzeit und Startdatum.
initDCF() ' Initialisierung des DCF Modus
Irq_SetVect(INT_TIM2COMP, INT_10ms) ' ISR definieren
' Timer2: 10ms Interrupt
Do While True ' Endlosschleife
If cnt1 = 50 Then
Port_WriteBit(PORT_LED1, PORT_OFF) ' LED1 aus
End If
If cnt1 = 100 Then ' Sekundentakt
Port_WriteBit(PORT_LED1, PORT_ON) ' LED1 an
cnt1 = 0
End If
If alte_sekunde <> Sekunde Then
alte_sekunde = Sekunde
#ifndef DEBUG
showCLOCK()
' showSTATUS()
#endif
#ifdef DEBUG
showDEBUGINFO()
#endif
End If
End While
End Sub
' -----------------------------------------------------------------------------
' Festlegung von Startzeit und Startdatum
'
Sub Time_Init()
Sekunde = 0 ' Uhr Startzeit: 12:00:00
Minute = 0
Stunde = 12
Wochentag = 7
Tag = 31 ' Uhr Startdatum: 31.05.2009
Monat = 5
Jahr = 9
End Sub
' -----------------------------------------------------------------------------
' Interrupt Routine
'
Sub INT_10ms()
cnt1 = cnt1 + 1 ' Zähler für Blinken der LED1
decodeDCF() ' DCF77 Decoder
irqcnt = Irq_GetCount(INT_TIM2COMP) ' Interrupt Request Counter
End Sub
' -----------------------------------------------------------------------------
Bibliothek (RP6DCFCClib.cbas), Teil 1:
/* ************************************************** **************************
* _______________________
* \| RP6 ROBOT SYSTEM |/
* \_-_-_-_-_-_-_-_-_-_/ >>> CCPRO M128
* ----------------------------------------------------------------------------
* ----------------------- [c]2009 - Dirk -------------------------------------
* ************************************************** **************************
* File: RP6DCFCClib.cbas
* Version: 1.0 - CCPRO BASIC
* Target: RP6 CCPRO M128 - C-Control PRO M128 @14.7456MHz
* mit optionalem LC-Display 16x2 Zeichen (CONRAD 190911)
* [oder OLED Textdisplay 16x2 Zeichen (CONRAD 197622)]
* und einem DCF77 Empfänger Modul (z.B. CONRAD 641138)
* Author(s): Dirk
* ************************************************** **************************
* Beschreibung:
* Dies ist meine DCF77 Bibliothek für die RP6 CCPRO M128.
* Der DCF-Empfänger wird an PE5 (XBUS INT1, SPI_I/O: Pin 7) der CCPRO M128
* angeschlossen.
*
* ANMERKUNG: Ein 10 kOhm Pulldown-Widerstand (R34) ist auf dem RP6 Mainboard
* mit E_INT1 verbunden und damit auch mit INT1 auf der CCPRO M128.
* Normalerweise haben DCF Empfänger einen open-collector Ausgang
* und benötigen einen PULLUP Widerstand zur korrekten Funktion.
* Der interne Pullup-Widerstand des ATMEGA128 kann den Pulldown-
* Widerstand auf dem RP6 Mainboard nicht kompensieren.
* Deshalb muss man einen PULLUP-Widerstand zwischen +5V und den
* DCF Empfängerausgang legen. Bei meinem DCF Empfänger klappt es
* gut mit einem 2,2 kOhm Widerstand.
*
* ************************************************** **************************
* CHANGELOG FINDEN SIE AM ENDE DIESER DATEI!
* ************************************************** **************************
*/
' Alles nur EINMAL einbinden!
#ifndef __RP6DCFCCLIB__
#define __RP6DCFCCLIB__
/************************************************** ****************************/
' Defines:
' RP6 CCPRO M128 DCF Empfänger Anschluß:
#define DCF_IN 37 ' DCF Eingangs Signale an PortE.5 (RP6: INT1)
' #define DCF_IN 13 ' DCF Eingangs Signal an PortB.5 (SERVO_1 PB5)
#define BIT_0 0x00 ' 0b00000000
#define BIT_1 0x80 ' 0b10000000
#define LETZTESBIT_0 0x40 ' 0b01000000
#define LETZTESBIT_1 0xc0 ' 0b11000000
#define BIT_FEHLER 0x01 ' 0b00000001
/************************************************** ************/
' AUFBAU DES DCF77 TELEGRAMMS:
' Bit 0: DCF Bit 0 (immer 0)
' Bits 1..14: Codierte Wetter Infos (Meteo Time GmbH)
' Bits 15..20 (DCF Flags):
' Flag R: Ruf Bit 15 für PTB Angestellte
' Flag A1: Ankündigung eines Zeitzonenwechsels
' Flag Z1: Zeitzone 1 [0 = MEZ, 1 = MESZ] (Z1 != Z2)
' Flag Z2: Zeitzone 2 [1 = MEZ, 0 = MESZ] (Z2 != Z1)
' Flag A2: Ankündigung einer Schaltsekunde
' Flag S: Start Bit 20 (immer 1)
' Bits 21..27: Minute (BCD)
' Bit 28 [P1]: Minutenparität
' Bits 29..34: Stunde (BCD)
' Bit 35 [P2]: Stundenparität
' Bits 36..41: Tag (BCD)
' Bits 42..44: Wochentag
' Bits 45..49: Monat (BCD)
' Bits 50..57: Jahr (BCD)
' Bit 58 [P3]: Datumsparität
' [Bit 59: Schaltsekundenbit (immer 0)]
/************************************************** ************/
' #define DEBUG ' Debug Modus
' Der Debug Modus dient zum Abgleich der Pausenlängen (PAUSE_xxxMS).
' Das LCD zeigt die vom Decoder erkannten Pausenlängen an. Wenn es
' eine deutliche Abweichung gibt, können die Pausenlängen angepaßt
' werden.
' #define REPARATUR ' Reparatur Modus
' Im Reparatur Modus wird in dieser Programm Version nur eine Er-
' kennung von Spikes ermöglicht. Damit sinkt die Störanfälligkeit.
' In weiteren Programmversionen kann hier ggf. noch eine "echte"
' Reparatur von fehlerhaften DCF Telegrammen erfolgen.
' #define WETTER ' Wetter Infos decodieren
' Wenn man die in den DCF Bits 1..14 enthaltenen Wetter Informationen
' einsehen möchte, muss man das Programm mit definiertem "WETTER"
' kompilieren. Da die Infos verschlüsselt sind, wird man in der Regel
' diese Bits nicht sinnvoll verwenden können.
#define UHRABGLEICH 100 ' Uhr Abgleich (100 x 10ms = 1s)
' Mit "UHRABGLEICH" kann man die Ganggenauigkeit der Software-Uhr beein-
' flussen.
#define PAUSE_800MS 80 ' Bit 1 Pausenlänge
#define PAUSE_900MS 90 ' Bit 0 Pausenlänge
#define PAUSE_1800MS 180 ' Letztes Bit 1 Pausenlänge
#define PAUSE_1900MS 190 ' Letztes Bit 0 Pausenlänge
#define PAUSE_ABWEICHUNG 5 ' Pausenlänge Abweichung
' Das DCF77 Telegramm wird in einer ganzen Minute für die Folgeminute
' übertragen. In jeder Sekunde wird ein DCF Bit codiert. Senderseitig
' wird dazu die Sendeleistung 100ms lang für ein 0-Bit oder 200ms lang
' für ein 1-Bit auf 25% abgesenkt. Danach ist für den Rest der Sekunde
' (900ms bzw. 800ms) Pause, also 100% Sendeleistung. Für einen DCF De-
' coder ist das Ende des Telegramms dadurch erkennbar, dass das letzte
' Bit (DCF Bit 58) eine Pause von 1900ms bzw. 1800ms besitzt. Damit
' können die o.g. 4 Pausendauern (PAUSE_XXXMS) unterschieden werden.
' Da der DCF Decoder alle 10ms aufgerufen wird, wird er etwa 80-mal den
' selben Pegel am Eingang feststellen, wenn die Pause nach einem 1-Bit
' gesendet wird.
' Durch "PAUSE_ABWEICHUNG" wird festgelegt, welche Abweichung vom Soll
' zugelassen wird. Beim Wert 5 erkennt der Decoder ein 1-Bit, wenn er
' zwischen 75- und 84-mal (= 750..840ms) den selben Pegel feststellt.
#define VALIDITAETSSTANDARD 1 ' Validitätszähler Grenze
' (1: Jedes DCF Telegramm nutzen!)
' Als INTAKT gilt ein Telegramm, wenn folgende Bedingungen erfüllt sind:
' 1. DCF Bit 0 ist 0
' 2. DCF Bits 17 und 18 sind ungleich
' 3. DCF Bit 20 ist 1
' 4. Die Paritätsbits 28, 35, 58 enthalten eine korrekte gerade Parität
' 5. Es wurden genau 58 DCF Bits decodiert
' 6. Fall Schaltsekunde: DCF Bit 59 ist 0 und DCF Bit 19 ist 1
' Nicht PLAUSIBEL ist ein Telegramm, wenn Werte außerhalb des möglichen
' Bereichs liegen. Ein Wert von 9 für den Wochentag ist z.B. nicht
' plausibel. Allgemeiner könnte man sagen, dass ein DCF Telegramm nicht
' plausibel ist, wenn es nicht die Folgeminute der aktuellen Minute ab-
' bildet.
' Ein Telegramm ist VALIDE (= gültig), wenn es intakt UND plausibel ist.
' Jedes valide DCF Telegramm wird gezählt. Ist VALIDITAETSSTANDARD 1,
' dann wird jedes valide Telegramm zum Stellen der Uhr verwendet. Man
' kann den Wert erhöhen, wenn man ein Stellen der Uhr nur bei sehr guten
' Empfangsbedingungen erlauben will. Setzt man VALIDITAETSSTANDARD z.B.
' auf 3, dann wird ein Telegramm nur dann zum Stellen der Uhr verwendet,
' wenn es das dritte valide Telegramm in Folge ist.
/************************************************** ****************************/
' Variablen:
Dim Jahr As Byte ' Jahr [0..99]
Dim Monat As Byte ' Monat [1..12]
Dim Wochentag As Byte ' Wochentag [1..7 = MO..SO]
Dim Tag As Byte ' Tag [1..31]
Dim Sommerzeit As Byte ' Zeitzone [0 / 1 = MEZ / MESZ]
Dim Stunde As Byte ' Stunde [0..23]
Dim Minute As Byte ' Minute [0..59]
Dim Sekunde As Byte ' Sekunde [0..59]
#ifdef WETTER
Dim Wetter As Word ' Codierte Wetter Informationen
#endif ' (DCF Bits 1..14; Bit 0 immer 0)
Dim dcfflags As Byte ' DCF Flags (DCF Bits 15..20):
#define FLAG_R 1 ' R: Ruf Bit 15 für PTB Angestellte
#define FLAG_A1 2 ' A1: Ankündigung eines Zeitzonenwechsels
#define FLAG_Z1 4 ' Z1: Zeitzone 1 [0 = MEZ, 1 = MESZ]
#define FLAG_Z2 8 ' Z2: Zeitzone 2 [1 = MEZ, 0 = MESZ]
#define FLAG_A2 16 ' A2: Ankündigung einer Schaltsekunde
#define FLAG_S 32 ' S: Start Bit 20 (immer 1)
Dim dcfstatus As Byte ' Status Flags (Bits 0..5 nur lesen!):
#define STATUS_FEHLER 1 ' Telegramm Fehler
#define STATUS_MINPARITAET 2 ' Minutenparität ok
#define STATUS_STDPARITAET 4 ' Stundenparität ok
#define STATUS_DATPARITAET 8 ' Datumsparität ok
#define STATUS_DCFBIT58 16 ' 58 (oder 59) DCF Bits decodiert
#define STATUS_TELEGRAMMINTAKT 32 ' Telegramm intakt
#define STATUS_UHRGESTELLT 64 ' Uhr einmal gestellt
#define STATUS_DCF_AN 128 ' DCF77 Decoder AN
Dim validitaetszaehler As Byte ' Zähler für intakte und
' plausible DCF Telegramme
Dim validitaetsgrenze As Byte ' Grenze Validitäts Zähler
#ifdef DEBUG
Dim pause_1_laenge As Byte
Dim pause_0_laenge As Byte
Dim letztepause_1_laenge As Byte
Dim letztepause_0_laenge As Byte
#endif
/************************************************** ****************************/
' Funktionen:
/**
* INIT DCF
*
* Unbedingt einmal aufrufen, bevor die DCF77 Funktion benutzt wird!
*
*/
Sub initDCF()
Port_DataDirBit(DCF_IN, 0) ' Port = Eingang
Port_WriteBit(DCF_IN, 1) ' Pullup Widerstand ein
validitaetszaehler = 0 ' Validitätszähler zurücksetzen
validitaetsgrenze = VALIDITAETSSTANDARD ' Grenze setzen
dcfstatus = STATUS_DCF_AN ' DCF77 Decoder AN
End Sub
/**
* DCF DECODER AN
*
* Der DCF77 Decoder wird eingeschaltet.
* Immer wenn ein intaktes DCF Telegramm decodiert wurde, kann die
* Uhr mit den aktuellen DCF Informationen gestellt werden.
*
*/
Sub DCFon()
dcfstatus = dcfstatus Or STATUS_DCF_AN ' Status Bit 7 setzen
End Sub
/**
* DCF DECODER AUS
*
* Der DCF77 Decoder wird ausgeschaltet.
* Die Uhr wird durch die interne Referenz (Timer) betrieben.
*
*/
Sub DCFoff()
' Alle Status Bits löschen, nur Status Bit 6 bleibt unverändert:
dcfstatus = dcfstatus And STATUS_UHRGESTELLT
End Sub
/**
* BCD to DEC
*
* Diese Funktion wandelt einen BCD- in einen Dezimalwert um.
*
*/
Sub BCDtoDEC(bcd As Byte) As Byte
Return (bcd >> 4) * 10 + (bcd And 0x0f)
End Sub
Gruß Dirk
P.S.: Teil 2 der Bibliothek folgt!