Code:
copyright = W.Krueger
comment = DCF77-Decoder und Softclock
libversion = 2.50 (D. Ottensmeyer)
date = 05.09.2006
statement = ----------------------------------
statement = muss alle 25ms ausgeführt werden !
statement = Neu: komplette Paritätsprüfung
statement = Neu: Auswertung der Bits 15..20
statement = Neu: erweiterte Softclock
statement = ----------------------------------
[Dcf77_soft]
.equ DCF_Port = $10 ;$10 = Portd
.equ DCF_Pin = 3 ;3 = Pin 3
.equ Imp0min = 70 ;minimale Länge des Minutenimpulses
.equ Imp1min = 6 ;minimale Länge des "1" Impulses
;alles darunter wird als "0" Impuls gewertet
.def Temp1 = r16
.def Temp2 = r17
.def Status = r18
;Bit0 = aktueller DCF Status
;Bit1 = vorheriger DCF Status
;Bit2 = 58 Impulse empfangen
;Bit3 = Parität OK
;Bit4 = Stundenparität OK
;Bit5 = Uhr nach DCF gestellt
;Bit6 = Datum nach DCF gestellt
;Bit7 = Uhr nach DCF stellen
.def Impulse = r19
.def Counter = r20
.def Buffer = r21
.def Parity = r22
Dcf77_soft:
*lds Status,{Dcfstatus} ;Status laden
rcall Softclock ;Softclock bearbeiten
bst Status,7 ;Status Uhr nach DCF stellen ?
brts Puls0 ;ja -> weiter
*sts {Dcfstatus},Status
ret
;-------------------------------------------------------------------------------
[Dcf77]
.equ DCF_Port = $10 ;$10 = Pind
.equ DCF_Pin = 3 ;3 = Pin 3
.equ Imp0min = 70 ;minimale Länge des Minutenimpulses
.equ Imp1min = 6 ;minimale Länge des "1" Impulses
;alles darunter wird als "0" Impuls gewertet
.def Temp1 = r16
.def Temp2 = r17
.def Status = r18
;Bit0 = aktueller DCF Status
;Bit1 = vorheriger DCF Status
;Bit2 = 58 Impulse empfangen
;Bit3 = Parität OK
;Bit4 = Stundenparität OK
;Bit5 = Uhr nach DCF gestellt
;Bit6 = Datum nach DCF gestellt
;Bit7 = Uhr nach DCF stellen
.def Impulse = r19
.def Counter = r20
.def Buffer = r21
.def Parity = r22
Dcf77:
*lds Status,{Dcfstatus} ;Status laden
bst Status,7 ;Status Uhr nach DCF stellen ?
brts Puls0 ;ja -> weiter
ret
Puls0:
*lds Impulse,{Dcfimpulse} ;Variablen laden
*lds Counter,{Dcfcounter}
*lds Buffer,{Dcfbuffer}
*lds Parity,{Dcfparity}
in temp1,Dcf_Port ;DCF Port lesen
bst temp1,Dcf_Pin ;Status holen
bld Status,0 ;aktuellen Status speichern
inc Counter ;Impulslänge erhöhen
bst Status,0 ;aktuellen Status prüfen
brts Puls20 ;Status Low -> weiter
bst Status,1 ;vorherigen Status prüfen
brtc Puls40 ;vorheriger Status Low -> Ende
ldi temp1,Imp0min ;Minutenimpuls Minimalwert laden
cp Counter,temp1 ;Impulslänge Minimalwert überschritten
brcs Puls10 ;nein -> weiter
*sts {Dcfpau},Counter ;--------> Minutenimpulslänge speichern für Debug
clr Buffer ;Empfangspuffer löschen
clr Impulse ;Impulszähler löschen
bst Status,3 ;Parität OK ?
brtc Puls15 ;Nein -> weiter
bst Status,2 ;58 Impulse empfangen ?
brtc Puls15 ;Nein -> weiter
rcall Stellen ;empfangene Zeit übernehmen
Puls5:
clt
bld Status,2 ;Status 58 Impulse löschen
bld Status,3 ;Status Parität OK löschen
bld Status,4 ;Status Stundenparität OK löschen
Puls10:
clr Counter ;Impulslänge löschen
rjmp Puls40 ;Ende
Puls15:
bst Status,4 ;Stundenparität OK ?
brtc Puls5
rcall Zeitstellen ;nur Uhrzeit übernehmen
rjmp Puls5
Puls20:
bst Status,1 ;vorherigen Status prüfen
brts Puls40 ;vorheriger Status Low -> Ende
ldi temp1,Imp1min ;Minimalwert für "1" Impuls laden
cp Counter,temp1 ;Minimalwert unterschritten ?
brcs Puls30 ;ja -> weiter
*sts {Dcfimp},Counter ;--------> Impulslänge High speichern für Debug
cpi Impulse,28 ;beim Paritätsbit Min keine Negation
breq Puls25
cpi Impulse,35 ;beim Paritätsbit Std keine Negation
breq Puls25
cpi Impulse,58 ;beim Paritätsbit Datum keine Negation
breq Puls25
ldi Temp1,1
eor Parity,Temp1 ;Paritätsbit Negation
Puls25:
sec ;Carry setzen ( "1" empfangen )
ror Buffer ;Carry in Empfangspuffer
rcall Auswerten ;Impulse auswerten
inc Impulse ;Impulszähler erhöhen
rjmp Puls40 ;Ende
Puls30:
*sts {Dcfimp},Counter ;--------> Impulslänge Low speichern für Debug
clc ;Carry löschen ( "0" empfangen )
ror Buffer ;Carry in Empfangspuffer
rcall Auswerten ;Impulse auswerten
inc Impulse ;Impulszähler erhöhen
Puls40:
bst Status,0 ;aktuellen Status holen
bld Status,1 ;Status speichern
*sts {Dcfstatus},Status ;Variablen wieder speichern
*sts {Dcfimpulse},Impulse
*sts {Dcfcounter},Counter
*sts {Dcfbuffer},Buffer
*sts {Dcfparity},Parity
ret
;-------------------------------------------------------------------------------
Softclock: ;muss 40x pro Sekunde aufgerufen werden
*lds Temp1,{Dcfhsec}
inc Temp1 ;Hundertstel Sek erhöhen
cpi Temp1,40 ;1000ms erreicht ?
breq Soft10 ;ja -> weiter
*sts {Dcfhsec},Temp1
ret ;sonst Ende
Soft10:
clr Temp1 ;Hundertstel Sek löschen
*sts {Dcfhsec},Temp1
*lds Temp1,{_sec}
inc Temp1 ;Sekunde erhöhen
cpi Temp1,60 ;60 Sekunden erreicht ?
breq Soft20 ;ja -> weiter
*sts {_sec},Temp1
ret
Soft20:
clr Temp1 ;Sekunde löschen
*sts {_sec},Temp1
*lds Temp1,{_min}
inc Temp1 ;Minute erhöhen
cpi Temp1,60 ;60 Minuten erreicht ?
breq Soft30 ;ja -> weiter
*sts {_min},Temp1
ret
Soft30:
clr Temp1 ;Minute löschen
*sts {_min},Temp1
*lds Temp1,{_hour}
inc Temp1 ;Stunde erhöhen
cpi Temp1,24 ;24 Stunden erreicht ?
breq Soft40 ;ja -> weiter
*sts {_hour},Temp1
ret
Soft40:
clr Temp1 ;Stunde löschen
*sts {_hour},Temp1
*lds Temp1,{_dayofweek}
inc Temp1 ;Wochentag erhöhen
cpi Temp1,8 ;letzter Wochentag erreicht ?
breq Soft50 ;ja -> weiter
*sts {_dayofweek},Temp1
ret
Soft50:
ldi Temp1,1 ;Wochentag auf "1" (Montag)
*sts {_dayofweek},Temp1
*lds Temp1,{_day} ;Tag holen
*lds Temp2,{_month} ;Monat holen
ldi zl,low(Tagdaten*2)
ldi zh,high(Tagdaten*2) ;Anzahl Tage pro Monat holen
add zl,Temp2 ;Zeiger auf aktuellen Monat
lpm ;Anzahl Tage holen
cp Temp1,r0 ;Monatsende erreicht ?
brne Soft90 ;nein -> weiter
cpi Temp2,2 ;Monatsende Februar ?
brne Soft60 ;nein -> weiter
clt ;Evtl. Schaltjahr mit 29.2.
bld Status,6 ;Status Datum nach DCF gestellt löschen
Soft60:
cpi Temp2,6 ;Monatsende Juni ?
brne Soft70 ;nein -> weiter
clt ;Zur Jahresmitte evtl. Schaltsekunde
bld Status,5 ;Status Uhr nach DCF gestellt löschen
Soft70:
ldi Temp1,1 ;Tag auf 1
cpi Temp2,12 ;Jahresende erreicht ?
brne Soft100 ;nein -> weiter
clt ;Zum Jahreswechsel evtl. Schaltsekunde
bld Status,5 ;Status Uhr nach DCF gestellt löschen
*lds Temp2,{_year} ;Jahr holen
inc Temp2 ;Jahr erhöhen
cpi Temp2,100 ;Jahr 100 erreicht ?
brne Soft80 ;nein -> Ende
clr Temp2 ;Jahr 00 setzen
Soft80:
*sts {_year},Temp2 ;speichern
ldi Temp2,1 ;Monat auf 1
rjmp Soft110
Soft90:
inc Temp1 ;Tag erhöhen
rjmp Soft110
Soft100:
inc Temp2 ;Monat erhöhen
Soft110:
*sts {_day},Temp1 ;Datum speichern
*sts {_month},Temp2
ret
Stellen:
*lds Temp1,{Dcftemp+2}
*sts {_day},Temp1 ;Tag auf empfangenen Tag
*lds Temp1,{Dcftemp+3}
*sts {_dayofweek},Temp1 ;Wochentag auf empfangenen Wochentag
*lds Temp1,{Dcftemp+4}
*sts {_month},Temp1 ;Monat auf empfangenen Monat
*lds Temp1,{Dcftemp+5}
*sts {_year},Temp1 ;Jahr auf empfangenes Jahr
set
bld Status,6 ;Status Datum nach DCF gestellt setzen
Zeitstellen:
ldi Temp1,1 ;Hundertstel zurücksetzen
*sts {Dcfhsec},Temp1 ;(1. Intervall 25ms kürzer !)
clr Temp1
*sts {_sec},Temp1 ;Sekunde auf 0 setzen
*lds Temp1,{Dcftemp}
*sts {_min},Temp1 ;Minute auf empfangene Minute
*lds Temp1,{Dcftemp+1}
*sts {_hour},Temp1 ;Stunde auf empfangene Stunde
*lds Temp1,{Dcftemp+6}
*sts {Dcfflags},Temp1 ;DCF77-Bits 15..20 aktualisieren
set
bld Status,5 ;Status Uhr nach DCF gestellt setzen
ret
Tagdaten:
.db 00, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
;-------------------------------------------------------------------------------
Auswerten:
cpi Impulse,14 ;14. Impuls
brne Aus5 ;nein -> weiter
clr Buffer
Aus5:
cpi Impulse,20 ;20. Impuls
brne Aus10 ;nein -> weiter
bst Buffer,7 ;Startbit 20 (S) selektieren
brtc Aus26 ;Fehler -> Ende
lsr Buffer ;Buffer 2x schieben, da 6 Bit
lsr Buffer
*sts {Dcftemp+6},Buffer ;Temp DCF77-Bits 15..20 schreiben
;Inhalt Buffer -> Bit0 (R) : Reserve-Antenne des DCF77-Senders
; Bit1 (A1): Ankündigung des Wechsels MEZ <-> MESZ
; Bit2 (Z1): \__ Z1/Z2: 10 = MESZ, 01 = MEZ
; Bit3 (Z2): /
; Bit4 (A2): Ankündigung einer Schaltsekunde
; Bit5 (S) : Startbit f. Zeitinformationen (immer 1)
clr Buffer
clr Parity
Aus10:
cpi Impulse,27 ;27. Impuls
brne Aus15 ;nein -> weiter
lsr Buffer ;Buffer 1x schieben, da Minute nur 7 Bit
rcall Bcd2dez ;in Dezimal wandeln
*sts {Dcftemp},Buffer ;Temp Minute schreiben
clr Buffer
Aus15:
cpi Impulse,28 ;Minuten Parität
brne Aus20
clr Temp1
bst Buffer,7 ;Paritätsbit selektieren
bld Temp1,0 ;Paritätsbit in Temp1 Bit0 kopieren
cp Temp1,Parity ;Minutenparität überprüfen
brne Aus26 ;Fehler -> Ende
clr Parity
clr Buffer
Aus20:
cpi Impulse,34 ;34. Impuls
brne Aus25 ;nein -> weiter
lsr Buffer ;Buffer 2x schieben, da Stunde nur 6 Bit
lsr Buffer
rcall Bcd2dez ;in Dezimal wandeln
*sts {Dcftemp+1},Buffer ;Temp Stunde schreiben
clr Buffer
Aus25:
cpi Impulse,35 ;Stunden Parität
brne Aus30
clr Temp1
bst Buffer,7 ;Paritätsbit selektieren
bld Temp1,0 ;Paritätsbit in Temp1 Bit0 kopieren
cp Temp1,Parity ;Stundenparität überprüfen
breq Aus27 ;Parität OK -> weiter
Aus26:
ret ;Fehler -> Ende
Aus27:
set
bld Status,4 ;Bit4 Status setzen (Stundenparität)
clr Parity
clr Buffer
Aus30:
cpi Impulse,41 ;41. Impuls
brne Aus40
lsr Buffer ;Buffer 2x schieben, da Tag nur 6 Bit
lsr Buffer
rcall Bcd2dez ;in Dezimal wandeln
*sts {Dcftemp+2},Buffer ;Temp Tag schreiben
clr Buffer
Aus40:
cpi Impulse,44 ;44. Impuls
brne Aus50
lsr Buffer ;Buffer 5x schieben, da Wochentag nur 3 Bit
lsr Buffer
lsr Buffer
lsr Buffer
lsr Buffer
rcall Bcd2dez ;in Dezimal wandeln
*sts {Dcftemp+3},Buffer ;Temp Wochentag schreiben
clr Buffer
Aus50:
cpi Impulse,49 ;49. Impuls
brne Aus60
lsr Buffer ;Buffer 3x schieben, da Monat nur 5 Bit
lsr Buffer
lsr Buffer
rcall Bcd2dez ;in Dezimal wandeln
*sts {Dcftemp+4},Buffer ;Temp Monat schreiben
clr Buffer
Aus60:
cpi Impulse,57 ;57. Impuls
brne Aus70
rcall Bcd2dez ;in Dezimal wandeln
*sts {Dcftemp+5},Buffer ;Temp Jahr schreiben
clr Buffer
Aus70:
cpi Impulse,58 ;Restparität
brne Aus80
set ;T-Bit setzen
bld Status,2 ;Bit2 Status setzen (58 Impulse)
clr Temp1
bst Buffer,7 ;Paritätsbit selektieren
bld Temp1,0 ;Paritätsbit in Temp1 Bit0 kopieren
cp Temp1,Parity ;Restparität überprüfen
brne Aus90 ;Fehler -> Ende
set ;T-Bit setzen
bld Status,3 ;Bit3 Status setzen (Parität)
Aus80:
cpi Impulse,59 ;mehr als 58 Impulse (d.h. Störimpulse)
brne Aus90
clt ;T-Bit löschen
bld Status,2 ;Bit2 Status löschen (58 Impulse)
Aus90:
ret
;-------------------------------------------------------------------------------
Bcd2dez:
mov Temp1,Buffer
andi Temp1,$0F
Bcd10:
subi Buffer,$10
brcs Bcd20
subi Temp1,$F6
rjmp Bcd10
Bcd20:
mov Buffer,Temp1
ret
[end]
Die LIB kann man MIT oder OHNE einen Uhrenquarz an TOSC1/2 verwenden. Ohne Quarz nimmt man einfach DCF77_soft, mit Quarz die Routine DCF77.
Lesezeichen