Programm

 

 

 


dESµ    DCF 77 - Funkuhrempfänger


 

 

 


DCF77.INC – das Funkuhrmodul









Dieser Treiber decodiert das eingespeiste, digitale und nicht invertierte, TTL Funksignal eines DCF-Empfängers. Dieses Signal muss auf einem Torbit des MC 8051-Derivats angeschlossen werden. Welches Torbit benutzt werden soll muss im Kopf des Programms eingetragen werden. Die Stelle wurde farblich hervorgehoben.






; DCF77.INC
; ---------- Version 300895  (für Funkuhr DCF77)

; (c)04 Schwarzer, www.GoBlack.de


; Das Programm decodiert Signale von DCF77 -Empfängern, die
; ein nicht invertiertes, digitales TTL-Zeitsignal erzeugen,
; das den Normen der PTB -Braunschweig entspricht.
; Das Programm ist in der vorliegenden Form mit dem
; dESy DCF77 Empfängermodell einsetzbar.

; Die Treiberprogramme dieser Datei müssen der Harware
; angepaßt werden. Es sind folgende Parameter einzustellen.

; - Der Timer des MC 8051-Systems, der zur Erzeugung des 10
;   mSec-Referenz -IRQ- Signals benutzt werden soll. Es
;   können Timer 0 oder 1 benutzt werden.

    $SET (TIMER =  0)     ; zu verwendender Timer


; - Der Toreingang, auf dem das ZeitSignal eingespeist
;   wird. (Es können alle freien Bit der EingangsTore des
;   MC8051- Systems benutzt werden)

    DCFTor  BIT  P1.7     ; BitEingang des DCF-Signals


; - Der Signalzustand, bei dem das ZeitSignal zur Anzeige
;   einer abgelaufenen Sekunde aktiv ist. Es kann bei log 0
;   oder 1 aktiv sein.

   $SET (DCFaktiv = 1)   ; aktiver Signalpegel dESy DFC77
          

; - Einige Status-Zustände der Uhr können auf Leuchtdioden
;   ausgegeben werden hierzu wird Tor P1 benutzt.
;   Erklärung zu den Signalen siehe Z1Flg.

    Z1Flg   EQU  P1      ; Statuszustände

; Abhängig von der Taktfrequenz des Microcontrollers muß
; der Nachladewert des Timers gesetzt werden. Beide Timer,
; T0 und T1, werden im Modus 2 betrieben,
; (16Bit Vorwärtszähler). Es wird also vom Nachlade-
; wert bis 0 hochgezählt. Die Timer zählen mit fosz/12,
; der internen Takfrequenz des MC 80515
; Daraus folgt für 12MHz/12 der Wert -10.000 = D8F0h für
; 10mSec


mS10_H   EQU  0D8h  ; MSB des 10 mSec -Timer Nachladewertes
mS10_L   EQU  0F0h  ; LSB des 10 mSec -Timer Nachladewertes


; Für den verwendeten Timer wird die höchste IRQ-Priorität
; eingestellt. Die Prioritäten der anderen IRQ's
; verschieben sich dadurch von der Voreinstellung um eine
; Ebene nach unten.


; Definitionen für die Wochentagnummer in <dTagNum>
; Die empfangene Nummer für den Namen des Wochentages
; entspricht folgendem Schema. Die Zahl in TagNum
; bedeutet ...

; 0 - den Startzustand des Programms
; 1 - Montag   2 - Dienstag   3 - Mittwoch  4 - Donnerstag
; 5 - Freitag  6 - Sonnabend  7 - Sonntag



; DATA MODULE -----------------------------------------

              ;DatenSegment mit 13 Bytes
DCF77_DATA    SEGMENT DATA
              ;DatenSegment Bitadres.bar
DCF77_DATABA  SEGMENT DATA BITADDRESSABLE
              ;BitSegment   mit 22 Bits
DCF77_BIT     SEGMENT BIT

; Die Anzeigeregister <dx> enthalten die auszugebende
; Zeitinformation, auch wenn die Uhr ohne DCF-Signal
; arbeitet. Die EinleseRegister <ix> enthalten die DCF-
; Angaben. Diese werden in die Anzeigeregister über-
; tragen. Die Informationen liegen in beiden Register-
; arten im BCD-Format vor. Die Abfolgeder <di> und <dx>
; Register darf nicht geändert werden. (indirekte
; Adressierung über R0)


                RSEG    DCF77_DATA

