Hallo Besitzer der Zusatzplatine RP6 CCPRO M128,

die mitgelieferte Library DCF_Lib.cc hat gerade so die basalen Funktionen eines DCF-Decoders. Mit dieser Bibliothek RP6DCFCCLib.cc wird das besser. Viel Spaß damit.

Demo (DCF_RTC.cc):
Code:
/*******************************************************************************
 * 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.cc geändert werden.
 * erforderliche Library: IntFunc_Lib.cc und neue RP6DCFCClib.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 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.cc"

// Die neue RP6DCFCCLib einbinden:
#include "../../RP6CCLib/RP6DCFCClib.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", "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
    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 != Sekunde) {
			alte_sekunde = Sekunde;
#ifndef DEBUG
            showCLOCK();
//            showSTATUS();
#endif
#ifdef DEBUG
            showDEBUGINFO();
#endif
        }
    }
}

//------------------------------------------------------------------------------
// Festlegung von Startzeit und Startdatum
//
void Time_Init(void)
{
    Sekunde = 0;                            // Uhr Startzeit:   12:00:00
    Minute = 0;
    Stunde = 12;
    Wochentag = 7;
    Tag = 31;                               // Uhr Startdatum:  31.05.2009
    Monat = 5;
    Jahr = 9;
}

//------------------------------------------------------------------------------
// 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 (RP6DCFCClib.cc), Teil 1:
Code:
/* ****************************************************************************
 *                           _______________________
 *                           \| RP6  ROBOT SYSTEM |/
 *                            \_-_-_-_-_-_-_-_-_-_/              >>> CCPRO M128
 * ----------------------------------------------------------------------------
 * ----------------------- [c]2009 - Dirk -------------------------------------
 * ****************************************************************************
 * File: RP6DCFCClib.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.
 * 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:

byte Jahr;                              // Jahr      [0..99]
byte Monat;                             // Monat     [1..12]
byte Wochentag;                         // Wochentag [1..7 = MO..SO]
byte Tag;                               // Tag       [1..31]
byte Sommerzeit;                        // Zeitzone  [0 / 1 = MEZ / MESZ]
byte Stunde;                            // Stunde    [0..23]
byte Minute;                            // Minute    [0..59]
byte Sekunde;                           // Sekunde   [0..59]

#ifdef WETTER
unsigned int Wetter;	    			// 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 Uhr wird durch die interne Referenz (Timer) betrieben.
 *
 */
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

P.S.: Teil 2 der Bibliothek folgt!