Hallo Leute,

jetzt ist meine Version der Dcf77_soft.lib fertig geworden und getestet.
Die 1. Version stammt von albundy.

Was ich wollte: Die Softclock von Bascom nutzen ohne Uhrenquarz an TOSC1/2 mit der Möglichkeit, ein Aktualisieren der Softclock durch DCF zu machen (z.B. jede Stunde oder 1x am Tag ...).

Dazu habe ich die dcf77_soft.lib von albundy um folgende Funktionen erweitert:

1. Status-Bit 5 bedeutet: Uhr wurde 1x nach DCF gestellt. Das Bit bleibt high, bis das Basic-Programm es auf low setzt oder bis der Wochentag auf 29, 30 oder 31 wechselt (weil die lib nicht weiß, wieviele Tage der Monat hat und deshalb das Datum evtl. falsch ist).

2. Status-Bit 7 bedeutet: Uhr kann nach DCF gestellt werden. Ist das Bit low, läuft nur die Softclock intern weiter ohne DCF-Empfang. Das Bit muss vom Basic-Programm gestellt werden.

3. Die Softclock zählt jetzt auch das Datum (Tag, Monat, Jahr) mit korrektem Überlauf weiter. Status.5 wird gelöscht, wenn Tag 29, 30 oder 31 erreicht ist, damit kann dann das Basic-Programm z.B. den DCF-Empfang einschalten (Status.7 = 1), um das Datum neu zu holen.

Hier die lib:
Code:
copyright    = W.Krueger
comment      = DCF 77 Decoder
libversion   = 2.00 (D. Ottensmeyer)
date         = 09.04.2006
statement    = ----------------------------------
statement    = muss alle 25ms ausgeführt werden !
statement    = ----------------------------------

[Dcf77]
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 Temp3   = r18
.def Minute  = r19
.def Stunde  = r20
.def Status  = r21
              ;Bit0 = aktueller DCF Status
              ;Bit1 = vorheriger DCF Status
              ;Bit2 = Uhr synchronisieren
              ;Bit3 = 59 Impulse empfangen
              ;Bit4 = Parität OK
              ;Bit5 = Uhr wurde 1x gestellt
              ;Bit7 = Uhr nach DCF stellen
.def Impuls  = r22
.def Zaehler = r23
.def Buffer  = r24
.def Pari    = r25
;------------------------------------
 *lds Status,{Status}         ;Status laden
  rcall Softuhr               ;Softuhr bearbeiten
  bst Status,7                ;Status Uhr nach DCF stellen ?
  brts Puls0                  ;ja -> weiter
 *sts {Status},Status
  ret
Puls0:
 *lds Impuls,{Impuls}         ;Variablen laden
 *lds Zaehler,{Zaehler}
 *lds Buffer,{Buffer}
 *lds Pari,{Pari}    
  in temp1,Dcf_Port           ;DCF Port lesen
  bst temp1,Dcf_Pin           ;Status holen
  bld Status,0                ;aktuellen Status speichern
  inc Zaehler                 ;Impulslänge erhöhen
  bst Status,0                ;akuellen 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 Zaehler,temp1            ;Impulslänge Minimalwert überschritten
  brcs Puls10                 ;nein -> weiter
 *sts {Pau},Zaehler           ;--------> Minutenimpulslänge speichern für Debug
  clr Buffer                  ;Empfangspuffer löschen
  clr Impuls                  ;Impulszähler löschen
  bst Status,4                ;Parität OK ?
  brtc Puls5                  ;Nein -> weiter
  bst Status,3                ;59 Impulse empfangen ?
  brtc Puls5                  ;Nein -> weiter
  set
  bld Status,2                ;Status Uhr synchronisieren setzen
Puls5:
  clt
  bld Status,3                ;Status 59 Impulse löschen
  bld Status,4                ;Status Parität OK löschen
Puls10:
  clr Zaehler                 ;Impulslänge löschen
  rjmp Puls40                 ;Ende
Puls20:
  bst Status,1                ;vorherigen Status prüfen
  brts Puls40                 ;vorheriger Status Low -> Ende
  ldi temp1,Imp1min           ;Minimalwert für "1" Impuls laden 
  cp Zaehler,temp1            ;Minimalwert unterschritten ?
  brcs Puls30                 ;ja -> weiter
 *sts {imp},Zaehler           ;--------> Impulslänge Height speichern für Debug
  cpi Impuls,28               ;beim Paritätsbit Min keine Negation
  breq Puls25
  cpi Impuls,35               ;beim Paritätsbit Std keine Negation
  breq Puls25
  ldi Temp1,1
  eor Pari,Temp1              ;Paritätsbit Negation
