Hier Teil 2 der Bibliothek:

Bibliothek (RP6DCFCClib.cc), Teil 2:
Code:
/**
 * DCF DECODER
 *
 * Dies ist die Softclock und der DCF77 Decoder.
 * Den Begriff "Softclock" könnte man mit "Software-Uhr" übersetzen.
 * Sie ermöglicht, dass die Zeit weiter läuft, wenn der DCF Decoder
 * ausgeschaltet ist oder kein DCF Empfang möglich ist. Der Nachteil
 * einer Softclock ist, dass die Uhrzeit verloren geht, wenn der
 * Microcontroller ausgeschaltet wird. Wenn man das vermeiden will,
 * muss man eine Real-Time-Clock (RTC, Echtzeituhr) verwenden. Für
 * den I2C-Bus gibt es z.B. die RTC PCF8583P, die gut geeignet ist.
 *
 * Der (abschaltbare) DCF Decoder in dieser Funktion decodiert die
 * DCF Informationen und stellt die Uhr mit den empfangenen Daten.
 *
 * Die Funktion decodeDCF() muss alle 10 ms aufgerufen werden.
 *
 */
void decodeDCF(void)
{byte temp, dcfbit;
 static byte irqzaehler, impulsdauer, alterpegel, paritaet;
 static byte dcfbitzaehler, dcfbitpuffer;
#ifdef WETTER
 static unsigned int wetterpuffer;
#endif
 static byte jahrpuffer, monatpuffer, wochentagpuffer, tagpuffer;
 static byte sommerzeitpuffer, stundepuffer, minutepuffer, dcfflagspuffer;
    // Softclock:
    irqzaehler++;                       // Wird alle 10ms hochgezählt!
    if (irqzaehler >= UHRABGLEICH) {
        irqzaehler = 0;
        Sekunde++;
        if (Sekunde > 59) {
            Sekunde = 0;
            Minute++;
            if (Minute > 59) {
                Minute = 0;
                Stunde++;
                if (Stunde > 23) {
                    Stunde = 0;
                    Wochentag++;
                    if (Wochentag > 7) {
                        Wochentag = 1;
                    }
                    Tag++;
                    switch (Monat) {
                        case 2 :
                            if (Jahr & 3) {
                                temp = 28;
                            }
                            else {
                                temp = 29; // Schaltjahr!
                            }
                            break;
                        case 4 : temp = 30; break;
                        case 6 : temp = 30; break;
                        case 9 : temp = 30; break;
                        case 11 : temp = 30; break;
                        default : temp = 31;
                    }
                    if (Tag > temp) {
                        Tag = 1;
                        Monat++;
                        if (Monat > 12) {
                            Monat = 1;
                            Jahr++;
                        }
                    }
                }
            }
        }
    }                                   // Ende der Softclock
    if (!(dcfstatus & STATUS_DCF_AN)) {
        return;                         // ... falls DCF Decoder AUS!
    }
    // DCF77 Decoder:
    temp = Port_ReadBit(DCF_IN);        // DCF Eingang lesen
    if (temp == alterpegel) {           // Keine Pegeländerung
        impulsdauer++;
        if (impulsdauer >= (PAUSE_1900MS + (PAUSE_ABWEICHUNG * 3))) {
            impulsdauer = 0;
            dcfstatus = dcfstatus | STATUS_FEHLER;
        }
        return;                         // Ende DCF Decoder!
    }
    else {                              // Pegeländerung am Eingang
#ifdef REPARATUR
        // Nach 1ms Port neu lesen zum Erkennen von "Spikes":
        // (Spikes sind kurze Störsignale von elektr. Geräten)
        AbsDelay(1);                    // 1ms Verzögerung
        if (temp != Port_ReadBit(DCF_IN)) { // Keine Pegeländerung
            impulsdauer++;
	        return;
        }
#endif
        alterpegel = temp;
        dcfbit = BIT_FEHLER;
        if ((impulsdauer >= (PAUSE_900MS - PAUSE_ABWEICHUNG))
         && (impulsdauer < (PAUSE_900MS + PAUSE_ABWEICHUNG))) {
            dcfbit = BIT_0;             // Bit 0 decodiert
#ifdef DEBUG
            pause_0_laenge = impulsdauer;
#endif
        }
        if ((impulsdauer >= (PAUSE_800MS - PAUSE_ABWEICHUNG))
         && (impulsdauer < (PAUSE_800MS + PAUSE_ABWEICHUNG))) {
            dcfbit = BIT_1;             // Bit 1 decodiert
            paritaet++;
#ifdef DEBUG
            pause_1_laenge = impulsdauer;
#endif
        }
        if ((impulsdauer >= (PAUSE_1900MS - PAUSE_ABWEICHUNG))
         && (impulsdauer < (PAUSE_1900MS + PAUSE_ABWEICHUNG))) {
            dcfbit = LETZTESBIT_0;      // Letztes Bit 0 decodiert
#ifdef DEBUG
            letztepause_0_laenge = impulsdauer;
#endif
        }
        if ((impulsdauer >= (PAUSE_1800MS - PAUSE_ABWEICHUNG))
         && (impulsdauer < (PAUSE_1800MS + PAUSE_ABWEICHUNG))) {
            dcfbit = LETZTESBIT_1;      // Letztes Bit 1 decodiert
            paritaet++;
#ifdef DEBUG
        	letztepause_1_laenge = impulsdauer;
#endif
		}
		impulsdauer = 0;					  // Impulsdauer zurücksetzen
		if (dcfbit != BIT_FEHLER) {           // Kein DCF Bitfehler
            dcfbitpuffer = dcfbitpuffer >> 1; // Puffer nach rechts schieben
            dcfbitpuffer = dcfbitpuffer | (dcfbit & 0x80); // DCF Bit einfügen
			switch (dcfbitzaehler) {
#ifdef WETTER
				case  7 :
					wetterpuffer = dcfbitpuffer; // Wetter Infos (Bits 0..7)
                    if (wetterpuffer & 0x01) {             // DCF Bit 0 == 1 ?
                        dcfstatus = dcfstatus | STATUS_FEHLER;     // -> Fehler!
                    }
					dcfbitpuffer = 0; break;
#endif
				case 14 :
#ifdef WETTER                                    // Wetter Infos (Bits 8..14)
					wetterpuffer = wetterpuffer | (dcfbitpuffer << 7);
#endif
					dcfstatus = dcfstatus & (~STATUS_TELEGRAMMINTAKT);
                    dcfbitpuffer = 0; break;
				case 20 :
					dcfflagspuffer = dcfbitpuffer >> 2;    // DCF Flags
                    if (dcfflagspuffer & FLAG_Z1) {        // Z1: Zeitzone
                        sommerzeitpuffer = 1;              // [1 = MESZ]
                        if (dcfflagspuffer & FLAG_Z2) {    // Z1 == Z2 ?
                            dcfstatus = dcfstatus | STATUS_FEHLER; // -> Fehler!
                        }
                    }
                    else {
                        sommerzeitpuffer = 0;              // [0 = MEZ]
                        if (!(dcfflagspuffer & FLAG_Z2)) { // Z1 == Z2 ?
                            dcfstatus = dcfstatus | STATUS_FEHLER; // -> Fehler!
                        }
                    }
					if (!(dcfflagspuffer & FLAG_S)) {      // Start Bit == 0 ?
						dcfstatus = dcfstatus | STATUS_FEHLER;     // -> Fehler!
					}
                    dcfbitpuffer = 0;
					paritaet = 0; break;
				case 27 :
					minutepuffer = BCDtoDEC(dcfbitpuffer >> 1); // Minute
					if (minutepuffer > 59) {               // Minute > 59 ?
						dcfstatus = dcfstatus | STATUS_FEHLER;     // -> Fehler!
					}
                    break;
                case 28 :
					if (!(paritaet & 1)) {                 // P1: Parität ok ?
                        dcfstatus = dcfstatus | STATUS_MINPARITAET;
                    }
                    dcfbitpuffer = 0;
					paritaet = 0; break;
				case 34 :
					stundepuffer = BCDtoDEC(dcfbitpuffer >> 2); // Stunde
					if (stundepuffer > 23) {               // Stunde > 23 ?
						dcfstatus = dcfstatus | STATUS_FEHLER;     // -> Fehler!
					}
                    break;
                case 35 :
					if (!(paritaet & 1)) {                 // P2: Parität ok ?
                        dcfstatus = dcfstatus | STATUS_STDPARITAET;
                    }
                    dcfbitpuffer = 0;
					paritaet = 0; break;
				case 41 :
					tagpuffer = BCDtoDEC(dcfbitpuffer >> 2); // Tag
					if ((tagpuffer == 0) || (tagpuffer > 31)) {
						dcfstatus = dcfstatus | STATUS_FEHLER;     // -> Fehler!
					}
					dcfbitpuffer = 0; break;
				case 44 :
					wochentagpuffer = dcfbitpuffer >> 5;   // Wochentag
					if ((wochentagpuffer == 0) || (wochentagpuffer > 7)) {
						dcfstatus = dcfstatus | STATUS_FEHLER;     // -> Fehler!
					}
					dcfbitpuffer = 0; break;
				case 49 :
					monatpuffer = BCDtoDEC(dcfbitpuffer >> 3); // Monat
					if ((monatpuffer == 0) || (monatpuffer > 12)) {
						dcfstatus = dcfstatus | STATUS_FEHLER;     // -> Fehler!
					}
					dcfbitpuffer = 0; break;
				case 57 :
					jahrpuffer = BCDtoDEC(dcfbitpuffer);   // Jahr
					if (jahrpuffer > 99) {
						dcfstatus = dcfstatus | STATUS_FEHLER;     // -> Fehler!
					}
                    break;
                case 58 :
                    dcfstatus = dcfstatus | STATUS_DCFBIT58;
					if (!(paritaet & 1)) {                 // P3: Parität ok ?
                        dcfstatus = dcfstatus | STATUS_DATPARITAET;
                    }
                    break;
				case 59 :                                  // Schaltsekundenbit
					if ((dcfbitpuffer & 0x80) || (!(dcfflagspuffer & FLAG_A2))) {
						dcfstatus = dcfstatus | STATUS_FEHLER;     // -> Fehler!
					}
					break;
				case 60 :                                  // Mehr als 59 Bits?
                    dcfstatus = dcfstatus & (~STATUS_DCFBIT58);    // -> Fehler!
			}
			if (dcfbit & LETZTESBIT_0) { // Ein letztes Bit (Telegrammende):
				if ((!(dcfstatus & STATUS_FEHLER))
                 && (dcfstatus & STATUS_MINPARITAET)
				 && (dcfstatus & STATUS_STDPARITAET)
                 && (dcfstatus & STATUS_DATPARITAET)
				 && (dcfstatus & STATUS_DCFBIT58)) { // Telegramm fehlerfrei?
					dcfstatus = dcfstatus | STATUS_TELEGRAMMINTAKT; // Ja!
					validitaetszaehler++;
					if (validitaetszaehler >= validitaetsgrenze) {
						validitaetszaehler = validitaetsgrenze;
#ifdef WETTER
                        Wetter = wetterpuffer;
#endif
                        dcfflags = dcfflagspuffer;
                        irqzaehler = 0;
                        Sekunde = 0;                       // Uhr stellen!
                        Minute = minutepuffer;
                        Stunde = stundepuffer;
                        Sommerzeit = sommerzeitpuffer;
                        Tag = tagpuffer;
                        Wochentag = wochentagpuffer;
                        Monat = monatpuffer;
                        Jahr = jahrpuffer;
						dcfstatus = dcfstatus | STATUS_UHRGESTELLT;
					}
				}
				else {			 // Telegramm NICHT intakt oder plausibel:
					validitaetszaehler = 0; // Validitätszähler zurücksetzen
				}
                // Vorbereitung auf nächstes DCF Telegramm:
                dcfstatus = dcfstatus & (~(STATUS_FEHLER | STATUS_MINPARITAET
                 | STATUS_STDPARITAET | STATUS_DATPARITAET
                 | STATUS_DCFBIT58));       // 5 Status Bits löschen
                dcfbitpuffer = 0;
				dcfbitzaehler = 0;
			}
			else {               // Kein Telegramm Ende:
				dcfbitzaehler++; // Nächstes DCF Bit decodieren
			}
		} // Kein DCF Bitfehler
	} // Pegeländerung am Eingang
}

