PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : CCPRO M128: DCF77 Decoder 2 (CompactC)



Dirk
06.06.2009, 14:50
Hier Teil 2 der Bibliothek:

Bibliothek (RP6DCFCClib.cc), Teil 2:

/**
* 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