Puls25:
  sec                         ;Carry setzen ( "1" empfangen )
  ror Buffer                  ;Carry in Empfangspuffer
  inc Impuls                  ;Impulszähler erhöhen
  rcall Auswerten             ;Impulse auswerten
  rjmp Puls40                 ;Ende
Puls30:
 *sts {imp},Zaehler           ;--------> Impulslänge Low speichern für Debug
  clc                         ;Carry löschen ( "0" empfangen )
  ror Buffer                  ;Carry in Empfangspuffer
  inc Impuls                  ;Impulszähler erhöhen
  rcall Auswerten             ;Impulse auswerten
Puls40:
  bst Status,0                ;aktuellen Status holen
  bld Status,1                ;Status speichern
 *sts {Status},Status         ;Variablen wieder speichern
 *sts {Impuls},Impuls
 *sts {Zaehler},Zaehler
 *sts {Buffer},Buffer
 *sts {Pari},Pari
  ret
;-------------------------------------------------------------------------------
Softuhr:
 *lds Temp1,{H_Sek}
 *lds Temp2,{_sec}
 *lds Minute,{_min}       
 *lds Stunde,{_hour} 
  bst Status,2                ;Status Uhr synchronisieren ?
  brtc Soft10                 ;nein -> weiter Softuhr
  clt
  bld Status,2                ;Status Synchron löschen
  bst Status,7                ;Status Uhr nach DCF stellen ?
  brtc Soft10                 ;nein -> nicht neu stellen
  set
  bld Status,5                ;Status Uhr 1x gestellt setzen
  clr Temp1                   ;Hundertstel löschen
  clr Temp2                   ;Sekunde löschen
 *lds Minute,{T_Min}          ;Minute auf empfangene Minute
 *lds Stunde,{T_Std}          ;Stunde auf empfangene Stunde
  rjmp Soft20                 ;empfangene Zeit übernehmen
Soft10:
  inc Temp1                   ;Hundertstel Sek erhöhen
  cpi Temp1,40                ;1000ms erreicht ?
  brne Soft20                 ;nein -> Ende
  clr Temp1                   ;Hundertstel Sek löschen
  inc Temp2                   ;Sekunde erhöhen
  cpi Temp2,60                ;60 Sekunden erreicht ?
  brne Soft20                 ;nein -> Ende
  clr Temp2                   ;Sekunde löschen
  inc Minute                  ;Minute erhöhen
  cpi Minute,60               ;60 Minuten erreicht ?
  brne Soft20                 ;nein -> Ende
  clr Minute                  ;Minute löschen
  inc Stunde                  ;Stunde erhöhen
  cpi Stunde,24               ;24 Stunden erreicht ?
  brne Soft20                 ;nein -> Ende
  clr Stunde                  ;Stunde löschen
 *lds Temp3,{_day}
  inc Temp3                   ;Tag erhöhen
  cpi Temp3,29                ;Tag 29 erreicht ?
  brlo Soft19                 ;bis 28 -> Ende
  clt                         ;ab 29  -> Hat Monat 29,30,31 Tage ?
  bld Status,5                ;Status Uhr 1x gestellt löschen
;  set                         ;Datum nach DCF stellen !
;  bld Status,7                ;Status Uhr nach DCF stellen setzen
  cpi Temp3,32                ;Tag 32 erreicht ?
  brne Soft19                 ;nein -> Ende
  ldi Temp3,1                 ;Tag 1 setzen
 *sts {_day},Temp3
 *lds Temp3,{_month}
  inc Temp3                   ;Monat erhöhen
  cpi Temp3,13                ;Monat 13 erreicht ?
  brne Soft18                 ;nein -> Ende
  ldi Temp3,1                 ;Monat 1 setzen
 *sts {_month},Temp3
 *lds Temp3,{_year}
  inc Temp3                   ;Jahr erhöhen
  cpi Temp3,100               ;Jahr 100 erreicht ?
  brne Soft17                 ;nein -> Ende
  clr Temp3                   ;Jahr 00 setzen
Soft17:
 *sts {_year},Temp3
  rjmp Soft20
