Hallo da,

ich bin wie viele andere an einem Wecker dran. Der Kerncode für die
Uhrzeiterfassung steht und ich dachte ich mach den mal Publik.

Funktionsweise:
Der Mega8 läuft mit 4 MHz.
Ich fahre über den Timer1 den InterruptA , wenn Timer1 = 40000, dass
entspricht 10ms. Für die selbstständige Zeitnahme werden daraus die Takte Sekunden, Minuten und Stunden generriert.

Das DCF Modul hängt OHNE Interrupt an PINB 0
und das messen der Pulslängen passiert parallel zur internen Takterzeugung. Das verhindert, das das Programm durch Interruppte vom DCF Modul durcheinandermommt und weiterhin weitere Zeitkritische Prozesse möglich beleiben.

Als Herzstück des Progammes dient das Register "status_reg" in dessen Bitkodierung sich der Status des Progammes wiederfindet.
Code:
.def status_reg = r18
;BIT 0 zeigt an, ob PINB0 während der ISR  HIGH war, dann = 1
;BIT 1 warten auf dcf Anfang =1 => erste lange Pause war da
;Bit 2 zweite lange Pause war da
;BIT 3 wird auf rising edge 1
;BIT 4 wird in dcf_einholen gesetzt, wenn 59 Bits da. enable für dcf_auswerten
;BIT 5 Signal wird ignoriert, bis 1
;BIT 6
;BIT 7 warten auf 2 komplette Signale, enable zum testen der Minuten, ob korrekt
Das Programm loggt sich über das warten auf eine Pause von mindestens 180ms auf den Start der Sequenz ein.


Nur so viel:
An Fehlerbhandlung habe ich zwei Mechanismen.

Das auftreten einer zweiten langen Pause signalisiert, dass ein weiterer Datensatz eingegangen sein muss. Ist die gezählte Bitzahl = 59, wird das Bitmuster ausgewertet. Stimmt das nicht, wird eine Fehlerroutine aufgerufen, in der alle Prozessrelevanten Register genullt werden. Bis auf die interne Zeitzählung natürlich.

Die intern ermittelte Zeitzählung kann nur überschrieben werden, wenn zwei Minutenabfolgen sich nur um 1 unterscheiden oder im Fall des Stundenwecjsels um 59.

Auf eine verbale Erklärung wie das Proramm genau Funktioniert verzichte ich hier. Ich werde dann mal zusehen, dass ich Flussdiagramme erstelle.

Edit:

wobei, ich merke, grade, dass ich keine .odt Dateien hochladen kann...

Code:
.include "m8def.inc"

.def tmp = r16
.def tmp2 = r17
.def status_reg = r18
;BIT 0 zeigt an, ob PINB,0 während der ISR HIGH war, dann = 1
;BIT 1 warten auf dcf Anfang =1 => erste lange Pause war da
;Bit 2 zweite lange Pause war da
;BIT 3 wird auf rising edge 1
;BIT 4 wird in dcf_einholen gesetzt, wenn 59 Bits da. enable für dcf_auswerten
;BIT 5 Signal wird ignoriert, bis 1
;BIT 6
;BIT 7 warten auf 2 komplette Signale, enable zum testen der Minuten, ob korrekt 
.def pw_kurz = r19; Pulslänge der Highpegel
.def pw_lang = r20; Pulslänge der Lowpegel
.def bit_counter = r21

.def dcf_shift_reg = r24
.def sreg_save = r25

.equ dcf_BIT_counter = 104
.equ eins = 1
.equ zwei = 2
.equ vier = 4
.equ acht = 8
.equ zehn = 10
.equ zwanzig = 20
.equ vierzig = 40

.org 0x000
  rjmp reset
.org OC1Aaddr
     rjmp timer1_int
.org OC1Baddr
     rjmp timer1b_int

;*****************************************	
;*****************************************	
;         Pointer Z
; 
;              ms = RAM 100
;              sc = RAM 101
;             min = RAM 102
;          stunde = RAM 103
; dcf_BIT_counter = RAM 104 (0 bis 8 für Bytecounter)
;         dcf_min = RAM 113     
;     dcf_min_alt = RAM 114
;         dcf_stu = RAM 115   
;******************************************