dSEK:    DS 1       ; AnzeigeRegister:  Sekunden
dMIN:    DS 1       ;                   Minuten
dSTD:    DS 1       ;                   Stunden
dTAG:    DS 1       ;                   Tag
dTagNam: DS 1       ;                   Nr des TagNamens
dMON:    DS 1       ;                   Monat
dJAHR:   DS 1       ;                   Jahr
iMIN:    DS 1       ; EinleseRegister:  Minuten
iSTD:    DS 1       ;                   Stunden
iTAG:    DS 1       ;                   Tag
iTagNam: DS 1       ;                   Nr des TagNamens
iMON:    DS 1       ;                   Monat
iJAHR:   DS 1       ;                   Jahr


                RSEG DCF77_BIT
                
; Betriebsflaggen des Programms: Diese Flaggen werden im
; Programm benutzt und geändert. Der Benutzer kann sie
; abfragen, sollte sie jedoch nicht ändern.

InfoBit:  DBIT 1    ; 0: empfangenes InformationsBit = 0
                    ; 1: empfangenes Informationsbit = 1
PBit:     DBIT 1    ; Paritätsbit bei Zeit/Datum Infos
DCFalt:   DBIT 1    ; vorheriger Zustand des DCF-Signals
Look_s59: DBIT 1    ; 0: Einlesen der decodierten Zeit
                    ; 1: nach der 59. Sekunde suchen
Sync_RES: DBIT 1    ; 1: Zeit wurde nach RESET mindestens
                    ;    einmal synchronisiert


; BenutzerInformationsFlaggen: Diese Flaggen werden im
; Programm gesetzt und stehen dem Benutzer zur Verfügung.
; Das Benutzerprogramm sollte sie nach Auswertung der
; Information mit 'clr BITx' löschen.

SecFlg:    DBIT 1    ; 1: ganze Sekunde erreicht
MinFlg:    DBIT 1    ; 1: ganze Minute erreicht
StdFlg:    DBIT 1    ; 1: ganze Stunde erreicht
Blink_4Hz: DBIT 1    ; 4 Hz Flagge     für z.B. Alarm
Blink_2Hz: DBIT 1    ; 2 Hz Flagge     "


; ZustandsFlaggen: Dies Flaggen signalisiern Betriebs-
; zustände des Programms. Sie werden vom Programm gesetzt
; und gelöscht. Der Benutzer kann sie z.B. mit LED
; anzeigen lassen.

                RSEG DCF77_DATABA
Z2Flg:     DS 1

ACT        EQU Z1Flg.0  ; 1: DFC77-Uhr wird angezeigt
                        ; 1/0: blinkt wenn nicht synchron

ST0        EQU Z1Flg.7  ; 1: 100mSec-InfoBit erkannt
                        ;    => log 0
ST1        EQU Z1Flg.6  ; 1: 200mSec-InfoBit erkannt
                        ;    => log 1
ST2        EQU Z1Flg.5  ; 1: ImpulsweitenFehler bei
                        ;    100/200 mSec Bit
ST3        EQU Z1Flg.4  ; 1: 1 Sec Impulsabstand
ST4        EQU Z1Flg.3  ; 1: 2-Sec Impulsabstand
                        ;    => Minute um
ST5        EQU Z1Flg.2  ; 1: ImpulsabstandFehler bei
                        ;    1/2 Sec

ANTE       BIT Z2Flg.7  ; 0: Betriebs- 1: Reserveantenne
AMEZ       BIT Z2Flg.6  ; 1: Ankünd. 1Std vor Wechsel
                        ;    MEZ/MESZ/MEZ
MESZ       BIT Z1Flg.1  ; 1: MESZ -Mitteleurop Sommerzeit
MEZ        BIT Z2Flg.4  ; 1: MEZ  -Mitteleurop Normalzeit
ASSEC      BIT Z2Flg.3  ; 1: Ankünd. 1Std vor
                        ;    Einfüg.Schaltsekunde
