Code:
'copyright = D. Ottensmeyer
'comment = DCF77-Decoder und Softclock
'libversion = 4.00
'date = 25.11.2006
'statement = ---------------------------------
'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
brne dcf77_16 ;nicht letztes Bit MONAT
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
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 , 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
;-------------------------------------------------------------------------------
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]
DCF77_soft.BAS:
Lesezeichen