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
Lesezeichen