DCFTIME    BIT Z2Flg.0  ; 1: DCF77 -UhrZeit wird angezeigt
                        ; 0: Uhrzeit wird vom Programm
                        ;    erzeugt

; CODE MODULE -------------------------------------------

$IF (TlMER =0)          ; wenn Timer 0 gewählt wurde
TMOD_CLR  EQU 11110001b ; F1h  durch 'anl'
                        ;      Gate, C/T, M1 werden 0
TMOD_SET  EQU 00000001b ; 01h  durch 'orl'
                        ;      M0 wird 1
TLx       EQU TL0       ; Adresse: Zählregister LOW
THx       EQU TH0       ;          "            HIGH
ETx       EQU ET0       ; Bitadr: Freigabe Timer IRQ
IP0m      EQU 00000010b ; höchste Priorität für den Timer
IP1m      EQU 00000010b ;          "
TRx       EQU TR0       ; Bitadr: Timer starten

$ELSE                   ; wenn Timer 1 gewählt wurde
TMOD_CLR  EQU 00011111b ; 1Fh  durch 'anl'
                        ;      Gate, C/T, M1 werden 0
TMOD_SET  EQU 00010000b ; 10h  durch 'orl
                        ;      M0 wird 1
TLx       EQU TL1       ; Adresse: Zählregister LOW
THx       EQU TH1       ;          "            HIGH
ETx       EQU ET1       ; Bitadr:  Freigabe Timer IRQ
IP0m      EQU 00001000b ; höchste Priorität für den Timer
IP1m      EQU 00001000b ; "
TRx       EQU TR1       ; BitAdr:  Timer starten
$ENDIF

          USING   2     ; Registerbank 2      -Belegung
          ; ----------------------------------------
          ;   R0:  Datenregister-Zeiger
          ;   R1:  Schleifenzähler, Schiebezähler
          ;   R2:  10mSec-Zähler bis Sekunde
          ;   R3:  enthält momentane Sekunde (Zähler)
          ;   R4:  Sekundenzähler bis Minute
          ;   R5:  nicht benutzt
          ;   R6:  nicht benutzt
          ;   R7:  nicht benutzt

DCF77_PROG      SEGMENT CODE
                RSEG    DCF77_PROG
; -------------------------------------------------------
; Name:   DCF77_Init
; Typ:    Unterprogramm
; -------------------------------------------------------

; Das Unterprogramm initialisiert den DCF77-Interrupt-
; treiber. Es muß vom Hauptprogramm einmal aufgerufen
; werden. Danach wird mit der Verarbeitungdes DCF-
; Eingangssignals über die IRQ -Service-Routine
; 'DCF77_Irq' begonnen. Es führt die folgend genannten
; Funktionen aus:

; - Timer für 10mSec_IRQ initialisieren
; - 10mSec_IRQ Priorität setzen und freigeben
; - Betriebsbits der DCF77-Uhr initialisieren
; - Zeitregister löschen
; - Registerbank 2 initialisieren

; Übergaben: keine
; Rückgaben: TMOD, TLx, THx, ETx, TRx, IP0, IP1
; Ändert:    dSEK, dMIN, dSTD, dTagNam, dTAG, dMON, dJAHR
;            DCFalt, Look_s59, SecFlg, MinFlg, StdFlg
;            DCFTIME, Sync_RES.
; Unterprogramme: keine
; Stacknutzung:   4 Bytes


DCF77_Init:  push ACC             ; Akku und Flags sichern
             push PSW
             mov  PSW,  #10h      ; Registerbank 2 setzen
             anl  TMOD, #TMOD_CLR ; Timer: 16-Bit-Timer
             orl  TMOD, #TMOD_SET ; Interner Takt
             mov  TLx,  #mS10_L   ; Wert für 10 mSec
             mov  THx,  #mS10_H   ; Interrupt laden
             setb ETx             ; Freigabe  Timer IRQ
             mov  IP0, IP0m       ; Priorität Timer IRQ
             mov  IP1, IP1m       ; setzen
             setb EAL             ; Freigabe aller  IRQ
             setb TRx             ; Start des Timers

$IF (DCF_INF= 0)
             setb DCFalt   ; Steuerbit löschen bei 0-aktiv
$ELSE
             clr  DCFalt   ; Steuerbit löschen bei 1-aktiv