/******************************************************************************/
// Nützliche LCD Funktionen:

/**
 * SHOW CLOCK
 *
 * Format: Uhrzeit
 *         Datum
 *
 */
void showCLOCK(void)
{
	setCursorPosLCD(0, 1);		// Zeile 1
	if (Stunde < 10) {
		writeCharLCD('0');
	}
	printIntegerLCD(Stunde);
	writeCharLCD(':');
	if (Minute < 10) {
		writeCharLCD('0');
	}
	printIntegerLCD(Minute);
	writeCharLCD(':');
	if (Sekunde < 10) {
		writeCharLCD('0');
	}
	printIntegerLCD(Sekunde);
	if (dcfstatus & STATUS_UHRGESTELLT) {
		if (Sommerzeit) {		// MESZ?
			printLCD("  MESZ");
		}
		else {
			printLCD("   MEZ");
		}
	}
	setCursorPosLCD(1, 1);		// Zeile 2
	switch (Wochentag) {
		case 1 : printLCD("Mo"); break;
		case 2 : printLCD("Di"); break;
		case 3 : printLCD("Mi"); break;
		case 4 : printLCD("Do"); break;
		case 5 : printLCD("Fr"); break;
		case 6 : printLCD("Sa"); break;
		case 7 : printLCD("So"); break;
		default : printLCD("--");
	}
	printLCD(", ");
	if (Tag < 10) {
		writeCharLCD('0');
	}
	printIntegerLCD(Tag);
	writeCharLCD('.');
	if (Monat < 10) {
		writeCharLCD('0');
	}
	printIntegerLCD(Monat);
	printLCD(".20");
	if (Jahr < 10) {
		writeCharLCD('0');
	}
	printIntegerLCD(Jahr);
}

