Hier Teil 2 der Bibliothek:
Bibliothek (RP6DCFCClib.cbas), Teil 2:Gruß DirkCode:/** * 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. * */ Sub decodeDCF() Dim temp, dcfbit As Byte Static irqzaehler, impulsdauer, alterpegel, paritaet As Byte Static dcfbitzaehler, dcfbitpuffer As Byte #ifdef WETTER Static wetterpuffer As Word #endif Static jahrpuffer, monatpuffer, wochentagpuffer, tagpuffer As Byte Static sommerzeitpuffer, stundepuffer, minutepuffer, dcfflagspuffer As Byte ' Softclock: irqzaehler = irqzaehler + 1 ' Wird alle 10ms hochgezählt! If irqzaehler >= UHRABGLEICH Then irqzaehler = 0 Sekunde = Sekunde + 1 If Sekunde > 59 Then Sekunde = 0 Minute = Minute + 1 If Minute > 59 Then Minute = 0 Stunde = Stunde + 1 If Stunde > 23 Then Stunde = 0 Wochentag = Wochentag + 1 If Wochentag > 7 Then Wochentag = 1 End If Tag = Tag + 1 Select Case Monat Case 2 If Jahr And 3 Then temp = 28 Else temp = 29 ' Schaltjahr! End If Case 4 temp = 30 Case 6 temp = 30 Case 9 temp = 30 Case 11 temp = 30 Else temp = 31 End Select If Tag > temp Then Tag = 1 Monat = Monat + 1 If Monat > 12 Then Monat = 1 Jahr = Jahr + 1 End If End If End If End If End If End If ' Ende der Softclock If (dcfstatus And STATUS_DCF_AN) = 0 Then Return ' ... falls DCF Decoder AUS! End If ' DCF77 Decoder: temp = Port_ReadBit(DCF_IN) ' DCF Eingang lesen If temp = alterpegel Then ' Keine Pegeländerung impulsdauer = impulsdauer + 1 If impulsdauer >= (PAUSE_1900MS + (PAUSE_ABWEICHUNG * 3)) Then impulsdauer = 0 dcfstatus = dcfstatus Or STATUS_FEHLER End If 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) Then ' Keine Pegeländerung impulsdauer = impulsdauer + 1 Return End If #endif alterpegel = temp dcfbit = BIT_FEHLER If impulsdauer >= (PAUSE_900MS - PAUSE_ABWEICHUNG) Then If impulsdauer < (PAUSE_900MS + PAUSE_ABWEICHUNG) Then dcfbit = BIT_0 ' Bit 0 decodiert #ifdef DEBUG pause_0_laenge = impulsdauer #endif End If End If If impulsdauer >= (PAUSE_800MS - PAUSE_ABWEICHUNG) Then If impulsdauer < (PAUSE_800MS + PAUSE_ABWEICHUNG) Then dcfbit = BIT_1 ' Bit 1 decodiert paritaet = paritaet + 1 #ifdef DEBUG pause_1_laenge = impulsdauer #endif End If End If If impulsdauer >= (PAUSE_1900MS - PAUSE_ABWEICHUNG) Then If impulsdauer < (PAUSE_1900MS + PAUSE_ABWEICHUNG) Then dcfbit = LETZTESBIT_0 ' Letztes Bit 0 decodiert #ifdef DEBUG letztepause_0_laenge = impulsdauer #endif End If End If If impulsdauer >= (PAUSE_1800MS - PAUSE_ABWEICHUNG) Then If impulsdauer < (PAUSE_1800MS + PAUSE_ABWEICHUNG) Then dcfbit = LETZTESBIT_1 ' Letztes Bit 1 decodiert paritaet = paritaet + 1 #ifdef DEBUG letztepause_1_laenge = impulsdauer #endif End If End If impulsdauer = 0 ' Impulsdauer zurücksetzen If dcfbit <> BIT_FEHLER Then ' Kein DCF Bitfehler dcfbitpuffer = dcfbitpuffer >> 1 ' Puffer nach rechts schieben dcfbitpuffer = dcfbitpuffer Or (dcfbit And 0x80) ' DCF Bit einfügen Select Case dcfbitzaehler #ifdef WETTER Case 7 wetterpuffer = dcfbitpuffer ' Wetter Infos (Bits 0..7) If wetterpuffer And 0x01 Then ' DCF Bit 0 == 1 ? dcfstatus = dcfstatus Or STATUS_FEHLER ' -> Fehler! End If dcfbitpuffer = 0 #endif Case 14 #ifdef WETTER ' Wetter Infos (Bits 8..14) wetterpuffer = wetterpuffer Or (dcfbitpuffer << 7) #endif dcfstatus = dcfstatus And (Not STATUS_TELEGRAMMINTAKT) dcfbitpuffer = 0 Case 20 dcfflagspuffer = dcfbitpuffer >> 2 ' DCF Flags If dcfflagspuffer And FLAG_Z1 Then ' Z1: Zeitzone sommerzeitpuffer = 1 ' [1 = MESZ] If dcfflagspuffer And FLAG_Z2 Then ' Z1 == Z2 ? dcfstatus = dcfstatus Or STATUS_FEHLER ' -> Fehler! End If Else sommerzeitpuffer = 0 ' [0 = MEZ] If (dcfflagspuffer And FLAG_Z2) = 0 Then ' Z1 == Z2 ? dcfstatus = dcfstatus Or STATUS_FEHLER ' -> Fehler! End If End If If (dcfflagspuffer And FLAG_S) = 0 Then ' Start Bit == 0 ? dcfstatus = dcfstatus Or STATUS_FEHLER ' -> Fehler! End If dcfbitpuffer = 0 paritaet = 0 Case 27 minutepuffer = BCDtoDEC(dcfbitpuffer >> 1) ' Minute If minutepuffer > 59 Then ' Minute > 59 ? dcfstatus = dcfstatus Or STATUS_FEHLER ' -> Fehler! End If Case 28 If (paritaet And 1) = 0 Then ' P1: Parität ok ? dcfstatus = dcfstatus Or STATUS_MINPARITAET End If dcfbitpuffer = 0 paritaet = 0 Case 34 stundepuffer = BCDtoDEC(dcfbitpuffer >> 2) ' Stunde If stundepuffer > 23 Then ' Stunde > 23 ? dcfstatus = dcfstatus Or STATUS_FEHLER ' -> Fehler! End If Case 35 If (paritaet And 1) = 0 Then ' P2: Parität ok ? dcfstatus = dcfstatus Or STATUS_STDPARITAET End If dcfbitpuffer = 0 paritaet = 0 Case 41 tagpuffer = BCDtoDEC(dcfbitpuffer >> 2) ' Tag If (tagpuffer = 0) Or (tagpuffer > 31) Then dcfstatus = dcfstatus Or STATUS_FEHLER ' -> Fehler! End If dcfbitpuffer = 0 Case 44 wochentagpuffer = dcfbitpuffer >> 5 ' Wochentag If (wochentagpuffer = 0) Or (wochentagpuffer > 7) Then dcfstatus = dcfstatus Or STATUS_FEHLER ' -> Fehler! End If dcfbitpuffer = 0 Case 49 monatpuffer = BCDtoDEC(dcfbitpuffer >> 3) ' Monat If (monatpuffer = 0) Or (monatpuffer > 12) Then dcfstatus = dcfstatus Or STATUS_FEHLER ' -> Fehler! End If dcfbitpuffer = 0 Case 57 jahrpuffer = BCDtoDEC(dcfbitpuffer) ' Jahr If jahrpuffer > 99 Then dcfstatus = dcfstatus Or STATUS_FEHLER ' -> Fehler! End If Case 58 dcfstatus = dcfstatus Or STATUS_DCFBIT58 If (paritaet And 1) = 0 Then ' P3: Parität ok ? dcfstatus = dcfstatus Or STATUS_DATPARITAET End If Case 59 ' Schaltsekundenbit If (dcfbitpuffer And 0x80) _ Or ((dcfflagspuffer And FLAG_A2) = 0) Then dcfstatus = dcfstatus Or STATUS_FEHLER ' -> Fehler! End If Case 60 ' Mehr als 59 Bits? dcfstatus = dcfstatus And (Not STATUS_DCFBIT58) ' -> Fehler! End Select If dcfbit And LETZTESBIT_0 Then ' Ein letztes Bit (Telegrammende): If (dcfstatus And (Not (STATUS_TELEGRAMMINTAKT _ Or STATUS_UHRGESTELLT Or STATUS_DCF_AN))) _ = (STATUS_MINPARITAET Or STATUS_STDPARITAET _ Or STATUS_DATPARITAET Or STATUS_DCFBIT58) Then ' T. fehlerfrei? dcfstatus = dcfstatus Or STATUS_TELEGRAMMINTAKT ' Ja! validitaetszaehler = validitaetszaehler + 1 If validitaetszaehler >= validitaetsgrenze Then 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 Or STATUS_UHRGESTELLT End If Else ' Telegramm NICHT intakt oder plausibel: validitaetszaehler = 0 ' Validitätszähler zurücksetzen End If ' Vorbereitung auf nächstes DCF Telegramm: dcfstatus = dcfstatus And (Not (STATUS_FEHLER _ Or STATUS_MINPARITAET Or STATUS_STDPARITAET _ Or STATUS_DATPARITAET Or STATUS_DCFBIT58)) ' Status Bits = 0 dcfbitpuffer = 0 dcfbitzaehler = 0 Else ' Kein Telegramm Ende: dcfbitzaehler = dcfbitzaehler + 1 ' Nächstes DCF Bit decodieren End If End If ' Kein DCF Bitfehler End If ' Pegeländerung am Eingang End Sub /******************************************************************************/ ' Nützliche LCD Funktionen: /** * SHOW CLOCK * * Format: Uhrzeit * Datum * */ Sub showCLOCK() setCursorPosLCD(0, 1) ' Zeile 1 If Stunde < 10 Then printLCD("0") End If printIntegerLCD(Stunde) printLCD(":") If Minute < 10 Then printLCD("0") End If printIntegerLCD(Minute) printLCD(":") If Sekunde < 10 Then printLCD("0") End If printIntegerLCD(Sekunde) If dcfstatus And STATUS_UHRGESTELLT Then If Sommerzeit Then ' MESZ? printLCD(" MESZ") Else printLCD(" MEZ") End If End If setCursorPosLCD(1, 1) ' Zeile 2 Select Case Wochentag Case 1 printLCD("Mo") Case 2 printLCD("Di") Case 3 printLCD("Mi") Case 4 printLCD("Do") Case 5 printLCD("Fr") Case 6 printLCD("Sa") Case 7 printLCD("So") Else printLCD("--") End Select printLCD(", ") If Tag < 10 Then printLCD("0") End If printIntegerLCD(Tag) printLCD(".") If Monat < 10 Then printLCD("0") End If printIntegerLCD(Monat) printLCD(".20") If Jahr < 10 Then printLCD("0") End If printIntegerLCD(Jahr) End Sub /** * SHOW STATUS * * Format: Status * Uhrzeit * */ Sub showSTATUS() Dim i As Integer Dim temp As Byte setCursorPosLCD(0, 1) ' Zeile 1 printLCD("Stat: ") temp = dcfstatus For i = 0 To 7 If temp And 0x80 Then printLCD("1") Else printLCD("0") End If temp = temp << 1 Next setCursorPosLCD(1, 1) ' Zeile 2 If Stunde < 10 Then printLCD("0") End If printIntegerLCD(Stunde) printLCD(":") If Minute < 10 Then printLCD("0") End If printIntegerLCD(Minute) printLCD(":") If Sekunde < 10 Then printLCD("0") End If printIntegerLCD(Sekunde) If dcfstatus And STATUS_UHRGESTELLT Then If (Sommerzeit) Then ' MESZ? printLCD(" MESZ") Else printLCD(" MEZ") End If End If End Sub #ifdef DEBUG /** * SHOW DEBUG INFO * */ Sub showDEBUGINFO() setCursorPosLCD(0, 1) ' Zeile 1 printLCD("P1/0: ") printIntegerLCD(pause_1_laenge) printLCD(" / ") printIntegerLCD(pause_0_laenge) printLCD(" ") printLCD(" ") setCursorPosLCD(1, 1) ' Zeile 2 printLCD("L1/0: ") printIntegerLCD(letztepause_1_laenge) printLCD(" / ") printIntegerLCD(letztepause_0_laenge) printLCD(" ") printLCD(" ") End Sub #endif /****************************************************************************** * Info * **************************************************************************** * Changelog: * - v. 1.0 (initial release) 06.06.2009 by Dirk * * **************************************************************************** */ /*****************************************************************************/ ' EOF







Zitieren

Lesezeichen