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
Lesezeichen