/**
 * SHOW STATUS
 *
 * Format: Status
 *         Uhrzeit
 *
 */
void showSTATUS(void)
{byte i, temp;
	setCursorPosLCD(0, 1);		// Zeile 1
	printLCD("Stat: ");
    temp = dcfstatus;
    for(i = 0; i < 8; i++) {
        if (temp & 0x80) {
            writeCharLCD('1');
        }
        else {
            writeCharLCD('0');
        }
        temp = temp << 1;
    }
	setCursorPosLCD(1, 1);		// Zeile 2
	if (Stunde < 10) {
		writeCharLCD('0');
	}
	printIntegerLCD(Stunde);
	writeCharLCD(':');
	if (Minute < 10) {
		writeCharLCD('0');
	}
	printIntegerLCD(Minute);
	writeCharLCD(':');
	if (Sekunde < 10) {
		writeCharLCD('0');
	}
	printIntegerLCD(Sekunde);
	if (dcfstatus & STATUS_UHRGESTELLT) {
		if (Sommerzeit) {		// MESZ?
			printLCD("  MESZ");
		}
		else {
			printLCD("   MEZ");
		}
	}
}

#ifdef DEBUG
/**
 * SHOW DEBUG INFO
 *
 */
void showDEBUGINFO(void)
{
	setCursorPosLCD(0, 1);		// Zeile 1
	printLCD("P1/0: ");
	printIntegerLCD(pause_1_laenge);
	printLCD(" / ");
	printIntegerLCD(pause_0_laenge);
	writeCharLCD(' ');
	writeCharLCD(' ');
	setCursorPosLCD(1, 1);		// Zeile 2
	printLCD("L1/0: ");
	printIntegerLCD(letztepause_1_laenge);
	printLCD(" / ");
	printIntegerLCD(letztepause_0_laenge);
	writeCharLCD(' ');
	writeCharLCD(' ');
}
#endif

/******************************************************************************
 * Info
 * ****************************************************************************
 * Changelog:
 * - v. 1.0 (initial release) 06.06.2009 by Dirk
 *
 * ****************************************************************************
 */

/*****************************************************************************/
// EOF
Gruß Dirk