/* * Binaeruhr.asm * * Created: 09.11.2020 * Author: Erich */ .INCLUDE "tn2313def.inc" .EQU Spalte, 31 ; die anzuzeigende Spalte (als Bitmaske fuer PORTD) .EQU Tics, 30 ; 100Hz-Tics .EQU nTics, 29 ; wann ist die naechste Sekunde gemessen in 100Hz-Tics .EQU Status, 28 ; Bit 0: Funksignal ; Bit 1: kein Fehler im aktuellen Empfang ; Bit 2: kein Fehler in der aktuellen oder letzten Minute ; Bit 3: MESZ <-> MEZ Umstellung am Ende der Stunde ; Bit 4: Richtung: 0 = MEZ -> MESZ; 1 = MESZ -> MEZ .EQU lHTics, 27 ; wann war die letzte Funk Low-High-Flanke in 100Hz-Tics .EQU Stunde, 0 ; anzuzeigende Stunde .EQU Minute, 1 ; anzuzeigende Minute .EQU Sekunde, 2 ; anzuzeigende Sekunde .EQU Funk0, 3 .EQU Funk1, 4 .EQU Funk2, 5 .EQU Funk3, 6 .EQU Funk4, 7 .EQU Funk5, 8 .EQU Funk6, 9 .EQU Funk7, 10 rjmp RESET reti reti reti rjmp TIMER1COMPA ; Timer1 Compare Match A reti reti reti reti reti reti reti reti reti reti reti reti RESET: ldi r16,lo8(RAMEND) ; Stackpointer initialisieren out SPL,r16 ldi r16,0x80 out CLKPR,r16 ldi r16,0x00 out CLKPR,r16 ; System-Vorteiler auf 1 ldi r16,0x00 out WDTCSR,r16 ; Watchdog aus ldi r17,0xd0 ldi r16,0x55 out OCR1AH,r17 out OCR1AL,r16 ; Timer1 bis 0xd055 laufen lassen (= 300 Hz) ldi r16,0x09 out TCCR1B,r16 ; no prescaler ldi r16,0x40 out TIMSK,r16 ; Counter1 Output Compare A Match Interrupt Enable ldi r16,0xff out PORTB,r16 ; Zeilen (aus) ldi r16,0x7c out PORTD,r16 ; 1x n.d., 1x In (DCF77), 2x In mit Pull-up (Taster), 3x Spalten (aus), 1x n.d. ldi r16,0xff out DDRB,r16 ; Ausgaenge: PORTB (Zeilen) ldi r16,0x70 out DDRD,r16 ; Ausgaenge: PORTD4..6 (Spalten) ldi Spalte,0x10 ldi r16,0x12 mov Stunde,r16 ldi r16,0x34 mov Minute,r16 ldi r16,0x56 mov Sekunde,r16 ldi nTics,100 cbr Status,0xff sei main_loop: bst Status,0 brts high_low_Funkflanke low_high_Funkflanke: mov r16,Tics sub r16,lHTics ; die gemessene "low" Zeit ist der Abstand der letzten lh-Flanke cpi r16,205 brcc Funkfehler ; "low" >= 2050ms -- hierzu ist *keine* Flanke vonnoeten sbis PIND,1 rjmp nach_Funkflanke sbr Status,0x01 mov lHTics,Tics cpi r16,95 brcs Funkfehler ; "low" < 950ms cpi r16,105 brcs neue_Funksekunde ; 950ms <= "low" < 1050ms (= normale Sekunde) cpi r16,195 brcs Funkfehler ; 1050ms <= "low" < 1950ms rjmp neue_Funkminute high_low_Funkflanke: mov r16,Tics sub r16,lHTics ; 10 vs. 20 ( = 100ms vs. 200ms) cpi r16,26 brcc Funkfehler ; high > 250ms -- hierzu ist *keine* Flanke vonnoeten sbic PIND,1 rjmp nach_Funkflanke cbr Status,0x01 cpi r16,5 brcs Funkfehler ; high < 50ms com r16 cpi r16,240 ror Funk7 ror Funk6 ror Funk5 ror Funk4 ror Funk3 ror Funk2 ror Funk1 ror Funk0 sbrs Funk0,3 ; zu viele Bits rjmp nach_Funkflanke Funkfehler: cbr Status,0x06 Funk_initialisieren: clr Funk0 clr Funk1 clr Funk2 clr Funk3 clr Funk4 clr Funk5 clr Funk6 ldi r16,0x80 mov Funk7,r16 rjmp nach_Funkflanke neue_Funksekunde: sbrs Status,2 rjmp nach_Funkflanke ; War die letzte Minute per Funk ok? mov r16,nTics sub r16,Tics ; wie viele Tics bis zur naechsten Sekunde (nach Quarz) mov nTics,Tics ; wir setzen es auf "jetzt" cpi r16,50 ; wurde die Sekunde durch den Quarz schon gezaehlt? brcs nach_Funkflanke ; branch, wenn "noch nicht gezaehlt" subi nTics,(256-100) ; wir setzen es jetz auf "in 100 Tics" nach_Funkflanke: cp nTics,Tics brpl main_loop neue_Sekunde: subi nTics,(256-100) ; naechste Sekunde 100 Tics nach der aktuellen sbis PIND,2 rjmp neue_Stunde sbis PIND,3 rjmp neue_Minute inc Sekunde mov r16,Sekunde cpi r16,60 brcc neue_Minute rjmp main_loop neue_Funkminute: bst Status,1 sbr Status,0x02 ; der nächstminütige Empfang ist bisher ok brtc Funk_initialisieren ; die letzte Minute enthielt schon Fehler sbrs Funk0,4 ; Bit -1: Start-bit da? rjmp Funk_initialisieren sbrc Funk0,5 ; Bit 0: 2.Start-bit da? rjmp Funk_initialisieren mov r16,Funk2 ; Bits 11..18 lsr r16 eor r16,Funk2 sbrs r16,6 ; Bit 17 xor Bit 18 -> ME(S)Z ok? rjmp Funk_initialisieren sbrs Funk3,1 ; Bit 20: Zeit-Start-bit rjmp Funk_initialisieren mov r16,Funk3 mov r17,Funk4 mov r18,Funk5 ror r18 ror r17 ror r16 ror r18 ror r17 ror r16 cbr r17,0x80 mov r18,r16 rcall checksum brts neue_Funkminute_Ende mov r18,r17 rcall checksum brts neue_Funkminute_Ende mov r18,r16 cbr r18,0x80 rcall bcd_to_bin mov Minute,r18 mov r18,r17 cbr r18,0xc0 rcall bcd_to_bin mov Stunde,r18 clr Sekunde sbr Status,0x04 ; die empfangene Minute ist ok mov nTics,Tics subi nTics,(256-100) ; die naechste Sekunde startet in genau 100 Tics bst Funk2,5 ; bit 16: MESZ <-> MEZ Umstellung bld Status,3 bst Funk2,6 ; bit 17: MESZ (1) oder MEZ (0) bld Status,4 neue_Funkminute_Ende: rjmp Funk_initialisieren neue_Minute: clr Sekunde inc Minute mov r16,Minute cpi r16,60 brcc neue_Stunde rjmp main_loop neue_Stunde: clr Sekunde clr Minute sbrc Status,3 ; keine Zeitumstellung => skip sbrs Status,4 ; MESZ -> MEZ => kein Stundeninkrement inc Stunde mov r16,Stunde cpi r16,24 brcc neuer_Tag sbrs Status,3 ; Zeitumstellung rjmp main_loop cbr Status,0x08 ; bitte nur ein Mal sbrc Status,4 ; MEZ -> MESZ => skip rjmp main_loop ; wurde oben schon behandelt rjmp neue_Stunde ; noch eine Stunde weiter vor neuer_Tag: clr Stunde rjmp main_loop TIMER1COMPA: push r16 in r16,SREG push r16 push r17 ldi r17,0x7c out PORTD,r17 mov r17,Spalte lsl Spalte sbrc Spalte,5 mov r16,Stunde sbrc Spalte,6 mov r16,Minute sbrs Spalte,7 rjmp anzeigen mov r16,Sekunde ldi Spalte,0x10 inc Tics anzeigen: com r16 sbrs Spalte,5 rjmp nach_Funkeinfuegung sbr r16,0x80 sbrc Status,0 cbr r16,0x80 sbrc Status,2 subi r16,0x80 nach_Funkeinfuegung: com r17 cbr r17,0x83 out PORTB,r16 out PORTD,r17 pop r17 pop r16 out SREG,r16 pop r16 reti bcd_to_bin: ; input/output: r18; tmp: r19 mov r19,r18 cbr r18,0xf0 swap r19 cbr r19,0xf0 lsl r19 add r18,r19 lsl r19 lsl r19 add r18,r19 ret checksum: ; input: r18; tmp: r19; output: T-Flag mov r19,r18 swap r19 eor r18,r19 mov r19,r18 ror r19 ror r19 eor r18,r19 mov r19,r18 ror r19 eor r18,r19 bst r18,0 ret