$ENDIF
             setb Look_s59 ; nach der 59.Sekunde suchen
             clr  SecFlg   ; Sekunde erreicht Flag löschen
             clr  MinFlg   ; Minute  erreicht Flag löschen
             clr  StdFlg   ; Stunde  erreicht Flag löschen
             clr  DCFTIME  ; interne Uhr erzeugt die Zeit
             clr  ACT
             clr  Sync_RES ; noch nicht nach RESET synchron
             clr  A
             mov  R0, #dSEK
             mov  R1, #7
DELE:        mov  @R0, A   ; Zeitregister <dSEK> bis
             inc  R0       ; <dJAHR> löschen
             djnz R1, DELE
             mov  R2, A    ; Zählregister der Regist.bank 2
             mov  R3, A    ; löschen
             mov  R4, A
             pop  PSW      ; Flaggenregister und Akku
             pop  ACC      ; wieder herstellen
             ret           ; Initialisierung beendet

 

; -------------------------------------------------------
; Name:   DCF77_Irq
; Typ:    IRQ -ServiceProgramm
; -------------------------------------------------------

; Über 'DCF77_Irq' wird alle 10 mSec das DCF77-Signal
; abgetastet und entsprechend verarbeitet. Das Programm
; führt folgende Funktionen aus

; - Timer für den nächsten 10 mSec_IRQ vorbereiten
; - 10 mSec-Zähler zur Erkennung einer Sekunde erhöhen
; - DCF-Signal abtasten und Signalwechsel erkennen
; - Impulsdauer und Impulsabstand messen
; - Synchronisation mit dem DCF77-Signal,
; - setzen von Blinkbits 2 und 4 Hz sowie von Steuerbits
;   nach vollen Sekunden, Minuten und Stunden

; Übergaben: DCFTor, DCFalt
; Rückgaben: Zeitregister, Betriebsflaggen,
;            Benutzerflaggen, Zustandsflaggen

; Ändert:    Zeitregister, Betriebsflags, Benutzerflags,
;            Zustandsflags, RegBank2: R0, R1, R2, R3, R4
;            TLx, THx, TRx, EAL
; Unterprogramme: DCF_Uhr, Uhr
; Stacknutzung:   7 Bytes
 
DCF77_Irq:   push ACC        ; die benutzten Prozessor-
             push B          ; register retten
             push PSW
             push DPH
             push DPL
             mov  PSW, #10h  ; Registerbank 2 setzen

; Neuladen des Timers für den 10 mSec_IRQ. (Die Addition
; von Werten zum Timer ergibt eine Laufzeitverkürzung,
; da Vorwärtszähler)

             clr  EAL         ; alle aktiven IRQ sperren
             clr  TRx         ;  Timer: STOP
             mov  A, #mS10_L+6; Startwert
                              ; TLx= LSB(-10000+6)   1
             add  A, TLx      ; mom.Wert TLx + Startwert
                              ;                TLx   1
             mov  TLx, A      ; = neuer Wert TLx.    1
             mov  A, #mS10_H  ; Startwert
                              ; THx= MSB(-10000+6)   1
             addc A, THx      ; mom.Wert THx + Startwert
                              ;                THx + C
             mov  THx, A      ; = neuer Wert Thx.    1
             setb TRx         ; Timer: START
             setb EAL         ; alle aktiven IRQ freigeben

;     Sekunden-Zähler erhöhen

             inc  R4
             inc  R2          ; 10 mSec-Zähler erhöhen

             cjne R2, #25,INC1
             sjmp INC5        ; Aufrufe zur Erzeugung von
INC1:        cjne R2, #50,INC2
             sjmp INC4        ; 2Hz und 4Hz -Signalen
INC2:        cjne R2, #75,INC3
             clr  ST0
             clr  ST1
             sjmp INC5
INC3:        cjne R2, #100,WCH ; Sekunde erreicht ?
             mov  R2, #0      ; 10 mSec-Zähler löschen und
             call Uhr         ; die Sekunde auf Zeitreg.
                              ; addieren
INC4:        jb   DCFTIME, inc41
             cpl  ACT
inc41:       setb Blink_2Hz   ; für AlarmFunktionen
                              ; verwendbar