;******************************************
;        Pointer Y

;     dcf BIT 0-7 = RAM 105
;    dcf BIT 8-15 = RAM 106
;   dcf BIT 16-23 = RAM 107
;   dcf BIT 24-31 = RAM 107
;   dcf BIT 32-39 = RAM 108
;   dcf BIT 40-47 = RAM 109     
;   dcf BIT 48-55 = RAM 110
;   dcf BIT 56-59 = RAM 111

reset:
   ;Stack wird bei Interrupts benötigt! 
   ldi tmp,HIGH(RAMEND) 
   out SPH,tmp 
   ldi tmp,LOW(RAMEND) 
   out SPL,tmp
   ldi tmp,0xFF
   out DDRD,tmp
   ldi tmp,0

   ldi r28,105
   ldi r29,0

   ldi r31,0
   ldi r30,100
   st Z+,tmp
   st Z+,tmp
   st Z+,tmp 
   st Z+,tmp 
   st Z,tmp
   ldi r30,100
   
   ldi tmp,0
   out DDRC,tmp
   ldi tmp,0b00110000
   out PORTC,tmp
   ldi tmp,0
   out DDRB,tmp
   ldi tmp,0
   out PORTB,tmp
   ldi tmp,0b00011000
   out TIMSK,tmp
 
   ldi tmp,0b00000001 
   out OCR1BH,tmp
   ldi tmp,0b11111010 ;InterupptB wenn Timer1 = 201 
   out OCR1BL,tmp

ldi tmp,0b10011100
   out OCR1AH,tmp
   ldi r17,0b01000000 ; InterupptA wenn Timer1 = 40000
   out OCR1AL,r17

   ldi tmp,0b00000000
   out TCCR1A,tmp
   ldi tmp,0b11001001 ;Prescaler Timer1 = 1, enable Int, A und B
   out TCCR1B,tmp
   ldi r17,0
   ldi status_reg,0
   
   ldi r28,105
   
ldi dcf_shift_reg,0
st Y+,dcf_shift_reg
st Y+,dcf_shift_reg
st Y+,dcf_shift_reg
st Y+,dcf_shift_reg
st Y+,dcf_shift_reg
st Y+,dcf_shift_reg
st Y+,dcf_shift_reg
st Y,dcf_shift_reg
ldi r28,105

ldi bit_counter,0
   sei
   main:
;**********************************
; Funktion dcf_einholen wird aufgerufen, wenn
; pw_kurz > 4  und am ISR Anfang keinSignal da war
; pw_kurz wird in dcf_einholen gelöscht
;pw_kurz kann nur erhöht werden, wenn 
;lange Pause da war => keine Abfrage von 
;Bit 1 im status_reg nötig
   cpi pw_kurz,5
   brlo dcf_nicht_einholen
   sbrc status_reg,0b00000000; 
   rjmp dcf_nicht_einholen
   rcall dcf_einholen
   
;**********************************
;   out PORTD,r28

   dcf_nicht_einholen:

  sbrs status_reg,0b00000001
  rjmp nicht_auswerten;ertste Pause muss da gewesen sein, um dcf_auswerten aufzurufen
  
  sbrs status_reg,0b00000010
  rjmp nicht_auswerten;zweite Pause muss da gewesen sein, um dcf_auswerten aufzurufen
  
  sbrc status_reg,0b00000100; ist Aufruf von dcf_auswerten in Abhängigkeit
  ; der zweiten langen Pause freigegeben, aber keine 59 Bits da, wird fehlerroutine
  ; aufgerufen 
  rjmp auswerten
  rcall fehlerroutine ;Freigabe von dcf_einholen => 59 Bits da
  rjmp nicht_auswerten
  auswerten:
   rcall dcf_auswerten
   nicht_auswerten:
   
  
  
   rjmp main




fehlerroutine:
;rücksetzten aller Prozessrelevanten Register
ldi status_reg,0 
ldi r28,105
st Y,status_reg
ldi r30,104
st Z,status_reg
ldi r30,100
ldi pw_kurz,0
ldi pw_lang,0
ret