Soft18:
 *sts {_month},Temp3
  rjmp Soft20
Soft19:
 *sts {_day},Temp3
Soft20:
 *sts {H_Sek},Temp1
 *sts {_sec},Temp2
 *sts {_min},Minute
 *sts {_hour},Stunde  
  ret
;-------------------------------------------------------------------------------
Auswerten:
  cpi Impuls, 21              ;21. Impuls
  brne Aus10                  ;nein -> weiter
  clr Buffer 
  clr Pari         
Aus10:          
  cpi Impuls, 28             ;28. Impuls
  brne Aus15                 ;nein -> weiter
  lsr Buffer                 ;Buffer 1x schieben, da Minute nur 7 Bit
  rcall Bcd2dez              ;in Dezimal wandeln
 *sts {T_Min},Buffer         ;Temp Minute schreiben
  clr Buffer   
Aus15: 
  cpi Impuls, 29             ;Minuten Parität
  brne Aus20
  clr Temp3
  bst Buffer,7               ;Paritätsbit selektieren
  bld Temp3,0                ;Paritätsbit in Temp3 Bit0 kopieren
  cp Temp3,Pari              ;Parität überprüfen
  brne Aus26                 ;Fehler -> Ende
  clr Pari
  clr Buffer
Aus20:  
  cpi Impuls, 35             ;35. Impuls
  brne Aus25                 ;nein -> weiter
  lsr Buffer                 ;Buffer 2x schieben, da Stunde nur 6 Bit
  lsr Buffer
  rcall Bcd2dez              ;in Dezimal wandeln
 *sts {T_Std},Buffer         ;Temp Stunde schreiben
  clr Buffer
Aus25: 
  cpi Impuls, 36             ;Stunden Parität
  brne Aus30
  clr Temp3
  bst Buffer,7               ;Paritätsbit selektieren
  bld Temp3,0                ;Paritätsbit in Temp3 Bit0 kopieren
  cp Temp3,Pari              ;Parität überprüfen
  breq Aus27                 ;Pari OK -> weiter
Aus26:
  ret                        ;Fehler -> Ende 
Aus27: 
  set                        ;T-Bit setzen
  bld Status,4               ;Bit4 Status setzen (Parität) 
  clr Buffer  
Aus30:                
  cpi Impuls,42              ;42. Impuls
  brne Aus40          
  lsr Buffer                 ;Buffer 2x schieben, da Tag nur 6 Bit
  lsr Buffer          
  rcall Bcd2dez              ;in Dezimal wandeln 
 *sts {_day},Buffer          ;Tag schreiben
  clr Buffer      
Aus40:       
  cpi Impuls,45              ;45. 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 {WoTag},Buffer        ;Wochentag schreiben
  clr Buffer   
Aus50: 
  cpi Impuls,50             ;50. Impuls
  brne Aus60           
  lsr Buffer                ;Buffer 3x schieben, da Monat nur 5 Bit
  lsr Buffer          
  lsr Buffer          
  rcall Bcd2dez             ;in Dezimal wandeln 
 *sts {_month},Buffer       ;Monat schreiben
  clr Buffer         
Aus60:           
  cpi Impuls,58             ;58. Impuls
  brne Aus70          
  rcall Bcd2dez             ;in Dezimal wandeln 
 *sts {_year},Buffer        ;Jahr schreiben
  clr Buffer     
Aus70:
  cpi Impuls,59             ;59. Impuls
  brne Aus80          
  set                       ;T-Bit setzen
  bld Status,3              ;Bit3 Status setzen (59 Impulse)
Aus80:
  cpi Impuls,60             ;bei mehr als 59 Impulsen (Störimpulse)
  brne Aus90          
  clt                       ;T-Bit löschen
  bld Status,3              ;Bit3 Status löschen (59 Impulse)
  bld Status,4              ;Bit4 Status löschen (Parität)  
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]
... und ein Testprog mit einem 4x16 LCD:
Code:
$regfile = "m32def.dat"                                     'ATmega 32
$crystal = 8000000                                          'Quarz: 8 MHz
$baud = 9600
$hwstack = 32                                               'hardware stack
$swstack = 10                                               'software stack
$framesize = 40                                             'frame space

Config Date = Dmy , Separator = .                           'deutsches Format für Datum
Config Clock = Soft
Disable Timer2                                              'ausgeschaltet lassen