INC5:        setb Blink_4Hz   ; der Benutzer setzt die
                              ; Flaggen zurück

; Abfrage ob ein Wechsel des Signalpegels 
; im DCF77-Signal stattfand

WCH:         clr  A
             mov  C, DCFalt   ; alt Wert des Signals nach C
             rlc  A           ; C --> ACC.0
             mov  C, DCFTor   ; neu Wert des Signals nach C
$IF (DCFaktiv= 1)
             cpl  C           ; wenn 1 aktiv auf 0 setzen
$ENDIF
             mov  DCFalt, C   ; neuen Wert speichern
             rlc  A           ; C --> ACC.0  ACC0 --> ACC1
             jz   LOW_LOW     ; Alt: LOW   Neu: LOW
             cjne A, #03h,NxtTst
             jmp  HIG_HIG     ; Alt: HIGH  Neu: HIGH
NxtTst:      cjne A, #02h,LOW_HIG  ; 0 -> 1 -Übergang
             jmp  HIG_LOW          ; 1 -> 0 -Übergang

;     0 -> 0   und   1 -> 1   Übergänge

LOW_LOW:
HIG_HIG:     jmp  NormalExit  ; Zähler Impulszeit erhöhen

;     0 -> 1  Übergang

LOW_HIG:     clr  C           ; wegen subb
             mov  A, R4       ; untere Toleranz 100 mSec
             subb A, #6       ; < 60mSec
             jc   ImpErr      ; Sprung bei Fehler
             mov  A, R4       ; oberen Toleranz 100 mSec
             subb A, #13      ; > 130mSec
             jnc  LHI         ; Sprung bei Fehler
             call Imp100      ; .. Bit anzeigen
             jb   Look_s59, ExJmp ; beiSuche nach 59.Sec= 1
             clr  InfoBit     ; iMPULSiNFORMATION 0
                              ;  verarbeiten
             sjmp ADDUP

LHI:         mov  A, R4       ; untere Toleranz 200 mSec
             subb A, #15      ; < 160 mSec
             jc   ImpErr      ; Sprung bei Fehler
             mov  A, R4       ; oberen Toleranz 200 mSec
             subb A, #23      ; >230mSec
             jnc  ImpErr      ; Sprung bei Fehler
             call Imp200      ; .. Fehler anzeigen
             jb   Look_s59, ExJmp ; beiSuche nach 59.Sec= 1
             setb InfoBit     ; iMPULSiNFORMATION 1
                              ; verarbeiten

ADDUP:       mov  A, R3       ; Input -SekundenZähler+1
             add  A, #1
             da   A           ; wegen BCD Zählung
             mov  R3, A
             call DCF_Uhr     ; Sekunden InfoBits
             jnc  ExJmp
             call dParErr     ; ein ParitätsFehler
             sjmp FehlerExit

ExJmp:       sjmp NormalExit
ImpErr:      call dImpwErr    ; FehlerBit Impulsdauer set
             sjmp FehlerExit

;     1 -> 0  Übergang

HIG_LOW:     clr  C           ; wegen subb
             mov  A, R4       ; untere Toleranzgrenze 1 Sec
             subb A, #93      ; < 930 mSec
             jc   ImpaErr     ; Sprung bei Fehler
             mov  A, R4       ; obere  Toleranzgrenze 1 Sec
             subb A, #107     ; >1070 mSec
             jnc  MIN59       ; Sprung bei Fehler
             call Imp1000
             sjmp M62

MIN59:       mov  A, R4       ; untere Toleranzgrenze 2 Sec
             subb A, #193     ; <1930 mSec
             jc   ImpaErr     ; Sprung bei Fehler
             mov  A, R4       ; obere  Toleranzgrenze 2 Sec
             subb A, #207     ; > 2070 mSec
             jnc  ImpaErr     ; Sprung bei Fehler
             call Imp2000
             jb   Look_s59, M60 ; wenn suche nach 59.Sec= 1

             mov  dSEK, #0    ; Display Register aktualis.
             mov  dMIN, iMIN  ; die Input-Register werden
                              ; in die
             mov  dSTD, iSTD  ; Display Register übertragen
             mov  dTagNam,iTagNam
             mov  dTAG, iTAG
             mov  dMON, iMON
             mov  dJAHR, iJAHR
             setb SecFlg      ; Sekunde erreicht Flag set
             setb MinFlg      ; Minute  erreicht Flag set
             mov  A, dMIN
             cjne A, #0, WTR1
             setb StdFlg      ; Stunde  erreicht Flag set