dcf_einholen:
/*
1.) prüft Pulsweite auf >< 160 ms
2.) erhöht Y Pointer, wenn ein Byte voll ist
3.) speichert bei "überlauf" von bit_counter=8 bit_counter = 0 ab
*/

	 
     ldi r30,dcf_BIT_counter
	 ld tmp,Z
	 ld dcf_shift_reg,Y;
	 lsr dcf_shift_reg
      	 
 	 cpi pw_kurz,16; 1.) prüft Pulsweite auf >< 160 ms
	 brlo log_null
     ori dcf_shift_reg,0b10000000
	 log_null:
	 
     st Y,dcf_shift_reg    
	 sbrs tmp,0b00000011
	 rjmp vollmachen
	 ldi tmp,0
	 st Z,tmp
	 
	 inc r28
	 
	 ldi dcf_shift_reg,0
	 vollmachen:
     
ldi pw_kurz,0
ldi r30,100
inc bit_counter
cpi bit_counter,59

brne mehr1
ori status_reg,0b00010000;Freigabe von dcf_auswerten
ldi bit_counter,0
mehr1:
ret


dcf_auswerten:

ldi r30,dcf_BIT_counter
ldi tmp,0
st Z,tmp
ori status_reg,0b10000000
andi status_reg,0b11101011; löschen der Freigabe von lange Pause_war_da
                          ; und Aufruf von dcf_auswerten




/*
wertet die Bitmuster in RAM 107 bis 109 in Minuten und Stunden aus

*/
  
;***************************
;       Minuten


ldi r28,107

ld tmp,Y
inc r28;lädt von 107 dann inc zu 108
ldi r22,0

ldi tmp2,1
sbrc tmp,0b00000101
add r22,tmp2

ldi tmp2,2
sbrc tmp,0b00000110
add r22,tmp2

ldi tmp2,4
sbrc tmp,0b00000111
add r22,tmp2


ld tmp,Y

inc r28;lädt von 108 dann inc zu 109

ldi tmp2,8
sbrc tmp,0b00000000
add r22,tmp2

ldi tmp2,10
sbrc tmp,0b00000001
add r22,tmp2

ldi tmp2,20
sbrc tmp,0b00000010
add r22,tmp2

ldi tmp2,40
sbrc tmp,0b00000011
add r22,tmp2


ldi r30,113
st Z,r22
ldi r30,115
ldi r22,0
;***************************

;***************************
;     Stunde

ldi tmp2,eins
sbrc tmp,0b00000101
add r22,tmp2

ldi tmp2,2
sbrc tmp,0b00000110
add r22,tmp2

ldi tmp2,4
sbrc tmp,0b00000111
add r22,tmp2

ld tmp,Y ;lädt von 109
ldi tmp2,8
sbrc tmp,0b00000000
add r22,tmp2

ldi tmp2,10
sbrc tmp,0b00000001
add r22,tmp2

ldi tmp2,20
sbrc tmp,0b00000010
add r22,tmp2

st Z,r22
ldi r22,0
ldi r30,100
;***************************
; nullen der Ramstellen
ldi r28,105
ldi dcf_shift_reg,0
st Y+,dcf_shift_reg
st Y+,dcf_shift_reg
st Y+,dcf_shift_reg
st Y+,dcf_shift_reg
st Y+,dcf_shift_reg
st Y+,dcf_shift_reg
st Y+,dcf_shift_reg
st Y,dcf_shift_reg
ldi r28,105


ret


timer1b_int:

in sreg_save,SREG
sbrs status_reg,0b00000111
  rjmp wigger0  

  
;******************************************************
; Uhrzeit gültig, wenn die neue Minute 1 größer als die
; alte ist, oder 59 kleiner bei Stundenwechsel
;Minuten und Stunden werden nur überschrieben, wenn 
;korrekte Minutenfolge erkannt wurde
ldi r30,113
ld tmp,Z ;min neu

ldi r30,114
ld tmp2,Z;min alt

ldi r30,114
st Z,tmp ;neu wird zu alt für den folgenden Vergleich

