; DCF77-FUNKUHR BAUSTEIN in AVR Assembler

; Aufruf im 10 mSek. Zyklus (z.B. über Timer-Interrupt).

; Verwendete Register: R20-R23, R28/R29 sowie R30/31 (Y,Z Pointer).

; Der statische Datenbereich belegt 12 Bytes für den DCF77-Decoder.
; Vor Verwendung ist zu dessen Initialisierung dcf77_init aufzurufen.
; Weitere 8 Bytes enthalten die aktuelle Zeitinformation im BCD-Format
; und können mit zusätzlich installierter Soft-RTC betrieben werden.
; Diese sollte dem Decoder vorangestellt werden und nach Möglichkeit
; auch 1/100 Sekunden zählen (zur Vermeidung von Sek.-Sprüngen beim
; Minutenwechsel).

; Bitte die 20 Variablen wie definiert beieinander lassen.
; Kurzbeschreibung/Initialisierungswerte siehe unten.

; Das DCF77-Signal wird mit Aktiv "Low" an Input PB0 erwartet
; (kann frei nach Bedarf angepasst werden). Die Impulslängenmessung
; erfolgt über die Bestimmung der Signal-Pausenzeiten (in x * 1/100 Sek.).  

dcf77_start:  ;alle 10 mSek. aufzurufen
	ldi  YL,LOW(DCF77CT)    
    ldi  YH,HIGH(DCF77CT)
    ldd  r20,Y+0
    ldd  r21,Y+1
    sbis  PIN_DCF,PIN_DCF_NUM      ;Input-Pin
    rjmp  dcf77_5      ;Aktiv = "Low"
    inc  r20
    brne  dcf77_3
dcf77_1:  sbr  r21,$80      ;Fehler-Flag setzen
    std  Y+1,r21
dcf77_2:  clr  r20
dcf77_3:  std  Y+0,r20
dcf77_4:  ret

dcf77_5:  tst  r20      ;Auswertung fertig?
    breq  dcf77_4      ;Ja!
    ldd  r22,Y+2      ;Nein!
    ldd  r23,Y+9
    ldd  ZL,Y+10
    ldd  ZH,Y+11

    cpi  r20,196      ;LastBit 0 Obere Zeitgrenze+1 x
    brsh  dcf77_1      ;überschritten -> Fehler
    cpi  r20,187      ;LastBit-Scheide x
    brsh  dcf77_11    ;187-195 = LastBit0
    cpi  r20,178      ;LastBit 1 Untere Zeitgrenze x
    brsh  dcf77_10    ;178-186 = Lastbit1
        
    sbrc  r21,7      ;Wenn inzwischen Fehler...
    rjmp  dcf77_2      ;dann Abbruch  

    cpi  r22,$15      ;STATE < 21:
    brlo  dcf77_8      ;Inc STATE
        
    cpi  r20,6      ;Störspikegrenze x
    brlo  dcf77_2      ;Störspike wird ignoriert
    cpi  r20,96      ;Datenbit obere Zeitgrenze+1 x
    brsh  dcf77_1      ;überschritten -> Fehler
    cpi  r20,78      ;Datenbit untere Zeitgrenze x
    brlo  dcf77_1      ;unterschritten -> Fehler
    cpi  r20,87      ;Bitscheide x
    brsh  dcf77_6      ;87-95 = Bit0        
    inc  r21      ;78-86 = Bit1
    std  Y+1,r21
    cpi  r22,$1c
    breq  dcf77_6      ;Prüfbit Minute!
    cpi  r22,$23
    breq  dcf77_6      ;Prüfbit Stunde!
    ld  r20,Z      ;R20 = (aktuelle NEWTIME) Zelle
    add  r20,r23      ;addiere SHIFTER
    st  Z,r20      ;zurückspeichern