WTR1:        setb DCFTIME     ; Zeit wird von DFC-Uhr
                              ; erzeugt
             setb ACT
             setb Sync_RES
             mov  R2, #00H    ; 10mSec-Zähler bis Sekunde
                              ; löschen
             sjmp M61

M60:         clr  Look_s59    ; Suche nach 59.Sec abbrechen
M61:         mov  R3, #99h    ; Einlese-Sekundenzähler
                              ; setzen BCD
M62:         mov  R4, #00h    ; Zähler für Impulsmessung
             sjmp NormalExit

ImpaErr:     call dImpaErr    ; Impulsabstand-FehlerBIT
                              ; setzen
             mov  R4, #00h    ; Zähler für Impulsmessung
                              ; löschen

;     Ende des IRQ -ServiceProgramms

FehlerExit:  clr  DCFTIME     ; interne Uhr muß die Zeit
                              ; erzeugen
             call SetLED
             setb Look_s59    ; Suche nach 59.Sek beginnen

NormalExit:  pop  DPL         ; gesicherte Register wieder
             pop  DPH         ; einsetzen
             pop  PSW
             pop  B
             pop  ACC
             reti             ; Rückkehr DCF77-Irq -Handler

 


; -------------------------------------------------------

; Bearbeiten der ZustandsFlaggen. Sind St0 bis St5
; TorBits, können, die Zustände zu Testzwecken angezeigt
; werden.

Imp100:      setb ST0       ; 100 mSEC-InfoBit erkannt
             clr  ST1
             clr  ST2
             sjmp SetLED
Imp200:      clr  ST0       ; 200 mSEC-InfoBit erkannt
             setb ST1
             clr  ST2
             sjmp SetLED
dImpwErr:    clr  ST0       ; Fehler in der Impulsdauer
             clr  ST1
             setb ST2
             sjmp SetLED
dParErr:     setb ST0       ; ParitätsFehler od.Sekunde=20
             setb ST1
             clr  ST2
             sjmp SetLED
Imp1000:     setb ST3       ; 1 SEC-Impulsabstand erkannt
             clr  ST4
             clr  ST5
             sjmp SetLED
Imp2000:     clr  ST3       ; 2 SEC-Impulsabstand erkannt
             setb ST4
             clr  ST5
             sjmp SetLED
dImpaErr:    clr  ST3       ; InfoBit-AbstandsFehler
             clr  ST4
             setb ST5
SetLED:      ret



; Name: DCF_Uhr
; Typ:  Unterprogramm  IRQ -Server
; Das Unterprogramm DCF_Uhr sammelt die Informationen der
; Sekundenimpulse und setzt sie zu der gesendeten Zeit,
; dem Datum, und den WochentagAngaben zusammen. Die
; fertigen Angaben werden auf ihre Parität geprüft und in
; die InputRegister <iMIN> bis <iJAHR> übertragen.

; Bei Paritätsfehlern oder einem Fehler im Startbit gibt
; das Programm C= 1 zurück. Andernfalls ist C= 0

; Übergaben: InfoBit, R3
; Rückgaben: EinleseRegister, Zustandsflaggen, C
; Ändert:    EinleseRegister, Zustandsflaggen,
;            A, PSW, R0, R1, PBit
; Unterprogramme: keine
; Stacknutzung:   0 Byte

DCF_Uhr: cjne R3, #00h, s15
         sjmp Sec00           ; s00 Start neue Infoübertrag.
s15:     cjne R3, #15h, s151
         sjmp SecAnt          ; s15 Flag Antenne setzen
s151:    jc   s60             ; s<15 nicht weiter abfragen
         cjne R3, #16h, s17
         sjmp SecAMez         ; s16 Flag Ankünd. MEZ/MESZ
s17:     cjne R3, #17h, s18
         sjmp SecMesz         ; s17 Flag MESZ einrichten
s18:     cjne R3, #18h, s19
         sjmp SecMez          ; s18 Flag MEZ einzichten