$lib "dcf77_soft.lib"                                       'LIB für DCF77
$external Dcf77
Declare Sub Dcf77

'###########################################################################

'Hauptprogramm:

'LCD konfigurieren:
Wait 1
Config Lcdpin = Pin , Db4 = Portb.4 , Db5 = Portb.5 , Db6 = Portb.6 , Db7 = Portb.7 , E = Portb.1 , Rs = Portb.0
Config Lcd = 16 * 4                                         'LCD 164A

'Startmeldung:
Cls
Lcd "* RNBFRA V1.22 *"
Wait 5
Cls

Config Timer0 = Timer , Prescale = 1024                     'Timer 40Hz
Const Startwert = 61                                        'Für 8MHz
Timer0 = Startwert
On Timer0 Tim0_isr                                          'Überlauf alle 25ms
Enable Interrupts
Enable Timer0

'---------------------- Pin für DCF Eingang definieren ---------------------
'Jeder Portpin kann benutzt werden.
'Auch in der "Dcf77_soft.lib" entsprechend anpassen !!!

Config Pind.3 = Input                                       'DCF 77 Eingang
Set Portd.3                                                 'Pullup ein

Declare Sub Showstatus()
Declare Sub Showtime()

'------------------- Variablen für DCF Routine -----------------------------

Dim Status As Byte , Zaehler As Byte , Buffer As Byte , Impuls As Byte
Dim H_sek As Byte , T_min As Byte , T_std As Byte , Wotag As Byte
Dim Pari As Byte , Pau As Byte , Imp As Byte

Dim I As Byte

'---------------------------------------------------------------------------

'Hauptprogramm:
Cls
Cursor Off

Date$ = "01.01.00"
Time$ = "00:00:00"

Status.7 = 0                                                'Uhr nach DCF stellen: AUS
Status.5 = 0                                                'Uhr wurde nicht gestellt
I = 0

'****************** HAUPTPROGRAMMSCHLEIFE **********************************

Do
  Cls
  Call Showtime()
  Call Showstatus()
  If _min = 58 And Status.7 = 0 Then Status.5 = 0           '1x pro Stunde nach DCF stellen
  If Status.5 = 0 Then Status.7 = 1 Else Status.7 = 0       'Zeit nicht aktuell: Stellen!
  Wait 1
Loop

End

'************* ENDE HAUPTPROGRAMM ******************************************

Sub Showstatus()                                            'Status anzeigen

  If I = 0 Then I = 1 Else I = 0
  Locate 1 , 1
  If Status.5 = 1 Then
    Lcd "*DCF-Soft Clock*"
  Else
    Lcd "***Soft Clock***"
  End If

  Locate 4 , 1
  If Status.7 = 1 Then
    Lcd "DCF:On "
  Else
    Lcd "DCF:Off"
  End If

  Locate 4 , 9
  If Status.4 = 1 And I = 0 Then
    Lcd "  Signal"
  Else
    Lcd "        "
  End If

End Sub
'---------------------------------------------------------------------------

Sub Showtime()

  Locate 2 , 5
  Lcd Time$                                                 'Zeit an LCD
  'Print Time$                                               'Zeit an Terminal

  If Status.5 = 1 Then
    Locate 3 , 3
    Wotag = Dayofweek()
    Lcd Lookupstr(wotag , Wochentag) ; ". "
    Lcd Date$
  End If

End Sub
'---------------------- Interrupt Routine DCF77 ----------------------------

Tim0_isr:
  Timer0 = Startwert
  Call Dcf77
Return

'###########################################################################
'Programm Ende:

End

'---------------------- Daten für Wochentag --------------------------------
Wochentag:
Data "Mo" , "Di" , "Mi" , "Do" , "Fr" , "Sa" , "So"

'###########################################################################
Die Demo zeigt neben Uhrzeit und Datum, ob die Softuhr ohne DCF-Aktualisierung läuft "Soft Clock" oder schon 1x nach DCF gestellt wurde "DCF-Soft Clock".
In der 4. Zeile erscheint "DCF:Off", wenn in der lib keine DCF-Decodierung erfolgt oder "DCF:On", wenn der Decoder eingeschaltet ist.
Dort blinkt auch "Signal", wenn die Parität o.k. ist (heißt: Es liegt wohl ein DCF-Signal an ...).

Viel Spaß damit.

Gruß Dirk