Hier der 2. Teil:

Bibliothek (RP6DCFClockCClib.cbas), Teil 2:
Code:
/**
 * DCF DECODER
 *
 * Dies ist der DCF77 Decoder.
 *
 * Der (abschaltbare) DCF Decoder in dieser Funktion decodiert die
 * DCF Informationen und stellt die Uhr mit den empfangenen Daten.
 *
 * Die Funktion decodeDCF() muss alle 10ms aufgerufen werden.
 *
 */
Sub decodeDCF()
 Dim temp, dcfbit As Byte
 Static 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
    If (dcfstatus And STATUS_DCF_AN) = 0 Then
        Return                          ' 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 0x0001 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
                        DCF_WEATHER = wetterpuffer
#endif
                        dcfflags = dcfflagspuffer
                        Clock_SetTime(stundepuffer, minutepuffer, 0, _
                         CLOCK_CORR)                       ' Uhr stellen!
                        DCF_DST = sommerzeitpuffer
                        DCF_DOW = wochentagpuffer
                        tagpuffer = tagpuffer - 1          ' Tag und Monat
                        monatpuffer = monatpuffer - 1      ' ... nullbasiert!
                        Clock_SetDate(tagpuffer, monatpuffer, 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()
 Dim temp As Byte
	setCursorPosLCD(0, 1)		' Zeile 1
    temp = Clock_GetVal(CLOCK_HOUR)
	If temp < 10 Then
		printLCD("0")
	End If
	printIntegerLCD(temp)
	printLCD(":")
    temp = Clock_GetVal(CLOCK_MIN)
	If temp < 10 Then
		printLCD("0")
	End If
	printIntegerLCD(temp)
	printLCD(":")
    temp = Clock_GetVal(CLOCK_SEC)
	If temp < 10 Then
		printLCD("0")
	End If
	printIntegerLCD(temp)
	If dcfstatus And STATUS_UHRGESTELLT Then
		If DCF_DST Then 		' MESZ?
			printLCD("  MESZ")
		Else
			printLCD("   MEZ")
		End If
	End If
	setCursorPosLCD(1, 1)		' Zeile 2
	Select Case DCF_DOW         ' 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(", ")
    temp = Clock_GetVal(CLOCK_DAY) + 1  ' Tag nullbasiert!
	If temp < 10 Then
		printLCD("0")
	End If
	printIntegerLCD(temp)
	printLCD(".")
    temp = Clock_GetVal(CLOCK_MON) + 1  ' Monat nullbasiert!
    If temp < 10 Then
		printLCD("0")
	End If
	printIntegerLCD(temp)
	printLCD(".20")
    temp = Clock_GetVal(CLOCK_YEAR)
	If temp < 10 Then
		printLCD("0")
	End If
	printIntegerLCD(temp)
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
    temp = Clock_GetVal(CLOCK_HOUR)
	If temp < 10 Then
		printLCD("0")
	End If
	printIntegerLCD(temp)
	printLCD(":")
    temp = Clock_GetVal(CLOCK_MIN)
	If temp < 10 Then
		printLCD("0")
	End If
	printIntegerLCD(temp)
	printLCD(":")
    temp = Clock_GetVal(CLOCK_SEC)
	If temp < 10 Then
		printLCD("0")
	End If
	printIntegerLCD(temp)
	If dcfstatus And STATUS_UHRGESTELLT Then
		If DCF_DST 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("  ")
	setCursorPosLCD(1, 1)		' Zeile 2
	printLCD("L1/0: ")
	printIntegerLCD(letztepause_1_laenge)
	printLCD(" / ")
	printIntegerLCD(letztepause_0_laenge)
	printLCD("  ")
End Sub
#endif

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

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