- Labornetzteil AliExpress         
Ergebnis 1 bis 2 von 2

Thema: Flussdiagram DCF-77 Code

  1. #1
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    12.06.2006
    Beiträge
    478

    Flussdiagram DCF-77 Code

    Anzeige

    Praxistest und DIY Projekte
    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
    Chuck Norris kann Windows Vista auf einem Atmel in Assembler implementieren!
    Chuck Norris coded mit 3 Tasten:"1","0" und "compile"

  2. #2
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    12.06.2006
    Beiträge
    478
    so, mit PDF geht´s wohl.

    Die Reihenfolge der Programteile ist IntA => dcf_einholen => dcf_auswerten => IntB


    EDIT:
    Ich habe grade gesehen, dass in IntA die Detektion zur rising edge nicht stimmte und sich auf der Seite der Zeitgenerierung Fehler eingeschlichen hatten ( "Ja" und "Nein" vertauscht) hier noch die korrigierte Version.
    Angehängte Dateien Angehängte Dateien

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

Labornetzteil AliExpress