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):
Bibliothek (RP6DCFClockCClib.cc), Teil 1:Code:/******************************************************************************* * 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 Teil 2 folgt (einfach mit Copy/Paste anfügen)!Code:/* **************************************************************************** * _______________________ * \| 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)); }
Gruß Dirk







Zitieren

Lesezeichen