Hier Teil 2 der Bibliothek:

Bibliothek (RP6DCFCClib.cbas), 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.
 *
 */
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
Gruß Dirk