s19:     cjne R3, #19h, s20
         sjmp SecASS          ; s19 Flag Ankünd. Schaltsek.
s20:     cjne R3, #20h, s21
         sjmp Sec20           ; s20 StartBit InfoBytes
s21:     cjne R3, #21h, s28
         sjmp SecISt0         ; s21 Start der Minuten
S28:     cjne R3, #28h, s29
         sjmp SecPar          ; s28 Parität d.Minuten
S29:     cjne R3, #29h, s35
         sjmp SecISt1         ; s29 Start des Stunden
s35:     cjne R3, #35h, s36
         sjmp SecPar          ; s35 Parität d.Stunden
s36:     cjne R3, #36h, s42
         sjmp SecISt1         ; s36 Start der TagNr
s42:     cjne R3, #42h, s45
         sjmp SecISt1         ; s42 Start der TagName
s45:     cjne R3, #45h, s50
         sjmp SecISt1         ; s45 Start der MonatNr
s50:     cjne R3, #50h, s58
         sjmp SecISt1         ; s50 Start der JahrNr
s58:     cjne R3, #58h,SecNrm
         sjmp SecPar          ; s58 Parität d.Datum
s60:     sjmp SecExit

; Sekunde 00 (Zeitstart)
Sec00:   clr  A
         mov  R0, #iMIN
         mov  R1, #06H        ; alle EingabeReg. löschen
Sec0L:   mov  R0, A
         inc  R0
         djnz R1, Sec0L
         sjmp SecExit


; Sekunde 15
; (Antennenbit  1: Betriebsantenne  0: Reserveantenne)
SecAnt:  mov  C, InfoBit
         mov  ANTE, C
         sjmp SecExit

; Sekunde 16
; (Ankündigung MEZ/MESZ 1: 1Std vor jeweiligem Wechsel)
SecAMez: mov  C, InfoBit
         mov  AMEZ, C
         sjmp SecExit

; Sekunde 17 (ZonenzeitBit 1 ist  1: wenn MESZ)
SecMesz: mov  C, InfoBit
         mov  MESZ, C
         sjmp SecExit

; Sekunde 18 (ZonenzeitBit 2 ist  1: wenn MEZ)
SecMez:  mov  C, InfoBit
         mov  MEZ, C
         sjmp SecExit

; Sekunde 19
; (Ankündigung Schaltsekunde   1: 1Std vor der Schaltsek.)
SecASS:  mov  C, InfoBit
         mov  ASSEC, C
         sjmp SecExit

; Sekunde 20 (Startbit der Zeit/Datum-Übertragung immer 1)
Sec20:   jnb  InfoBit, SecErr ; war nicht das Startbit
         mov  R0, #iMIN-1     ; R0 zeigt auf Eing.Register
         clr  PBit            ; Paritybit löschen
         sjmp SecExit

; Sekunden mit Prüfbit bearbeiten
; (das sind Sekunde 28, 35, 58)
SecPar:  jnb  InfoBit, SecPaj ; Parität = InfoBit = 0
         cpl  PBit            ; ermittelte Parität invert.
SecPaj:  jb   PBit, SecErr    ; PBit=1 : Paritätsfehler
         sjmp SecExit

; Sekunden mit erstem Bit einer InformationsFolge
; bearbeiten
SecISt1: mov  A, @R0          ; zuletzt bearb. Register
SecIsL:  clr  C               ; mit Nullen auffüll.da alle
         rrc  A               ; Informat.eingetroffen sind
         djnz R1, SecIsL
         mov  @R0, A          ; diese Register speichern
SecISt0: inc  R0              ; neues EingabeRegister setzen
         mov  R1, #8          ; Schiebe-Zähler neu setzen

; Normale Sekunden bearbeiten
SecNrm:  mov  A, @R0          ; R0 zeigt auf Eing.Reg. X
         mov  C, InfoBit      ; InfoBit  0 od.1 zum  Carry
         jnc  SecNrj          ; wenn 0 nach SecNrj
         cpl  PBit            ; wenn 1 zum ParityBit add.
SecNrj:  rrc  A               ; Carry von rechts zum Akku
         mov  @R0, A          ; A zum InputRegister X
         dec  R1              ; Zähler für Schiebeop.-1
                                          
