Code:
copyright = Dirk
comment = DCF77-Decoder und Softclock
libversion = 4.11
date = 15.01.2010
statement = ----------------------------------
statement = Version 4.11:
statement = !
statement = Version 4.10:
statement = Jahr: BCD->DEZ-Fehler korrigiert!
statement = Version 4.00:
statement = Komplette Paritätsprüfung
statement = Auswertung der DCF77-Bits 15..20
statement = NEU: DCF77-Bit 20 - Prüfung!
statement = NEU: Schaltsekunde decodiert!
statement = NEU: DCF77-Bits 0..14 erfasst!
statement = NEU: Plausibilitäts-Check!
statement = NEU: Validitäts-Zähler!
statement = ----------------------------------
[Dcf77_soft]
;Eingang für DCF77-Empfänger-Anschluss:
.equ PIND = &H10 ;Pind
.equ PIND3 = 3 ;3 = Pin 3
;Timer-Interruptfrequenz:
.equ ISR_freq = 40 ;40 Hz
;Grenzwerte für Pausenzeit-Zähler (/ ISR_freq [s]):
.equ LastBit0Max = 79 ;LastBit 0 obere Zeitgrenze + 1
.equ LastBit_Mid = 75 ;LastBit-Grenze
.equ LastBit1Min = 71 ;LastBit 1 untere Zeitgrenze
.equ DataBit0Max = 39 ;Datenbit 0 obere Zeitgrenze + 1
.equ DataBit_Mid = 35 ;Datenbit-Grenze
.equ DataBit1Min = 31 ;Datenbit 1 untere Zeitgrenze
.equ Spike_Limit = 3 ;Störimpulsgrenze
;Validitäts-Zähler Limit:
.equ Val_Limit = 1 ;Jedes Telegramm ist gültig
.def Status = r16
;Bit0 = 15. Impuls erreicht
;Bit1 = Minutenparität OK
;Bit2 = Stundenparität OK
;Bit3 = Parität OK
;Bit4 = 58 Impulse empfangen
;Bit5 = Gültiges DCF77-Telegramm
;Bit6 = Softclock nach DCF gestellt
;Bit7 = DCF-Decoder EIN
.def Counter = r17
.def Parity = r18
.def Impulse = r19
.def Shifter = r20
Dcf77_soft:
*lds Status,{Dcfstatus} ;Status laden
rcall Softclock ;Softclock bearbeiten
rjmp dcf77_start
;-------------------------------------------------------------------------------
[Dcf77]
$EXTERNAL Dcf77_soft
Dcf77:
*lds Status,{Dcfstatus} ;Status laden
dcf77_start:
*lds Counter,{DCF77Counter} ;Pausenzeit-Zähler laden
*lds Parity,{DCF77Parity} ;Fehler-Flag + 1-Zähler laden
sbis PIND,PIND3 ;Input-Pin für DCF-Empfänger
rjmp dcf77_5 ;low: Bit auswerten!
inc Counter ;high: Pausenzeit zählen!
brne dcf77_3
dcf77_1:
sbr Parity,&B10000000 ;Fehler-Flag setzen
*sts {DCF77Parity},Parity
andi Status,&B11000000 ;Statusbits 0..5 löschen
dcf77_2:
clr Counter ;Pausenzeit-Zähler zurücksetzen
dcf77_3:
*sts {DCF77Counter},Counter
*sts {Dcfstatus},Status
dcf77_4:
ret
dcf77_5:
tst Counter ;Auswertung fertig?
breq dcf77_4 ;ja: Ende!
*lds Impulse,{DCF77Impulse} ;nein: Auswerten!
*lds Shifter,{DCF77Shifter}
*lds ZL,{DCF77TAL}
*lds ZH,{DCF77TAH}
cpi Counter,LastBit0Max ;LastBit 0 obere Zeitgrenze + 1
brsh dcf77_1 ;überschritten: Fehler
cpi Counter,LastBit_Mid ;LastBit-Grenze
brlo dcf77_6
rjmp dcf77_20 ;75..78 = LastBit0
dcf77_6:
cpi Counter,LastBit1Min ;LastBit 1 untere Zeitgrenze
brlo dcf77_7
rjmp dcf77_19 ;71..74 = LastBit1
dcf77_7:
sbrc Parity,7 ;wenn Fehler aufgetreten, ...
rjmp dcf77_2 ;... dann Abbruch!
cpi Counter,Spike_Limit ;Störimpulsgrenze
brlo dcf77_2 ;Störimpuls wird ignoriert
cpi Counter,DataBit0Max ;Datenbit 0 obere Zeitgrenze + 1
brsh dcf77_1 ;überschritten: Fehler
cpi Counter,DataBit1Min ;Datenbit 1 untere Zeitgrenze
brlo dcf77_1 ;unterschritten: Fehler
*sts {DCF77Databit},Counter ;DataBit0/1-Pausenlänge für Debug
cpi Counter,DataBit_Mid ;Datenbit-Grenze
brlo dcf77_8 ;Bit1!
cpi Impulse,20 ;DataBit = 0 (35..38):
breq dcf77_2 ;Bit 20 = 0: Abbruch!
cpi Impulse,58 ;P3 (= 0) bei Schaltsekunde?
breq dcf77_2 ;Abbruch: LastBit 59 (= 0) folgt!
rjmp dcf77_10 ;andere 0-Bits: weiter
dcf77_8: ;DataBit = 1 (31..34):
cpi Impulse,21 ;DCF77-Bits 0..20 (= 1)?
brlo dcf77_9 ;keine Parität!
inc Parity ;sonst alle 1-Bits zählen
*sts {DCF77Parity},Parity
cpi Impulse,28
breq dcf77_10 ;Minutenparitätsbit nicht addieren!
cpi Impulse,35
breq dcf77_10 ;Stundenparitätsbit nicht addieren!
cpi Impulse,58 ;P3 (= 1) bei Schaltsekunde?
breq dcf77_2 ;Abbruch: LastBit 59 (= 0) folgt!
dcf77_9:
ld Counter,Z ;Counter = aktuelle DCF77Buffer Zelle
add Counter,Shifter ;addiere 1 an der aktuellen Bitposition
st Z,Counter ;zurückspeichern
dcf77_10:
lsl Shifter ;Shifter auf nächste Bitposition
*sts {DCF77Shifter},Shifter
cpi Impulse,7
brlo dcf77_16 ;DCF77-Bits 0..7 Zyklus
breq dcf77_15 ;letztes Bit 0..7 Zyklus
cpi Impulse,14
brlo dcf77_16 ;DCF77-Bits 8..14 Zyklus
brne dcf77_11
andi Status,&B11000111 ;Statusbits 3..5 löschen
sbr Status,&B00000001 ;Status 15. Impuls erreicht setzen
rjmp dcf77_15 ;letztes Bit 8..14 Zyklus
dcf77_11:
cpi Impulse,20
brlo dcf77_16 ;DCF77-Bits 15..20 Zyklus
breq dcf77_15 ;letztes Bit (DCF77-Bit 20)
cpi Impulse,28
brlo dcf77_16 ;Minuten-Zyklus
breq dcf77_17 ;Minutenparität
cpi Impulse,35
brlo dcf77_16 ;Stunden-Zyklus
breq dcf77_17 ;Stundenparität
cpi Impulse,41
brlo dcf77_16
breq dcf77_12 ;letztes Bit TAG
cpi Impulse,44
brlo dcf77_16
breq dcf77_12 ;letztes Bit WOCHENTAG
cpi Impulse,49
brlo dcf77_16
breq dcf77_12 ;letztes Bit MONAT
cpi Impulse,57
brne dcf77_16 ;nicht letztes Bit JAHR
dcf77_12: ;DCF77Buffer Zelle in DEZ wandeln:
ld Counter,Z ;Counter = aktuelle DCF77Buffer Zelle
mov Shifter,Counter ;Counter (BCD)
andi Shifter,&H0F
dcf77_13:
subi Counter,&H10
brcs dcf77_14
subi Shifter,&HF6
rjmp dcf77_13
dcf77_14: ;-> Shifter (DEZ)
st Z,Shifter ;DEZ in Zelle zurückspeichern
cpi Impulse,57
breq dcf77_16 ;letztes Bit JAHR
dcf77_15: ;aktuelle DCF77Buffer Zelle fertig:
ldi Shifter,1 ;Bitposition zurücksetzen
adiw ZL,1 ;nächste DCF77Buffer Zelle
*sts {DCF77Shifter},Shifter
*sts {DCF77TAL},ZL ;Adresse der nächsten Zelle speichern
*sts {DCF77TAH},ZH
dcf77_16:
inc Impulse ;nächstes DCF77-Bit
*sts {DCF77Impulse},Impulse
rjmp dcf77_2
dcf77_17: ;Parität Min./Std. Auswertung:
sbrc Parity,0
rjmp dcf77_2 ;Parität Fehler: Abbruch!
cpi Impulse,28 ;Minutenparität?
brne dcf77_18 ;nein: Stundenparität (35)
sbr Status,&B00000010 ;Status Minutenparität OK setzen
rjmp dcf77_12
dcf77_18:
sbr Status,&B00000100 ;Status Stundenparität OK setzen
rjmp dcf77_12 ;Parität Min./Std. OK
dcf77_19: ;Telegramm Ende:
inc Parity ;LastBit = 1
dcf77_20: ;LastBit = 0
*sts {DCF77Lastbit},Counter ;LastBit0/1-Pausenlänge für Debug
cpi Impulse,58 ;58 DCF77-Bits erfasst?
brne dcf77_21 ;unvollständig: weiter
sbr Status,&B00010000 ;ja: Status 58 Impulse empfangen setzen
dcf77_21:
andi Parity,&B10000001
brne dcf77_22 ;Paritäts- oder sonst. Fehler aufgetreten?
sbr Status,&B00001000 ;nein: Status Parität OK setzen
dcf77_22:
mov Counter,Status
andi Counter,&B00011111 ;Status Bits 0..4?
cpi Counter,&B00011111 ;alle 5 Bits = 1?
breq dcf77_24
dcf77_23:
clr Shifter ;Validitäts-Zähler zurücksetzen
rjmp dcf77_25 ;Fehler: Softclock NICHT stellen!
dcf77_24: ;Plausibilitäts-Check:
ld Counter,Z ;Jahr (0..99)
cpi Counter,100
brsh dcf77_23 ;> 99: Nicht plausibel!
ld Counter,-Z ;Monat (1..12)
tst Counter
breq dcf77_23
cpi Counter,13
brsh dcf77_23
ld Counter,-Z ;Wochentag (1..7)
tst Counter
breq dcf77_23
cpi Counter,8
brsh dcf77_23
ld Counter,-Z ;Tag (1..31)
tst Counter
breq dcf77_23
cpi Counter,32
brsh dcf77_23
ld Counter,-Z ;Stunde (0..23)
cpi Counter,24
brsh dcf77_23
ld Counter,-Z ;Minute (0..59)
cpi Counter,60
brsh dcf77_23
adiw ZL,5 ;Pufferzeiger auf Jahr zurücksetzen
sbr Status,&B00100000 ;Status Gültiges DCF77-Telegramm setzen
*lds Shifter,{DCF77Val_cnt} ;Validitäts-Zähler laden
inc Shifter ;Zähler erhöhen
cpi Shifter,Val_Limit ;Stand Validitäts-Zähler?
brlo dcf77_25 ;< Val_Limit: Softclock NICHT stellen!
ldi Shifter,Val_Limit ;Zähler wird nicht > Val_Limit!
sbrs Status,7 ;Status DCF-Decoder EIN/AUS?
rjmp dcf77_25 ;AUS: Softclock NICHT stellen!
;Softclock nach DCF stellen:
loadadr _year,X ;Zeiger auf Softclock-Variablen
ld Counter,Z ;Jahr = DCF77Buffer(9)
st X,Counter ;in _year sichern
ld Counter,-Z ;Monat = DCF77Buffer(8)
st -X,Counter ;in _month sichern
ld Counter,-Z ;Wochentag = DCF77Buffer(7)
*sts {_dayofweek},Counter ;in _dayofweek sichern
ld Counter,-Z ;Tag = DCF77Buffer(6)
st -X,Counter ;in _day sichern
ld Counter,-Z ;Stunde = DCF77Buffer(5)
st -X,Counter ;in _hour sichern
ld Counter,-Z ;Minute = DCF77Buffer(4)
st -X,Counter ;in _min sichern
clr Counter
st -X,Counter ;_sec zurücksetzen
*sts {Dcf77hsec},Counter ;Sek.-Bruchteile zurücksetzen
ld Counter,-Z ;DCF77-Bits 15..20 = DCF77Buffer(3)
*sts {Dcfflags},Counter ;in Dcfflags sichern
ld Counter,-Z ;DCF77-Bits 8..14 = DCF77Buffer(2)
*sts {Dcf77bits8_14},Counter ;in Dcf77bits8_14 sichern
ld Counter,-Z ;DCF77-Bits 0..7 = DCF77Buffer(1)
*sts {Dcf77bits0_7},Counter ;in Dcf77bits0_7 sichern
sbr Status,&B01000000 ;Status Softclock nach DCF gestellt setzen
dcf77_25:
andi Status,&B11111000 ;Statusbits 0..2 löschen
rjmp dcf77_26
;-------------------------------------------------------------------------------
[Dcf77_init]
$EXTERNAL Dcf77_soft
Dcf77_init: ;DCF77-Variablen Reset
clr Shifter ;Validitätszähler zurücksetzen
andi Status,&B11000000 ;Statusbits 0..5 löschen
dcf77_26:
*sts {Dcfstatus},Status ;Status speichern
*sts {DCF77Val_cnt},Shifter ;Validitäts-Zähler speichern
loadadr DCF77Buffer(1),Z ;Adresse DCF77Buffer
mov Parity,ZL
mov Impulse,ZH
loadadr DCF77Counter,Z ;Adresse DCF77Counter
ldi Counter,12
clr Shifter
dcf77_27: ;DCF77Counter..DCF77Buffer = 0
st Z+,Shifter
dec Counter
brne dcf77_27
inc Counter
st Z+,Counter ;DCF77Shifter = 1
st Z+,Parity ;Adresse DCF77Buffer -> DCF77TAL/AH
st Z,Impulse
ret
;BASCOM-Variablen für die Dcf77.lib:
;DCF77counter: Pausenzeit-Zähler
;DCF77parity: Fehler-Flag (Bit 7) + 1-Bit-Zähler
;DCF77impulse: Aktuelle DCF77-Bitnummer
;DCF77buffer(9): Zeit-Zwischenspeicher
;(Inhalt: DCF77-Bits 0..7, DCF77-Bits 8..14, DCF-Flags (= DCF77-Bits 15..20),
; Minute, Stunde, Tag, Wochentag, Monat, Jahr)
;DCF77shifter: Bitposition in der aktuellen DCF77Buffer Zelle
;DCF77tal: Zeiger (low) auf die aktuelle DCF77Buffer Zelle
;DCF77tah: Zeiger (high) auf die aktuelle DCF77Buffer Zelle
;Dcf77hsec: Sekunden-Bruchteile
;Dcf77bits0_7: DCF77-Bits 0..7
;Dcf77bits8_14: DCF77-Bits 8..14
;Dcf77val_cnt: Validitäts-Zähler
;Dcf77lastbit: LastBit-Pausenlänge für Debug
;Dcf77databit: DataBit-Pausenlänge für Debug
;-------------------------------------------------------------------------------
Softclock:
*lds Counter,{Dcf77hsec}
inc Counter ;Sek.-Bruchteile erhöhen
cpi Counter,ISR_freq ;1000ms = 1s erreicht?
breq Soft_10 ;ja: weiter
*sts {Dcf77hsec},Counter
ret ;sonst Ende
Soft_10:
clr Counter ;Sek.-Bruchteile löschen
*sts {Dcf77hsec},Counter
*lds Counter,{_sec}
inc Counter ;Sekunde erhöhen
cpi Counter,60 ;60 Sekunden erreicht?
breq Soft_20 ;ja: weiter
*sts {_sec},Counter
ret
Soft_20:
clr Counter ;Sekunde löschen
*sts {_sec},Counter
*lds Counter,{_min}
inc Counter ;Minute erhöhen
cpi Counter,60 ;60 Minuten erreicht?
breq Soft_30 ;ja: weiter
*sts {_min},Counter
ret
Soft_30:
clr Counter ;Minute löschen
*sts {_min},Counter
*lds Counter,{_hour}
inc Counter ;Stunde erhöhen
cpi Counter,24 ;24 Stunden erreicht?
breq Soft_40 ;ja: weiter
*sts {_hour},Counter
ret
Soft_40:
clr Counter ;Stunde löschen
*sts {_hour},Counter
*lds Counter,{_dayofweek}
inc Counter ;Wochentag erhöhen
cpi Counter,8 ;letzter Wochentag erreicht?
brne Soft_50 ;nein: weiter
ldi Counter,1 ;Wochentag auf "1" (Montag)
Soft_50:
*sts {_dayofweek},Counter
*lds Counter,{_day} ;Tag holen
*lds Shifter,{_month} ;Monat holen
ldi zl,low(Daysofmonth*2)
ldi zh,high(Daysofmonth*2) ;Anzahl Tage pro Monat holen
add zl,Shifter ;Zeiger auf aktuellen Monat
lpm ;Anzahl Tage holen
cp Counter,r0 ;Monatsende erreicht?
brne Soft_90 ;nein: weiter
cpi Shifter,2 ;Monatsende Februar (wg. Schaltjahr)?
brne Soft_60 ;nein: weiter
cbr Status,&B01000000 ;Status Softclock nach DCF gestellt löschen
Soft_60:
cpi Shifter,6 ;Monatsende Juni (wg. Schaltsekunde)?
brne Soft_70 ;nein: weiter
cbr Status,&B01000000 ;Status Softclock nach DCF gestellt löschen
Soft_70:
ldi Counter,1 ;Tag auf 1
cpi Shifter,12 ;Jahresende (+ wg. Schaltsekunde)?
brne Soft_100 ;nein: weiter
cbr Status,&B01000000 ;Status Softclock nach DCF gestellt löschen
*lds Shifter,{_year} ;Jahr holen
inc Shifter ;Jahr erhöhen
cpi Shifter,100 ;Jahr 100 erreicht?
brne Soft_80 ;nein: Ende
clr Shifter ;Jahr 00 setzen
Soft_80:
*sts {_year},Shifter ;speichern
ldi Shifter,1 ;Monat auf 1
rjmp Soft_110
Soft_90:
inc Counter ;Tag erhöhen
rjmp Soft_110
Soft_100:
inc Shifter ;Monat erhöhen
Soft_110:
*sts {_day},Counter ;Datum speichern
*sts {_month},Shifter
ret
Daysofmonth:
.db 00, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
[end]
Die Demo (Hauptprogramm) und Include-Datei kommen in das Programme-Verzeichnis, die Lib ins LIB-Verzeichnis (ACHTUNG: Wenn da schon eine dcf77.lib enthalten ist, müßte man die Lib aus diesem Post unter anderem Namen speichern!).
Lesezeichen