Dirk
13.06.2009, 16:44
Hallo Leute,
nach meinem 1. DCF-Decoder mit Softclock hier:
https://www.roboternetz.de/phpBB2/viewtopic.php?t=48432
... und hier:
https://www.roboternetz.de/phpBB2/viewtopic.php?t=48434
... jetzt eine ZWEITE Version in CompactC, die keine eigene Softclock (mit den Variablen Sekunde, Minute, Stunde usw.) mehr hat (so wie in der mitgelieferten DCF_Lib.cc).
Stattdessen nutzt dieser DCF-Decoder die interne Clock des CCPRO-Betriebssystems, die mit den Befehlen Clock_GetVal(), Clock_SetTime() usw. gelesen oder gestellt werden kann.
Viel Spaß damit!
Demoprogramm (RP6_DCFClock.cc):
/************************************************** *****************************
* RP6 C-Control PRO M128 Erweiterungsmodul
* ----------------------------------------------------------------------------
* RP6_DCFClock Testprogramm 1 - CompactC
* ----------------------------------------------------------------------------
* RP6_DCFClock: DCF Uhr
* DCF Empfänger erforderlich
* Mega128: DCF-Eingang PE5 (PortE.5, RP6: INT1)
* Der DCF-Eingang kann in RP6DCFClockCClib.cc geändert werden.
* erforderliche Library: IntFunc_Lib.cc und neue
* RP6DCFClockCClib.cc (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 der internen Clock
* (Anleitung Abschnitt 6.5 Clock), die so oft wie möglich mit den DCF
* Informationen gestellt wird, angezeigt.
* Die LED1 blinkt im Sekundentakt.
*
* ************************************************** ***************************
* Der Roboter bewegt sich in diesem Beispielprogramm NICHT und kann
* am Rechner angeschlossen bleiben!
************************************************** ****************************/
// WICHTIG: Immer die RP6CCLib mit einbinden:
#include "../../RP6CCLib/RP6CCLib.cc"
// Die neue RP6DCFClockCCLib einbinden:
#include "../../RP6CCLib/RP6DCFClockCClib.cc"
int irqcnt; // globale Variablendeklaration
byte cnt1, alte_sekunde;
void main(void)
{
// 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", "RP6 DCF Clock 1");
// 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
while (1) // Endlosschleife
{
if (cnt1 == 50) Port_WriteBit(PORT_LED1, PORT_OFF); // LED1 aus
if (cnt1 == 100) { // Sekundentakt
Port_WriteBit(PORT_LED1, PORT_ON); // LED1 an
cnt1 = 0;
}
if (alte_sekunde != Clock_GetVal(CLOCK_SEC)) {
alte_sekunde = Clock_GetVal(CLOCK_SEC);
#ifndef DEBUG
showCLOCK();
// showSTATUS();
#endif
#ifdef DEBUG
showDEBUGINFO();
#endif
}
}
}
//------------------------------------------------------------------------------
// Festlegung von Startzeit und Startdatum
//
void Time_Init(void)
{
Clock_SetTime(12, 0, 0, CLOCK_CORR); // Uhr Startzeit: 12:00:00
// (CLOCK_CORR ist in der RP6DCFClockCClib definiert!)
Clock_SetDate(30, 4, 9); // Uhr Startdatum: 31.05.2009
// (Tag und Monat sind nullbasiert!)
}
//------------------------------------------------------------------------------
// Interrupt Routine
//
void INT_10ms(void)
{
cnt1++; // Zähler für Blinken der LED1
decodeDCF(); // DCF77 Decoder
irqcnt = Irq_GetCount(INT_TIM2COMP); // Interrupt Request Counter
}
//------------------------------------------------------------------------------
Bibliothek (RP6DCFClockCClib.cc), Teil 1:
/* ************************************************** **************************
* _______________________
* \| RP6 ROBOT SYSTEM |/
* \_-_-_-_-_-_-_-_-_-_/ >>> CCPRO M128
* ----------------------------------------------------------------------------
* ----------------------- [c]2009 - Dirk -------------------------------------
* ************************************************** **************************
* File: RP6DCFClockCClib.cc
* Version: 1.0 - CompactC
* 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, die mit der
* internen Clock (Anleitung Abschnitt 6.5 Clock) zusammen arbeitet.
* Der DCF-Empfänger wird an PE5 (XBUS INT1, SPI_I/O: Pin 7) der CCPRO M128
* angeschlossen.
*
* ANMERKUNG: Ein 10kOhm 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,2kOhm Widerstand.
*
* ************************************************** **************************
* CHANGELOG FINDEN SIE AM ENDE DIESER DATEI!
* ************************************************** **************************
*/
// Alles nur EINMAL einbinden!
#ifndef __RP6DCFCLOCKCCLIB__
#define __RP6DCFCLOCKCCLIB__
/************************************************** ****************************/
// Defines:
// RP6 CCPRO M128 DCF Empfänger Anschluß:
#define DCF_IN 37 // DCF Eingangs Signal 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.
// Korrekturfaktor für die Clock:
#define CLOCK_CORR 0 // Siehe Anleitung Abschnitt 6.5 Clock!
#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:
byte DCF_DOW; // Wochentag [1..7 = MO..SO]
byte DCF_DST; // Zeitzone [0 / 1 = MEZ / MESZ]
#ifdef WETTER
unsigned int DCF_WEATHER; // Codierte Wetter Informationen
#endif // (DCF Bits 1..14; Bit 0 immer 0)
byte dcfflags; // 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)
byte dcfstatus; // 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
byte validitaetszaehler; // Zähler für intakte und
// plausible DCF Telegramme
byte validitaetsgrenze; // Grenze Validitäts Zähler
#ifdef DEBUG
byte pause_1_laenge;
byte pause_0_laenge;
byte letztepause_1_laenge;
byte letztepause_0_laenge;
#endif
/************************************************** ****************************/
// Funktionen:
/**
* INIT DCF
*
* Unbedingt einmal aufrufen, bevor die DCF77 Funktion benutzt wird!
*
*/
void initDCF(void)
{
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
}
/**
* 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.
*
*/
void DCFon(void)
{
dcfstatus = dcfstatus | STATUS_DCF_AN; // Status Bit 7 setzen
}
/**
* DCF DECODER AUS
*
* Der DCF77 Decoder wird ausgeschaltet.
* Die interne Uhr (Clock) läuft weiter.
*
*/
void DCFoff(void)
{
// Alle Status Bits löschen, nur Status Bit 6 bleibt unverändert:
dcfstatus = dcfstatus & STATUS_UHRGESTELLT;
}
/**
* BCD to DEC
*
* Diese Funktion wandelt einen BCD- in einen Dezimalwert um.
*
*/
byte BCDtoDEC(byte bcd)
{
return ((bcd >> 4) * 10 + (bcd & 0x0f));
}
Bibliothek Teil 2 folgt (einfach mit Copy/Paste anfügen)!
Gruß Dirk
nach meinem 1. DCF-Decoder mit Softclock hier:
https://www.roboternetz.de/phpBB2/viewtopic.php?t=48432
... und hier:
https://www.roboternetz.de/phpBB2/viewtopic.php?t=48434
... jetzt eine ZWEITE Version in CompactC, die keine eigene Softclock (mit den Variablen Sekunde, Minute, Stunde usw.) mehr hat (so wie in der mitgelieferten DCF_Lib.cc).
Stattdessen nutzt dieser DCF-Decoder die interne Clock des CCPRO-Betriebssystems, die mit den Befehlen Clock_GetVal(), Clock_SetTime() usw. gelesen oder gestellt werden kann.
Viel Spaß damit!
Demoprogramm (RP6_DCFClock.cc):
/************************************************** *****************************
* RP6 C-Control PRO M128 Erweiterungsmodul
* ----------------------------------------------------------------------------
* RP6_DCFClock Testprogramm 1 - CompactC
* ----------------------------------------------------------------------------
* RP6_DCFClock: DCF Uhr
* DCF Empfänger erforderlich
* Mega128: DCF-Eingang PE5 (PortE.5, RP6: INT1)
* Der DCF-Eingang kann in RP6DCFClockCClib.cc geändert werden.
* erforderliche Library: IntFunc_Lib.cc und neue
* RP6DCFClockCClib.cc (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 der internen Clock
* (Anleitung Abschnitt 6.5 Clock), die so oft wie möglich mit den DCF
* Informationen gestellt wird, angezeigt.
* Die LED1 blinkt im Sekundentakt.
*
* ************************************************** ***************************
* Der Roboter bewegt sich in diesem Beispielprogramm NICHT und kann
* am Rechner angeschlossen bleiben!
************************************************** ****************************/
// WICHTIG: Immer die RP6CCLib mit einbinden:
#include "../../RP6CCLib/RP6CCLib.cc"
// Die neue RP6DCFClockCCLib einbinden:
#include "../../RP6CCLib/RP6DCFClockCClib.cc"
int irqcnt; // globale Variablendeklaration
byte cnt1, alte_sekunde;
void main(void)
{
// 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", "RP6 DCF Clock 1");
// 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
while (1) // Endlosschleife
{
if (cnt1 == 50) Port_WriteBit(PORT_LED1, PORT_OFF); // LED1 aus
if (cnt1 == 100) { // Sekundentakt
Port_WriteBit(PORT_LED1, PORT_ON); // LED1 an
cnt1 = 0;
}
if (alte_sekunde != Clock_GetVal(CLOCK_SEC)) {
alte_sekunde = Clock_GetVal(CLOCK_SEC);
#ifndef DEBUG
showCLOCK();
// showSTATUS();
#endif
#ifdef DEBUG
showDEBUGINFO();
#endif
}
}
}
//------------------------------------------------------------------------------
// Festlegung von Startzeit und Startdatum
//
void Time_Init(void)
{
Clock_SetTime(12, 0, 0, CLOCK_CORR); // Uhr Startzeit: 12:00:00
// (CLOCK_CORR ist in der RP6DCFClockCClib definiert!)
Clock_SetDate(30, 4, 9); // Uhr Startdatum: 31.05.2009
// (Tag und Monat sind nullbasiert!)
}
//------------------------------------------------------------------------------
// Interrupt Routine
//
void INT_10ms(void)
{
cnt1++; // Zähler für Blinken der LED1
decodeDCF(); // DCF77 Decoder
irqcnt = Irq_GetCount(INT_TIM2COMP); // Interrupt Request Counter
}
//------------------------------------------------------------------------------
Bibliothek (RP6DCFClockCClib.cc), Teil 1:
/* ************************************************** **************************
* _______________________
* \| RP6 ROBOT SYSTEM |/
* \_-_-_-_-_-_-_-_-_-_/ >>> CCPRO M128
* ----------------------------------------------------------------------------
* ----------------------- [c]2009 - Dirk -------------------------------------
* ************************************************** **************************
* File: RP6DCFClockCClib.cc
* Version: 1.0 - CompactC
* 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, die mit der
* internen Clock (Anleitung Abschnitt 6.5 Clock) zusammen arbeitet.
* Der DCF-Empfänger wird an PE5 (XBUS INT1, SPI_I/O: Pin 7) der CCPRO M128
* angeschlossen.
*
* ANMERKUNG: Ein 10kOhm 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,2kOhm Widerstand.
*
* ************************************************** **************************
* CHANGELOG FINDEN SIE AM ENDE DIESER DATEI!
* ************************************************** **************************
*/
// Alles nur EINMAL einbinden!
#ifndef __RP6DCFCLOCKCCLIB__
#define __RP6DCFCLOCKCCLIB__
/************************************************** ****************************/
// Defines:
// RP6 CCPRO M128 DCF Empfänger Anschluß:
#define DCF_IN 37 // DCF Eingangs Signal 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.
// Korrekturfaktor für die Clock:
#define CLOCK_CORR 0 // Siehe Anleitung Abschnitt 6.5 Clock!
#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:
byte DCF_DOW; // Wochentag [1..7 = MO..SO]
byte DCF_DST; // Zeitzone [0 / 1 = MEZ / MESZ]
#ifdef WETTER
unsigned int DCF_WEATHER; // Codierte Wetter Informationen
#endif // (DCF Bits 1..14; Bit 0 immer 0)
byte dcfflags; // 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)
byte dcfstatus; // 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
byte validitaetszaehler; // Zähler für intakte und
// plausible DCF Telegramme
byte validitaetsgrenze; // Grenze Validitäts Zähler
#ifdef DEBUG
byte pause_1_laenge;
byte pause_0_laenge;
byte letztepause_1_laenge;
byte letztepause_0_laenge;
#endif
/************************************************** ****************************/
// Funktionen:
/**
* INIT DCF
*
* Unbedingt einmal aufrufen, bevor die DCF77 Funktion benutzt wird!
*
*/
void initDCF(void)
{
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
}
/**
* 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.
*
*/
void DCFon(void)
{
dcfstatus = dcfstatus | STATUS_DCF_AN; // Status Bit 7 setzen
}
/**
* DCF DECODER AUS
*
* Der DCF77 Decoder wird ausgeschaltet.
* Die interne Uhr (Clock) läuft weiter.
*
*/
void DCFoff(void)
{
// Alle Status Bits löschen, nur Status Bit 6 bleibt unverändert:
dcfstatus = dcfstatus & STATUS_UHRGESTELLT;
}
/**
* BCD to DEC
*
* Diese Funktion wandelt einen BCD- in einen Dezimalwert um.
*
*/
byte BCDtoDEC(byte bcd)
{
return ((bcd >> 4) * 10 + (bcd & 0x0f));
}
Bibliothek Teil 2 folgt (einfach mit Copy/Paste anfügen)!
Gruß Dirk