SecExit: clr  C               ; Empfang ohne Fehler
         ret
SecErr:  setb C               ; Fehler b.Startb.od.Parität
         ret



; Name:   Uhr
; Typ:    UNTERPROGRAMM
; Das Programm wird im Sekundenrythmus aufgerufen, wenn
; der DCF77 -Empfang ausgefallen ist. Es schreibt dann
; wie bei einer Uhr Zeit und Datum fort.
; Die Zeit- und Datuminformationen werden im BCD-Format
; gespeichert. Ebenso die Nummer des Tagesnamen

; Übergaben:  Zeitregister
; Rückgaben:  Zeitregister, SecFlg, MinFlg, StdFlg
; Änderungen: Zeitregister,
;             SecFlg, MinFlg, StdFlg, A, B, PSW
; Unterprogramme: keine
; Stacknutzung:   0 Byte

Uhr:    mov  A, dSEK         ; Sekunde ..
        add  A, #1           ; .um 1 erhöhen
        da   A               ; .zu BCD-Zahl machen
        mov  dSEK, A         ; .und speichern
        setb SecFlg          ; .Sekunde erreicht Flag setzen
        cjne A, #60h, UhrEnd ; -60 Sekunden vergangen ?
        mov  dSEK, #0        ; .Sekunde auf 0 setzen ..
        setb MinFlg          ; .Minute  erreicht Flag setzen
        mov  A, dMIN         ; Minute ..
        add  A, #1           ; .um 1 erhöhen
        da   A               ; .zu BCD-Zahl machen
        mov  dMIN, A         ; .und speichern
        cjne A, #60h, UhrEnd ; -60 Minuten vergangen ?
        mov  dMIN, #0        ; .Minute auf 0 setzen
        setb StdFlg          ; .Stunde  erreicht Flag setzen
        mov  A, dSTD         ; Stunden ..
        add  A, #1           ; .um 1 erhöhen
        da   A               ; .zu BCD-Zahl machen
        mov  dSTD, A         ; .und speichern
        cjne A, #24h, UhrEnd ; -24 Stunden vergangen ?
        mov  dSTD, #0        ; .Stunde auf 0 setzen
        mov  A, dTagNam      ; Kennummer des Tages
        inc  A               ; .um 1 erhöhen
        mov  dTagNam, A      ; .und speichern
        cjne A, #08h, UhrDat ; .größer als 8
        mov  dTagNam, #1     ; .dann 1 (Montag setzen)
UhrDat: mov  A, dTAG         ; Tag ..
        add  A, #1           ; .um 1 erhöhen
        da   A               ; .zu BCD-Zahl machen
        mov  dTAG, A         ; .und speichern
        mov  A, dMON         ; .Monat holen
        cjne A, #02h, Uhr2   ; -Monat Februar ?
        mov  A, dJAHR        ; .prüfen ob Schaltjahr vor-
        mov  B, #04h         ;  liegt
        div  AB              ;  Division durch 4,
                             ;  wenn Rest=0
        mov  A, B            ;  .dann Schaltjahr
        jnz  Uhr1            ;  .kein Schaltjahr
        mov  A, #30h         ; .Schaltjahr Tage Februar+1
        sjmp Uhr3
Uhr1:   mov  A, #29h         ; .normale Tagzahl für Feb.
        sjmp Uhr3
Uhr2:   mov  A,#TAGpM-Uhr3-1 ; für die Monate außer Feb.
        add  A, dMON         ; Zahl der Tage/Monat+1 aus der
        movc A, @A+PC        ; TAGpM-Tabelle in den A laden
Uhr3:   cjne A, dTAG, UhrEnd ; -MonatsEnde erreicht ?
        mov  dTAG, #1
        mov  A, dMON         ; .Monat+1 und speichern
        add  A, #1
        da   A
        mov  dMON, A
        cjne A, #13h, UhrEnd ; .nach 12.Monat
        mov  dMON, #1
        mov  A, dJAHR        ; Jahr+1 und speichern
        add  A, #1
        da   A
        mov  dJAHR, A
UhrEnd: ret

TAGpM:  DB   '2)2121221212'  ; Anzahl der Tage im
                             ; Monat + 1 (als ASCII-
                             ; Zeichen angegeben)


www..de