cp tmp2,tmp
breq fehler
brsh min_uberlauf
sub tmp,tmp2
cpi tmp,1
brne fehler


rjmp sig_erfasst

min_uberlauf:
sub tmp2,tmp ; alt - neu
cpi tmp2,59
brne fehler
sig_erfasst:
;******************************************************

ldi r30,102
ld tmp2,Z
ldi r30,113
ld tmp,Z
;*************************
;überschreiben der Minute
ldi r30,102
mov tmp2,tmp
st Z,tmp2
;*************************
;*************************
;überschreiben der Stunde
ldi r30,115
ld tmp,Z
ldi r30,103
st Z,tmp
;*************************

fehler:
wigger0:



out SREG,sreg_save
reti

 

 timer1_int:
 in sreg_save,SREG
 sbrs status_reg,0b00000101
 rjmp ignore
  ;****************************
  ; setzt Bit 0 in status_reg, wenn Signal da (PINB_0 HIGH)  ist
  ; setzte Bit 3 in status_reg auf rising edge 
  sbis PINB,0
  rjmp kein_signal_an_pinb0 
   sbrs status_reg,0b00000000
   ori status_reg,0b00001000
    ori status_reg,0b00000001
	rjmp signal_da
  kein_signal_an_pinb0:
  andi status_reg,0b11111110
  signal_da:
;**************************

;***************************
; ausführen wenn kein Signal 
; hier wird die Zeit zwischen zwei Highpegeln gemessen,
; um die lange Pause zu erfassen  
  sbrc status_reg,0b00000000
  rjmp warten_auf_pause
; wenn Bit 0 nin status_reg = 0, dann kein Signal
 
    inc pw_lang
    cpi pw_lang,120
    brlo warten_auf_pause
	ldi r22,0
	ldi pw_lang,0
    sbrc status_reg,0b00000001
    rjmp zweite_lange_Pause
       
        ori status_reg,0b00000010      
    rjmp warten_auf_pause
    zweite_lange_Pause:
	ori status_reg,0b00000100
    

 
	   
	   

    rjmp war_keins_da 
 
 warten_auf_pause:

 war_keins_da: 
;***************************

;***************************
;ausführen, wenn zu ISR Anfang Signal HIGH war und
;lange Pause da war  (Einloggen auf Sequenzanfang)
 sbrs status_reg,0b00000000
 rjmp warten_auf_signal
 sbrs status_reg,0b00000001
 rjmp warten_auf_signal
 
 inc pw_kurz
 ldi pw_lang,0;sonst würden sich die kleinen Pausen aufsummieren
 
 warten_auf_signal:

 sbrc status_reg,0b00000000
 ldi pw_lang,0


 sbrs status_reg,0b00000011
 rjmp fix
 ldi r30,dcf_BIT_counter
 ld tmp,Z
 inc tmp
 st Z,tmp


 andi status_reg,0b11110111
 fix: 

ignore:


ldi r30,101
  ld tmp,Z
  cpi tmp,10
  brlo wait_for_sig
 sbic PINB,0
 sbr status_reg,0b00100000;
wait_for_sig:


;****************** Zählen der ms RAM 100
  ldi r30,100
  ld tmp,Z
  inc tmp
  st Z,tmp
  cpi tmp,100 
  brlo mehr
  ldi tmp,0
  st Z+,tmp
;******************

;****************** Zählen der sec RAM 101

  ld tmp,Z
  inc tmp
  st Z,tmp

  cpi tmp,60
  brlo mehr 
  ldi tmp,0
  
  st Z,tmp
  inc r30
;****************** 

;****************** Zählen der min RAM 102

  
 ld tmp,Z
 inc tmp
out portd,tmp
 st Z,tmp
 cpi tmp,60
 brlo mehr
 ldi tmp,0
 st Z,tmp
 inc r30


;******************

;****************** Zählen der Stunde RAM 103
 ld tmp,Z
 inc tmp
 st Z,tmp
 cpi tmp,25
 ldi tmp,0
 st Z,tmp
;******************
 mehr:
ldi r30,100
 out SREG,sreg_save
reti
mfg,
The Man