dcf77_6:  lsl  r23      ;Bit0/1: SHIFTER um 1 nach links
    std  Y+9,r23
    cpi  r22,$1c
    brlo  dcf77_8      ;Minuten-Zyklus 
    breq  dcf77_9      ;Minute Prüfbit
    cpi  r22,$23
    brlo  dcf77_8      ;Stunden-Zyklus
    breq  dcf77_9      ;Stunden-Prüfbit
    cpi  r22,$29
    brlo  dcf77_8
    breq  dcf77_7      ;LastBit TAG
    cpi  r22,$2c
    brlo  dcf77_8
    breq  dcf77_7      ;LastBit WOCHENTAG
    cpi  r22,$31
    brne  dcf77_8
dcf77_7:  ldi  r23,1      ;LastBit MONAT
    adiw  ZH:ZL,1
    std  Y+9,r23
    std  Y+10,ZL
    std  Y+11,ZH    

dcf77_8:  inc  r22      ;Inc STATE
    std  Y+2,r22
    rjmp  dcf77_2                          

dcf77_9:  sbrc  r21,0      ;Prüfbit MIN/STU Auswertung
    rjmp  dcf77_1      ;Prüfbit Fehler
    rjmp  dcf77_7      ;Prüfbit OK

dcf77_10:  inc  r21      ;LastBit = 1: Inc CHECK
dcf77_11:  cpi  r22,$3a      ;58 DCF77-Bits erfasst?
    brne  dcf77_init    ;unvollständig -> dcf77_init
    andi  r21,$81
    brne  dcf77_init    ;Fehlerstatus -> dcf77_init

    ldi  r20,6      ;Erfolgreicher Empfang:
    ld  r21,Z      ;BCD-Zeitinformation
dcf77_12:  std  Z+11,r21    ;nach MIN...JHR sichern
    ld  r21,-Z
    dec  r20
    brne  dcf77_12
    std  Z+11,r20    ;Sek. = 0 setzen
    std  Z+10,r20    ;1/100 Sek. = 0 setzen  
  
dcf77_init:  ldi  ZL,LOW(DCF77CT)    ;DCF77-VARIABLEN RESET
    ldi  ZH,HIGH(DCF77CT)
    ldi  r21,LOW(NEWTIME)
    ldi  r22,HIGH(NEWTIME)
    ldi  r20,$09
    clr  r23
dcf77_14:  st  Z+,r23
    dec  r20
    brne  dcf77_14
    inc  r20
    st  Z+,r20
    st  Z+,r21
    st  Z,r22
    ret


;SRAM Variable  Definition  Init.Wert  Beschreibung
;------------------------------------------------------------------------------
.dseg
DCF77CT:	.BYTE 1    ;0    DCF77 Impuls-Pausenzeit-Zähler
DCF77CHECK:	.BYTE 1    ;0    DCF77 Fehler-Flag + 1-Zähler
DCF77STATE:	.BYTE 1    ;0    DCF77 Aktuelle Bitnummer
NEWTIME:	.BYTE 6    ;0,0,0,0,0,0  DCF77 Zeit-Zwischenspeicher
DCF77SHIFT:	.BYTE 1    ;1    DCF77 Shifter
DCF77TAL:	.BYTE 1    ;LOW(NEWTIME)  DCF77 Pointer auf NEWTIME Low
DCF77TAH:	.BYTE 1    ;HIGH(NEWTIME)  DCF77 Pointer auf NEWTIME High
HSEK:		.BYTE 1    ;RTC verwaltet  BCD 1/100 Sekunde
SEK:		.BYTE 1    ;RTC verwaltet  BCD Sekunde
MIN:		.BYTE 1    ;RTC verwaltet  BCD Minute
STU:		.BYTE 1    ;RTC verwaltet  BCD Stunde
TAG:		.BYTE 1    ;RTC verwaltet  BCD Tag
WTAG:		.BYTE 1    ;RTC verwaltet  BCD Wochentag
MON:		.BYTE 1    ;RTC verwaltet  BCD Monat
JHR:		.BYTE 1    ;RTC verwaltet  BCD Jahr
.cseg	;Wieder auf Programmspeicher wechseln