;*************************************************** ; DCF77 Decoder Uhr: ; Anzeige von Zeit, Datum, Wochentag, ; Sommer-/Winterzeit-Kuerzel, Quarz-Gangreserve ; Ausgabe auf LCD und RS232 ; MCU: ATMEL AVR ATtiny4313 ; DCF77 input code low active = PD6 ; DCF77 output code ASCII 0/1 = PD1,RS232,9k6,8N1 ; Quarzfrequenz 4,096 MHz (3,686 MHz) ; ; ; ; LCD 2x16, Vierbitmodus ; PortB LCD Ausgabe: R/W=GND ; PB7 PB6 PB5 PB4 PB3 PB2 PB1 PB0 ; D7 D6 D5 D4 n/c LED ena rs ; ; ATtiny4313 memory use summary [bytes]: ; Segment Begin End Code Data Used Size Use% ;[.cseg] 0x000000 0x000810 2022 36 2058 4096 50.2% ;[.dseg] 0x000060 0x00007b 0 27 27 256 10.5% ;[.eseg] 0x000000 0x000000 0 0 0 256 0.0% ;Assembly complete, 0 errors. 0 warnings ; Rev.: 04052026 ; Abgewandelt nach Vorlage Wohnuhr Scott Falk Huehn ;*************************************************** ; ;Assemblerdirektiven: ; .nolist .include "tn4313def.inc" .list ; ; Definitionen: ; Im SRAM reservierte Bytes ; .dseg ; Datensegment (SRAM) Start bei .org 0x0060 ; Adresse 0x0060 ; precnt: ; Vorteiler 1:100 fuer Gangreserve .byte 1 sekunde: ; Sekundenpufferbyte binaer .byte 1 minute: ; Minutenpufferbyte binaer .byte 1 stunde: ; Stundenpufferbyte binaer .byte 1 tag: ; Tag-Pufferbyte binaer (1-31) .byte 1 monat: ; Monat-Pufferbyte binaer (1-12) .byte 1 jahr: ; Jahr-Pufferbyte binaer (0-99) .byte 1 wtag: ; Wochentag-Pufferbyte binaer (1-7) .byte 1 block: ; Stoeraustastung .byte 1 dcftab: ; DCF77-Tabelle, eingehende Bits werden in .byte 6 ; Byte 5, Bit 7 eingeschoben und alle weiteren ; Bits um eine Position weitergerueckt, ; Byte/Bit: ; 0/6-7: 0bxx000000 Zeitzone (6=1 Som,7=1 Wint) ; 1/2-5: 0b00xxxx00 Minute Einer ; 1/6-7: 0bxx000000 Minute Zehner LSB ; 2/0: 0b0000000x Minute Zehner MSB ; 2/1: 0b000000x0 Pruefbit 1 (Minuten) ; 2/2-5: 0b00xxxx00 Stunde Einer ; 2/6-7: 0bxx000000 Stunde Zehner ; 3/0: 0b0000000x Pruefbit 2 (Stunden) ; 3/1-4: 0b000xxxx0 Kalendertag Einer ; 3/5-6: 0b0xx00000 Kalendertag Zehner ; 3/7: 0bx0000000 Wochentag LSB ; 4/0-1: 0b000000xx Wochentag MSB ; 4/2-5: 0b00xxxx00 Monat Einer ; 4/6: 0b0x000000 Monat Zehner ; 4/7: 0bx0000000 Jahr Einer LSB ; 5/0-2: 0b00000xxx Jahr Einer MSB ; 5/3-6: 0b0xxxx000 Jahr Zehner ; 5/7: 0bx0000000 Pruefbit 3 (Datum) ; dcbuf1: ; DCF-Puffer 1, aktuelle, decodierte Uhrzeit .byte 12 ; Byte 0: 0b0000000x Zeitzone ; Byte 1: 0b0000xxxx Minute Einer ; Byte 2: 0b00000xxx Minute Zehner ; Byte 3: 0b0000xxxx Stunde Einer ; Byte 4: 0b000000xx Stunde Zehner ; Byte 5: 0b0000xxxx Kalendertag Einer ; Byte 6: 0b000000xx Kalendertag Zehner ; Byte 7: 0b00000xxx Wochentag ; Byte 8: 0b0000xxxx Monat Einer ; Byte 9: 0b0000000x Monat Zehner ; Byte 10: 0b0000xxxx Jahr Einer ; Byte 11: 0b0000xxxx Jahr Zehner ; ; ; Konstanten-Definitionen: .equ daten = portb .equ light = 2 ; 0b00000x00 PB2 LCD-Beleuchtung .equ ena = 1 ; 0b000000x0 PB1 Enable .equ rs = 3 ; 0b0000000x PB0 Register Select .equ delay0 = 1024 ; Zeitschleifen Ladewerte .equ delay1 = 65535 ;.equ MCUfreq = 4096000; Quarzfrequenz 4,096 MHz(resp.3686000) ; ; (Fuses:0xFD,0xDF,0xFF) .equ comp = 40959; Timer compare bei 10 ms {MCUfreq/(40960-1)} ; ; (STK500=36859;bei 4 MHz=39999) .equ bdrt = 27 ; (24)Baudratenteiler fuer 9600 Bd festlegen ; ;Registerdefinitionen: .def dcfsec = r9 ; DCF77 Sekundenmarkenzaehler (0-59) .def dcfcnt = r10 ; DCF77-Sampling, PD6 low {x*(1/100) sec} .def flags = r11 ; Verschiedene Flags ; Bit 0: akueller DCF77-Zustand - high oder low ; Bit 1: vorheriger DCF77-Zustand ; Bit 2: Uhr wurde mind. einmal synchronisiert ; Bit 3: Start neue Minute;TimerISR set,main reset ; Bit 4: Datum gueltig ; Bit 5: nicht belegt ; Bit 6: nicht belegt ; Bit 7: nicht belegt .def inttmp = r12 ; Temporaerregister fuer Interrupt-Routinen .def flags1 = r13 ; Flagregister fuer Gangreserve ; ; Bit 0: Sperrbit bei Synchronisation ; ; Bit 1: Ausgabefreigabe bei Minutenbeginn .def intreg = r15 ; Zwischenspeicher fuer SREG bei ISRs .def temp = r16 ; diverse Universalregister .def temp1 = r17 .def temp2 = r18 .def temp3 = r19 ; .cseg ; Codesegment .org 0x0000 ; Startadresse rjmp reset ; Interrupt Vektoren Einsprungadressen (default) ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .org 0x0001 ; ext IRQ0 Flanke rjmp INT00 .org 0x0002 ; ext IRQ1 Flanke rjmp INT10 .org 0x0003 ; Timer 1 capt rjmp ICP10 .org 0x0004 ; Timer 1 comp match A rjmp OC100 .org 0x0005 ; Timer 1 overflow rjmp OVF10 .org 0x0006 ; Timer 0 overflow rjmp OVF00 .org 0x0007 ; UART Receive Complete rjmp URXC0 .org 0x0008 ; UART Data Register Empty rjmp UDRE0 .org 0x0009 ; UART Transmit Complete rjmp UTXC0 .org 0x000A ; Analog Comparator Interrupt rjmp ACI00 .org 0x000B ; Pin Change Interrupt Request B rjmp PCIBA .org 0x000C ; Timer 1 comp match B rjmp OC1BA .org 0x000D ; Timer 0 comp match A rjmp OC0AA .org 0x000E ; Timer 0 comp match B rjmp OC0BA .org 0x000F ; USI Start Condition rjmp USIST .org 0x0010 ; USI Overflow rjmp USIOV .org 0x0011 ; Eprom read ready rjmp ERDYA .org 0x0012 ; Watchdog Timer Overflow rjmp WDTAD .org 0x0013 ; Pin Change Interrupt Request A rjmp PCIAA .org 0x0014 ; Pin Change Interrupt Request D rjmp PCIDA ; ;Interrupt Service Routinen - Interrupt handler ;- - - - - - - - - - - - - - - - - - - - - - - - - INT00: ; ISR not in use reti INT10: ; ISR not in use reti ICP10: ; ISR not in use reti OC100: ; ISR Portabfrage DCF Status high/low rjmp T1Interr OVF10: ; ISR not in use reti OVF00: ; ISR not in use reti URXC0: ; ISR not in use reti UDRE0: ; ISR not in use reti UTXC0: ; ISR not in use reti ACI00: ; ISR not in use reti PCIBA: ; ISR not in use reti OC1BA: ; ISR not in use reti OC0AA: ; ISR not in use reti OC0BA: ; ISR not in use reti USIST: ; ISR not in use reti USIOV: ; ISR not in use reti ERDYA: ; ISR not in use reti WDTAD: ; ISR not in use reti PCIAA: ; ISR not in use reti PCIDA: ; ISR not in use reti ; reset: cli ; Interrupts sperren ldi temp, low(ramend) ; Stackpointer setzen out spl, temp ldi temp, high(ramend) out sph, temp ldi yl, low(0x0060) ; <<8 Start SRAM-Bereich low(0x0060) ldi yh, high(0x0060) ; &255 Start SRAM-Bereich high(0x0000) ldi temp, 0x00 init10x: ; SRAM mit Nullen beschreiben st y+, temp ; Speicherzellen loeschen cpi yl, low(ramend+1) ; RAM-Ende (low) erreicht? brne init10x ; nein -> Schleife cpi yh, high(ramend+1) ; RAM-Ende (high) erreicht? brne init10x ; nein -> Schleife rcall regclr ; Registerreset rcall portinit ; Init I/O-Ports rcall rs232init ; Init serielle Schnittstelle rcall lcdinit ; LCD-Init ldi temp, 'A' ; LCD-Test Buchstaben rcall char2lcd rcall wait3 mov temp1, temp rcall num ; LCD-Test Ziffern rcall wait3 rcall lcd_clear ; LCD-Anzeige loeschen rcall wait3 rcall timerinit ; Timerinitialisierung sei ; generelle Interruptfreigabe rjmp main ; Sprung zum Hauptprogramm ; regclr: clr dcfsec ; DCF77-Sekundenmarkenzaehler loeschen clr dcfcnt ; DCF77-Samplingzaehler loeschen clr flags ; Flagregister resetten clr flags1 ; Gangreserve flags1register resetten ret ; portinit: ldi temp, 0xFF ; PortB Ausgang LCD out ddrb, temp ; PB0=RS, PB1=Enable, PB2=Hintergrundlight out portb, temp ; PB4-PB7=Daten ldi temp, 0b00111010 out ddrd, temp ; PD0=RXD, PD1=TXD, PD6=DCF77input (low act.) ldi temp, 0xFF ; Pullups auch fuer RXD out portd, temp ret ; timerinit: ldi temp, high(comp) ; CTC=clear timer on compare match out OCR1AH, temp ; loescht Zaehlregisterinhalt bei ldi temp, low(comp) ; Uebereinstimmung mit dem Vorladewert out OCR1AL, temp ; (STK500=36859, bei 4 MHz=39999) ldi temp, 0x00 out TCCR1A, temp ldi temp, (1< weiter mit ma1060 cli ; Interrupts sperren ldi temp, 0b11110111 ; sonst Minuten-Flag loeschen and flags, temp ; in Flags speichern sei ; Interrupts wieder aktivieren rcall mdcprc ; DCF77-Auswertung tst r19 ; DCF77 ok? brne ma1060 ; nein -> weiter rcall mtsync ; sonst Uhr synchronisieren rjmp ma1060 ; ma1060: clr r19 ; Fehlerzaehler resetten clr r20 rjmp ma1070 ; ma1070: set bld flags, 2 ; Synchronisationsversuch-Flag setzen clt bld flags, 4 ; Datum ungueltig clr r19 ; Fehlerzaehler resetten clr r20 sbrc flags1, 1 ; Gangreserve-Bit in ISR gesetzt ? rcall nosync ; -> Gangreserve aufrufen, rjmp main ; sonst Schleife ; ;------------------------------------------------- ; DCF77-Auswertung, Kontrolle der Pruefbits 1-3, ; Ablegen der Zeitinformation in Puffer dcbuf1 ; Register: r18,r19,r20,r21,r22,r23,y,z ; Ausgang: r19=0 - alles ok, r19>0 - Fehler ;------------------------------------------------- ; ;- Kontrolle des Impulszaehlers und der Paritybits ; fuer Minuten, Stunden und Datum ; mdcprc: clr r19 ; Fehlerzaehler loeschen mov r21, dcfsec ; DCF77-Markenzaehler kopieren clr dcfsec ; DCF77-Markenzaehler loeschen cpi r21, 59 ; wurden 59 Impulse empfangen? breq mdc010 ; ja -> weiter inc r19 ; sonst Fehlerzaehler erhoehen rjmp mdc200 ; Auswertung vorzeitig beenden ; mdc010: clr r21 ; wird fuer Paritaetsber. benoetigt clr r22 ; Reset Zaehler fuer Paritaetsber. lds r23, dcftab+1 ; Byte 1 aus DCF77-Puffer0 holen ldi r20, 6 ; 6 Minuten-Bits auswerten ; mdc020: rol r23 ; relevantes Bit in Carry schieben adc r22, r21 ; Eins-Bit addieren dec r20 ; alle Bits ausgewertet? brne mdc020 ; nein -> Schleife lds r23, dcftab+2 ; Byte 2 aus DCF77-Puffer0 holen ror r23 ; relevantes Bit in Carry schieben adc r22, r21 ; Eins-Bit addieren ror r23 ; relevantes Bit in Carry schieben adc r22, r21 ; Eins-Bit addieren bst r22, 0 ; war das Ergebnis geradzahlig? brtc mdc030 ; ja -> weiter inc r19 ; sonst Fehlerzaehler erhoehen ; mdc030: clr r22 ; Reset Zaehler fuer Paritaetsber. ldi r20, 6 ; 6 Stunden-Bits auswerten ; mdc040: ror r23 ; relevantes Bit in Carry schieben adc r22, r21 ; Eins-Bit addieren dec r20 ; alle Bits ausgewertet? brne mdc040 ; nein -> Schleife lds r23, dcftab+3 ; Byte 3 aus DCF77-Puffer0 holen ror r23 ; relevantes Bit in Carry schieben adc r22, r21 ; Eins-Bit addieren bst r22, 0 ; war das Ergebnis geradzahlig? brtc mdc050 ; ja -> weiter inc r19 ; sonst Fehlerzaehler erhoehen ; mdc050: clr r22 ; Reset Zaehler fuer Paritaetsber. ldi r20, 7 ; 7 Datum-Bits auswerten ; mdc060: ror r23 ; relevantes Bit in Carry schieben adc r22, r21 ; Eins-Bit addieren dec r20 ; alle Bits ausgewertet? brne mdc060 ; nein -> Schleife lds r23, dcftab+4 ; Byte 4 aus DCF77-Puffer0 holen ldi r20, 8 ; 8 Datum/Wochentag-Bits auswerten ; mdc070: ror r23 ; relevantes Bit in Carry schieben adc r22, r21 ; Eins-Bit addieren dec r20 ; alle Bits ausgewertet? brne mdc070 ; nein -> Schleife lds r23, dcftab+5 ; Byte 5 aus DCF77-Puffer0 holen ldi r20, 8 ; 8 Datum/Jahreszahl-Bits auswerten ; mdc080: ror r23 ; relevantes Bit in Carry schieben adc r22, r21 ; Eins-Bit addieren dec r20 ; alle Bits ausgewertet? brne mdc080 ; nein -> Schleife bst r22, 0 ; war das Ergebnis geradzahlig? brtc mdc090 ; ja -> weiter inc r19 ; sonst Fehlerzaehler erhoehen ; mdc090: tst r19 ; Paritaetsfehler aufgetreten? breq mdc100 ; nein -> weiter rjmp mdc200 ; sonst DCF-Puffer0 loeschen ; ; - Ablegen der Zeitinformation in Puffer dcbuf1 ; mdc100: ldi zl, low(dcbuf1) ; Zeiger auf DCF77-Puffer1 ldi zh, high(dcbuf1) lds r23, dcftab ; Byte 0 aus DCF77-Puffer0 holen rol r23 ; Bit 6 auf Bit 0 schieben rol r23 rol r23 andi r23, 0x01 ; relevantes Bit filtern st z+, r23 ; Zeitzone speichern lds r23, dcftab+1 ; Byte 1 aus Tabelle holen ror r23 ; Bits 2-5 auf Bits 0-3 schieben ror r23 andi r23, 0x0F ; relevante Bits filtern st z+, r23 ; Minuten Einer speichern lds r23, dcftab+1 ; Byte 1 aus DCF77-Puffer0 holen lds r22, dcftab+2 ; Byte 2 aus DCF77-Puffer0 holen rol r23 ; Bits 6-7 aus r23 und 0 aus r22 rol r22 ; auf Bits 0-2 von r22 schieben rol r23 rol r22 andi r22, 0x07 ; relevante Bits filtern st z+, r22 ; Minuten Zehner speichern lds r23, dcftab+2 ; Byte 2 aus DCF77-Puffer0 holen ror r23 ; Bits 2-5 auf Bits 0-3 schieben ror r23 andi r23, 0x0F ; relevante Bits filtern st z+, r23 ; Stunden Einer speichern lds r23, dcftab+2 ; Byte 2 aus DCF77-Puffer0 holen rol r23 ; Bits 6-7 auf Bits 0-1 schieben rol r23 rol r23 andi r23, 0x03 ; relevante Bits filtern st z+, r23 ; Stunden Zehner speichern lds r23, dcftab+3 ; Byte 3 aus DCF77-Puffer0 holen ror r23 ; Bits 1-4 auf Bits 0-3 schieben andi r23, 0x0F ; relevante Bits filtern st z+, r23 ; Kalendertag Einer speichern lds r23, dcftab+3 ; Byte 3 aus DCF77-Puffer0 holen ror r23 ; Bits 5-6 auf Bits 4-5 schieben swap r23 ; Nibbles tauschen andi r23, 0x03 ; relevante Bits filtern st z+, r23 ; Kalendertag Zehner speichern lds r23, dcftab+3 ; Byte 3 aus DCF77-Puffer0 holen rol r23 ; Bit 7 in Carry schieben lds r23, dcftab+4 ; Byte 4 aus DCF77-Puffer0 holen rol r23 ; Carry in Bit 0 schieben andi r23, 0x07 ; relevante Bits filtern st z+, r23 ; Wochentag speichern lds r23, dcftab+4 ; Byte 4 aus DCF77-Puffer0 holen ror r23 ; Bits 2-5 in Bits 0-3 schieben ror r23 andi r23, 0x0F ; relevante Bits filtern st z+, r23 ; Monat Einer speichern lds r23, dcftab+4 ; Byte 4 aus DCF77-Puffer0 holen rol r23 ; Bit 6 in Bit 0 schieben rol r23 rol r23 andi r23, 0x01 ; relevantes Bit filtern st z+, r23 ; Monat Zehner speichern lds r23, dcftab+4 ; Byte 4 aus DCF77-Puffer0 holen rol r23 ; Bit 7 in Carry schieben lds r23, dcftab+5 ; Byte 5 aus DCF77-Puffer0 holen rol r23 ; Carry in Bit 0 schieben andi r23, 0x0F ; relevante Bits filtern st z+, r23 ; Jahr Einer speichern lds r23, dcftab+5 ; Byte 5 aus DCF77-Puffer0 holen rol r23 ; Bits 3-6 in Bits 4-7 schieben swap r23 ; Nibbles tauschen andi r23, 0x0F ; relevante Bits filtern st z+, r23 ; Jahr Zehner speichern ; mdc200: ret ; ------------------------------------------------------ ; Zeitinformationen in Uhrenpuffer kopieren und Uhrzeit ; bei Synchronisation auf LCD und RS232 ausgeben ; ------------------------------------------------------ mtsync: ldi temp, '<' ; Vorzeichen nur fuer RS232-Ausgabe rcall senden cli ; Interrupts sperren lds r0, dcbuf1+3 ; Stunden Einer holen (1) lds r1, dcbuf1+4 ; Stunden Zehner holen (2) sei rcall locate2a mov temp, r1 subi temp, -0x30 rcall char2lcd rcall senden mov temp, r0 subi temp, -0x30 rcall char2lcd rcall senden rcall bcdbin ; Format von BCD => binaer sts stunde, temp ; Kopie fuer Gangreserve-Puffer ldi temp, ':' rcall char2lcd rcall senden cli lds r0, dcbuf1+1 ; Minuten Einer holen (3) lds r1, dcbuf1+2 ; Minuten Zehner holen (4) sei mov temp, r1 subi temp, -0x30 rcall char2lcd rcall senden mov temp, r0 subi temp, -0x30 rcall char2lcd rcall senden rcall bcdbin ; Format von BCD => binaer sts minute, temp ; Kopie fuer Gangreserve-Puffer ldi temp, ':' rcall char2lcd ldi temp, '-' rcall senden cli lds r0, dcbuf1+5 ; Tag Einer holen lds r1, dcbuf1+6 ; Tag Zehner holen sei rcall locate1a mov temp, r1 subi temp, -0x30 rcall char2lcd rcall senden mov temp, r0 subi temp, -0x30 rcall char2lcd rcall senden ; rcall bcdbin ; Format von BCD => binaer sts tag, temp ; Kopie fuer Gangreserve-Puffer ; ldi temp, '.' rcall char2lcd rcall senden cli lds r0, dcbuf1+8 ; Monat Einer holen lds r1, dcbuf1+9 ; Monat Zehner holen sei mov temp, r1 subi temp, -0x30 rcall char2lcd rcall senden mov temp, r0 subi temp, -0x30 rcall char2lcd rcall senden ldi temp, '.' rcall char2lcd rcall senden rcall bcdbin ; Format von BCD => binaer sts monat, temp ; Kopie fuer Gangreserve-Puffer ; ************************************************************ push temp ldi temp, 0x34 rcall char2lcd ; 0x14 Jahr Tausender/Hunderter rcall senden ; rcall num ergaenzen - nicht im DCF-Code pop temp ; ; rcal nums enthalten, auch auf RS232 ausgeben ;************************************************************* cli lds r0, dcbuf1+10 ; Jahr Einer holen lds r1, dcbuf1+11 ; Jahr Zehner holen sei mov temp, r1 rcall locate1c subi temp, -0x30 rcall char2lcd rcall senden mov temp, r0 subi temp, -0x30 rcall char2lcd rcall senden rcall bcdbin ; Format von BCD => binaer sts jahr, temp ; Kopie fuer Gangreserve-Puffer ldi temp, 0x20 rcall senden rcall wochentag rcall szwz ldi temp, 0x0A rcall senden ldi temp, 0x0D rcall senden cli ; Interrupts sperren clr temp sts sekunde, temp ; Sekundenpuffer loeschen sts precnt, temp ; Vorteiler loeschen ldi temp, 0b00010100; Synchron- und Datum-Bit... or flags, temp ; ...in Flags einsetzen ldi temp, 0b00000001 ; Ausgabesperre Gangreserve mov flags1, temp ; ...bei Synchronisation clr temp sei ; Interrupts wieder aktivieren ret ; wochentag: lds r0, dcbuf1+7 mov temp2, r0 sts wtag, temp2 ; Kopie fuer Gangreserver-Puffer rjmp wochentag1 ; wochentag1: cpi temp2, 0x01 breq monta cpi temp2, 0x02 breq diens cpi temp2, 0x03 breq mittw cpi temp2, 0x04 breq donne cpi temp2, 0x05 breq freit cpi temp2, 0x06 breq samst cpi temp2, 0x07 breq sonnt ret ; szwz: lds r0, dcbuf1 mov temp2, r0 cpi temp2, 0x00 breq wintz cpi temp2, 0x01 breq sommz ret ; monta: ldi zl, low(mont*2) ; Adresse der Tabelle "mont" ldi zh, high(mont*2) ; in Z-Pointerregister laden rjmp pmread0 ; Ausgabeschleife aufrufen ; diens: ldi zl, low(dien*2) ; Adresse der Tabelle "dien" ldi zh, high(dien*2) ; in Z-Pointerregister laden rjmp pmread0 ; Ausgabeschleife aufrufen ; mittw: ldi zl, low(mitt*2) ; Adresse der Tabelle "mitt" ldi zh, high(mitt*2) ; in Z-Pointerregister laden rjmp pmread0 ; Ausgabeschleife aufrufen ; donne: ldi zl, low(donn*2) ; Adresse der Tabelle "donn" ldi zh, high(donn*2) ; in Z-Pointerregister laden rjmp pmread0 ; Ausgabeschleife aufrufen ; freit: ldi zl, low(frei*2) ; Adresse der Tabelle "frei" ldi zh, high(frei*2) ; in Z-Pointerregister laden rjmp pmread0 ; Ausgabeschleife aufrufen ; samst: ldi zl, low(sams*2) ; Adresse der Tabelle "sams" ldi zh, high(sams*2) ; in Z-Pointerregister laden rjmp pmread0 ; Ausgabeschleife aufrufen ; sonnt: ldi zl, low(sonn*2) ; Adresse der Tabelle "sonn" ldi zh, high(sonn*2) ; in Z-Pointerregister laden rjmp pmread0 ; Ausgabeschleife aufrufen ; sommz: ldi zl, low(somzt*2) ; Adresse der Tabelle "somzt" ldi zh, high(somzt*2); in Z-Pointerregister laden rjmp pmread ; Ausgabeschleife aufrufen ; wintz: ldi zl, low(winte*2) ; Adresse der Tabelle "winte" ldi zh, high(winte*2); in Z-Pointerregister laden rjmp pmread ; Ausgabeschleife aufrufen ; pmread: rcall locate2c rjmp pmread1 ; pmread0: rcall locate1d rjmp pmread1 ; pmread1: lpm temp, z+ ; Kopie Byte 1 des Tabellen-Strings nach temp tst temp ; temp auf 0 testen ;tst r0 ; r0 auf 0 testen breq prt_end ; wenn 0, dann zu prt_end ;mov temp, r0 ; Inhalt von r0 nach temp kopieren rcall char2lcd ; Zeichen-Uebergabe an LCD rcall senden ; Zeichen-Uebergabe an RS232 ;adiw zl:zh, 1 ; Adresse des Z-Pointers um 1 erhoehen rjmp pmread1 ; wieder zum Anfang (Label "pmread1") springen ; ; und naechstes Byte aus Tabelle holen prt_end: ; Beendigung der Leseroutine,Ruecksprung ret ; ; Tabellen Wochentag: mont: .db "Mo ",0 dien: .db "Di ",0 mitt: .db "Mi ",0 donn: .db "Do ",0 frei: .db "Fr ",0 sams: .db "Sa ",0 sonn: .db "So ",0 ; ; Tabellen Sommerzeit/Winterzeit-Kuerzel: somzt: .db "SZ ",0 winte: .db "WZ ",0 ; nosync: ; Gangreserve bei Fehlen DCF77-Signals sbrc flags1, 0 ; Gangreservesperrbit bei Synchronisation rjmp nosync1 ; gesetzt -> Beendigung, sonst Ausgabe... rcall locate2a ; ...ueber Gangreserve lds temp1, stunde ; nur Stunden und Minuten rcall numx ; anzeigen ldi temp, ':' rcall char2lcd rcall senden lds temp1, minute rcall numx ldi temp, ':' rcall char2lcd rcall senden ; RS232 serielle Ausgabe ldi temp, 0x0A ; naechste Zeile (Zeilenvorschub) rcall senden ldi temp, 0x0D ; Anfang Zeile (Wagenruecklauf) rcall senden ;lds temp1, sekunde ; bei Bedarf hinzufuegen ;rcall num ; eingefrorene Sekundenanzeige-> rcall locate1a ; Indikator "keine Synchronisation"... lds temp1, tag ; ...Uhr laeuft auf Gangreserve rcall num ldi temp, '.' rcall char2lcd lds temp1, monat rcall num ldi temp, '.' rcall char2lcd ldi temp1, 0x14 rcall num rcall locate1c lds temp1, jahr rcall num lds temp2, wtag rcall wochentag1 clr flags1 ret ; nosync1: ; Gangreserve-Ausgabe wieder vorbereiten clr flags1 ret ; ; ------------------------------------------------------------ ; Interrupt-Routine Timer1 Compare A, liest DCF77-Pegel ; alle 10 ms ein, zaehlt die Uhrzeit autonomatisch hoch, ; Register: dcfsec,dcfcnt,flags,inttmp,intreg,r25,xl,xh ; ------------------------------------------------------------ T1Interr: in intreg, SREG ; CPU-Flags sichern in r25, pind ; Portbit PD6 DCF77 einlesen lds temp, block ; Pegel von Sperregister holen or r25, temp ; Bit6 in r25 auf high setzen, sbrc temp, 6 ; wenn vorher in "block" gesetzt rjmp t010 ; Bit6 =1 ->t010 rjmp t030 ; Bit6 =0 ->t030 ; t010: ; Eingang 500ms (260ms)auf high halten inc r14 ldi temp1, 50 ; 26 cp r14, temp1 brcc t020 ; 500ms (260ms) erreicht?->t020 rjmp t030 ; nein ->t030 ; t020: ; Zaehler ruecksetzen clr temp1 ; r25 wieder freigeben clr r14 ; fuer Low-Pegel ldi temp, 0x00 sts block, temp rjmp t030 ; t030: bst r25, 6 ; DCF77-Pegel holen bld flags, 0 ; und in Flags speichern rjmp t040 ; t040: inc dcfcnt ; DCF77-Sampling-Zaehler erhoehen bst flags, 0 ; akuellen DCF77-Pegel pruefen brts t060 ; ist DCF77 High? ja -> t060 bst flags, 1 ; sonst vorh. DCF-Status pruefen brtc t100 ; war DCF77 vorher High? ldi r25, 150 ; nein -> Ende cp dcfcnt, r25 ; Zaehler<150 (1,5s) ? brcs t050 ; nein -> t050 bld flags, 3 ; ja -> Bit3 Minutenanfang in Flags kopieren rjmp t050 ; wird von Main-Routine geloescht ; t050: clr dcfcnt ; DCF77-Sampling-Zaehler loeschen rjmp t100 ; Ende ; t060: bst flags,1 ; vorherigen DCF-Status pruefen brts t100 ; war DCF77 vorher H? ja -> Ende inc dcfsec ; sonst Sekunde hochzaehlen ; ldi temp, 0b01000000; 0x40; Bit6 high setzen sts block, temp ; in "block" speichern ; ; r25 wird beim naechsten Interrupt ; ; nach l/h-Wechsel 500(260) ms gesperrt ldi r25, 14 ; DCF-Sampling-Zaehler<14 (140ms)? cp dcfcnt, r25 ; Ergebnis in Carry - invertiert rjmp t080 ; t080: ldi r25, 6 ; 6 Pufferbytes bearbeiten ldi xl, low(dcftab+6); Zeiger auf Pufferende setzen ldi xh, high(dcftab+6) rol inttmp ; Carry in Register legen (LSB) com inttmp ; alle Bits invertieren mov temp2, inttmp ; Kopie fuer DCF77-RS232-Anzeige ror inttmp ; LSB wieder in Carry schieben ; t090: ld inttmp, -x ; Pufferbyte -1 holen ror inttmp ; neues Bit einschieben als MSB st x, inttmp ; LSB in Carry und speichern dec r25 ; alle Pufferbytes bearbeitet? brne t090 ; nein -> Schleife (rueckwaerts) ;- - - - - - - - - - - - - - - - - - - - - - - - - - - andi temp2, 0b00000001 ; DCF77 Code Nullen/Einsen mov temp, temp2 subi temp, -0x30 rcall senden ; nur auf RS232 ausgeben ;- - - - - - - - - - - - - - - - - - - - - - - - - - - rcall locate2b ; Sekundenanzeige DCF synchron mov temp1, dcfsec rcall num ; nur auf LCD ausgeben rjmp t100 ; t100: bst flags, 0 ; aktuellen DCF77-Status holen bld flags, 1 ; und als neuen Status speichern ;- - - - - - - - - - fuer Gangreserve - - - - - - - - - lds r25, precnt ; Vorteiler holen tst r25 ; Vorteiler=0? brne t110 ; nein -> t110 rjmp t110 ; ja -> t110; rjmp timerend ; t110: lds r25, precnt ; Vorteiler holen inc r25 ; erhoehen sts precnt, r25 ; und wieder speichern cpi r25, 100 ; Endwert erreicht? brne t190 ; nein -> Ende clr r25 ; ja -> zuruecksetzen sts precnt, r25 ; und speichern rjmp t120 ; t120: lds r25, sekunde ; Sekunden holen inc r25 ; erhoehen sts sekunde, r25 ; und wieder speichern cpi r25, 60 ; Endwert erreicht? brne timerend ; nein -> Ende clr r25 ; ja -> zuruecksetzen sts sekunde, r25 ; und speichern lds r25, minute ; Minuten holen inc r25 ; Minuten erhoehen sts minute, r25 ; und wieder speichern ldi temp, 0x02 ; Gangreserve-Ausgabe... mov flags1, temp ; ...vorbereiten cpi r25, 60 ; Endwert erreicht? brne timerend ; nein -> Ende clr r25 ; ja -> zuruecksetzen sts minute, r25 ; und speichern lds r25, stunde ; Stunden holen inc r25 ; erhoehen sts stunde, r25 ; und wieder speichern cpi r25, 24 ; Endwert erreicht? brne timerend ; nein -> Ende clr r25 ; ja -> zuruecksetzen sts stunde, r25 ; und speichern lds r25, tag ; Tag holen inc r25 ; erhoehen sts tag, r25 ; und wieder speichern lds r25, wtag ; Wochentag holen inc r25 ; erhoehen sts wtag, r25 ; und wieder speichern cpi r25, 7 ; Endwert erreicht? brne timerend ; nein -> Ende clr r25 ; ja -> zuruecksetzen sts wtag, r25 ; und speichern lds yl, monat ; Monat holen cpi yl, 1 ; Monat Januar? brne t200 ; nein -> weiter testen cpi r25, 32 ; Tag>31? brcc t210 ; ja -> Monatswechsel rjmp t190 ; t190: rjmp timerend ; Sprung zu Beendigung ISR ; t200: cpi yl, 2 ; Monat Februar? brne t230 ; nein -> weiter testen lds yl, jahr ; Jahr holen andi yl, 0x03 ; Schaltjahr? breq t220 ; ja -> 29 Tage cpi r25, 29 ; sonst Tag>28? ; t210: brcc t400 ; ja -> Monatswechsel rjmp timerend ; sonst Ende ; t220: cpi r25, 30 ; Tag>29? brcc t400 ; ja -> Monatswechsel rjmp timerend ; sonst Ende ; timerend: out SREG, intreg ; CPU-Flags wiederherstellen reti ; Interrupthandler-Ende ; t230: cpi yl, 3 ; Monat Maerz? brne t240 ; nein -> weiter testen cpi r25, 32 ; Tag>31? brcc t400 ; ja -> Monatswechsel rjmp timerend ; sonst Ende ; t240: cpi yl, 4 ; Monat April? brne t250 ; nein -> weiter testen cpi r25, 31 ; Tag>30? brcc t400 ; ja -> Monatswechsel rjmp timerend ; sonst Ende ; t250: cpi yl, 5 ; Monat Mai? brne t260 ; nein -> weiter testen cpi r25, 32 ; Tag>31? brcc t400 ; ja -> Monatswechsel rjmp timerend ; sonst Ende ; t260: cpi yl, 6 ; Monat Juni? brne t270 ; nein -> weiter testen cpi r25, 31 ; Tag>30? brcc t400 ; ja -> Monatswechsel rjmp timerend ; sonst Ende ; t270: cpi yl, 7 ; Monat Juli? brne t280 ; nein -> weiter testen cpi r25, 32 ; Tag>31? brcc t400 ; ja -> Monatswechsel rjmp timerend ; sonst Ende ; t280: cpi yl, 8 ; Monat August? brne t290 ; nein -> weiter testen cpi r25, 32 ; Tag>31? brcc t400 ; ja -> Monatswechsel rjmp timerend ; sonst Ende ; t290: cpi yl, 9 ; Monat September? brne t300 ; nein -> weiter testen cpi r25, 31 ; Tag>30? brcc t400 ; ja -> Monatswechsel rjmp timerend ; sonst Ende ; t300: cpi yl, 10 ; Monat Oktober? brne t310 ; nein -> weiter testen cpi r25, 32 ; Tag>31? brcc t400 ; ja -> Monatswechsel rjmp timerend ; sonst Ende ; t310: cpi yl, 11 ; Monat November? brne t320 ; nein -> Monat Dezember cpi r25, 31 ; Tag>30? brcc t400 ; ja -> Monatswechsel rjmp timerend ; sonst Ende ; t320: cpi r25, 32 ; Tag>31? brcs timerend ; nein -> Ende ; t400: ldi r25, 1 ; Tag=1 setzen sts tag, r25 ; und speichern lds r25, monat ; Monat holen inc r25 ; erhoehen sts monat, r25 ; und wieder speichern cpi r25, 13 ; Endwert ueberschritten? brcs timerend ; nein -> Ende ldi r25, 1 ; sonst Monat=1 setzen sts monat, r25 ; und wieder speichern lds r25, jahr ; Jahr holen inc r25 ; erhoehen sts jahr, r25 ; und wieder speichern rjmp timerend ; ;- -LCD-Initialisierung - LCD - Ausgabe-Routinen- - lcdinit: rcall wait3 ; LCD Power On Self Reset abwarten push temp ; Sicherung Temporaer- und push temp1 ; Statusregister auf Stapel in temp1,SREG push temp1 rcall lcd_reset ; LCD-Bus-Reset rcall lcd_achtbit ; LCD-Init: acht Bit rcall lcd_acht_vier ; LCD-Init: acht zu vier Bit rcall lcd_vier_zwei ; LCD-Init: vier Bit, zwei Zeilen rcall lcd_on_off ; LCD-Init: Displaypuffer aus rcall lcd_clear ; LCD-Init: Anzeige l schen rcall lcd_entrymode ; LCD-Init: Entry Mode Set pop temp1 ; Wiederherstellung Temporaer- out SREG,temp1 ; und Statusregister pop temp1 pop temp ret ; lcd_reset: ; LCD-Bus Reset push temp ; Temporaerregister auf Stack retten ldi temp, 0x00 ; RS=0; Reset des LCD-Ausgabeports out daten,temp rcall enable ; Enable-Impuls toggeln rcall wait2 pop temp ; Temporaerregister wiederherstellen ret ; lcd_achtbit: ; Acht-Bit-Init push temp ; an folgende Portbelegung angepasst: ; ; PB7 PB6 PB5 PB4 PB3 PB2 PB1 PB0 ; ; D7 D6 D5 D4 n/cled ena rs ldi temp, 0x30 ; dreimal hex 0x30 ;cbi daten, rs ; RS=0 out daten, temp ; immer notwendig, auch rcall enable ; wenn auf Vierbitmodus rcall wait2 ; gewechselt wird, dabei ldi temp, 0x30 ; hex 0x30 ;cbi daten, rs ; RS=0 out daten, temp ; auf Port ausgeben rcall enable ; Enable-Impuls senden, dann rcall wait2 ; Pausen folgen lassen ldi temp, 0x30 ;cbi daten, rs ; RS=0 out daten,temp rcall enable rcall wait2 pop temp ret ; lcd_acht_vier: ; Acht-zu-Vier-Bit-Modus-Wechsel push temp ;cbi daten, rs ; RS=0 ldi temp, 0x20 ; zunaechst nur Vier-Bit-Modus- out daten,temp ; Wechsel-Befehl, "obere" vier Portbits rcall enable ; werden ignoriert, aber immer noch rcall wait2 ; Uebergabe im 8-Bit-Befehlsformat pop temp ret ; lcd_vier_zwei: ; Vier-Bit-Modus, zwei Zeilen push temp cbi daten,rs ; RS=0 ldi temp, 0x28 ; dann Vier-Bit-Modus, zweizeilig rcall comd2lcd ; ab hier werden Steuerbefehle rcall wait2 ; auch im Vier-Bit-Modus ueber pop temp ; Unterprogramm "comd2lcd" gesendet ret ; lcd_on_off: ; On-off-Control push temp ; Displaypuffer ein-, ausschalten ;cbi daten, rs ; RS=0 ldi temp, 0x08 ; Displaypuffer aus, Blinken aus, rcall comd2lcd ; kein Cursor rcall wait2 pop temp ret ; lcd_clear: ; Anzeige loeschen push temp cbi daten, rs ; RS=0 ldi temp, 0x01 ; Anzeige wird im Space-Modus rcall comd2lcd ; geloescht, dauert laenger... rcall wait3 ; ... Pause laenger pop temp ret ; lcd_entrymode: ; Entry/Shift Mode Set push temp cbi daten, rs ; RS=0 ldi temp, 0x06 ; Cursor von rechts nach links rcall comd2lcd ; kein Schieben rcall wait2 cbi daten, rs ; RS=0 ldi temp, 0x10 ; kein Schieben, Cursorbewegung rcall comd2lcd ; nach rechts rcall wait2 cbi daten, rs ; RS=0 ldi temp, 0x0C ; Anzeige wieder einschalten rcall comd2lcd ; Cursor aus, Blinken aus rcall wait2 cbi daten, rs ; RS=0 ldi temp, 0x01 ; Anzeige nochmals loeschen rcall comd2lcd rcall wait2 pop temp ret ; char2lcd: ; charakter output on LCD push temp ; saves "temps" on stack push temp1 mov temp1, temp ; content's copy for further actions below; andi temp, 0b11110000 ; blanking out D0-D3 data nibble ori temp, 0b00000001 ; RS=H masking out daten, temp ; output D4-D7 on PB4-PB7 rcall enable ; output first enable impuls swap temp1 ; swapping nibbles, uses copy of temp to temp1 andi temp1, 0b11110000 ; blanking out LSB port nibble ori temp1, 0b00000101 ; RS=H; LED-backlight on mov temp, temp1 ; copy temp1 to output register in use temp out daten, temp ; output D0-D3 on Port PB4-PB7 rcall enable ; output second enable impuls rcall wait2 ; wait for LCD processing pop temp1 ; reestablishing temps ... pop temp ; ...previous saved on stack ret ; comd2lcd: ; transmitting instructions towards LCD via TWI push temp ; saves "temps" on stack push temp1 mov temp1, temp ; content's copy for further actions below andi temp, 0b11110000 ; RS=L; blanking out D0-D3 data nibble out daten, temp ; output D4-D7 on PB4-PB7 rcall enable ; output first enable impuls swap temp1 ; swapping nibbles, uses copy of temp to temp1 andi temp1, 0b11110000 ; blanking out LSB port nibble mov temp, temp1 ; copy temp1 to output register in use temp out daten, temp ; output D0-D3 on Port B4-B7 rcall enable ; output second enable impuls rcall wait2 ; wait for LCD processing pop temp1 ; reestablishing temps ... pop temp ; ...previous saved on stack ret ; enable: nop ori temp, 0b00000010 ; H-masking enable bit out daten, temp nop nop nop nop nop nop nop nop andi temp, 0b11111101 ; L-masking enable bit out daten, temp nop ret ; ;*************** Verzoegerungsschleifen fuer LCD ************ ; wait1: ; Verzoegerungsschleife1 fuer LCD: Konstante 512: 257,5 us push xl ; Register sichern auf Stapel push xh push temp ; Sicherung von Temporaerregistern... push temp1 ; und Statusregister auf Stapel push temp2 in temp2, SREG ; (bei Interrupts notwendig) push temp2 ldi xl, low(delay0) ; laedt Zaehlregisterpaar ldi xh, high(delay0) ; mit oben deklariertem Wert... rjmp repeatx ; ..."delay0" ; wait2: ; Verzoegerungsschleife2 fuer LCD: Konstante 65535: 32 ms push xl ; Register sichern auf Stapel push xh push temp ; Sichern von Temporaerregistern push temp1 ; und Statusregister auf Stapel push temp2 in temp2, SREG push temp2 ldi xl, low(delay1) ; laedt Zaehlregisterpaar ldi xh, high(delay1) ; mit oben deklariertem Wert... rjmp repeatx ; ..."delay1" ; repeatx: ; 16-Bit-Subtraktionsschleife: sbiw xl:xh, 1 ; decrementiert Doppelregister brne repeatx ; zaehlt bis Null pop temp2 ; Wiederherstellung out SREG, temp2 ; von "geretteten" Registern etc. pop temp2 pop temp1 pop temp pop xh pop xl ret ; wait3: ; Verzoegerungsschleife3: ca. 128 ms rcall wait2 rcall wait2 rcall wait2 rcall wait2 nop ret ; ;- - - - - - Zahlenumwandlung(1) binaer=>dezimal - - - - - - num: ; wandelt 8 Bit bin r auf "temp1" ; ; nach ASCII dezimal und gibt "temp" auf LCD aus ; ; Format: 2 Ziffern mit fuehrender Null push temp ; Eingaberegister "temp1", push temp1 ; Ausgaberegister "temp" push temp2 mov temp2, temp1 ldi temp1, 0x30 ; num3: subi temp2, 10 ; Berechnung Zehner brcs num4 inc temp1 rjmp num3 ; num4: mov temp, temp1 rcall char2lcd ; Ausgabe Zehnerstelle auf LCD subi temp2, -10 ; Berechnung Einer ldi temp1, 0x30 add temp1, temp2 mov temp, temp1 rcall char2lcd ; Ausgabe Einerstelle auf LCD pop temp2 pop temp1 pop temp ret ; ;- - - - - - Zahlenumwandlung(1a) binaer=>dezimal - - - - - - nums: ; wandelt Byte auf "temp1" (nur RS232-Ausgabe) ; ; nach ASCII dezimal und gibt "temp" RS232 I/O ; ; Format: 2 Ziffern mit fuehrender Null push temp ; Eingaberegister "temp1", push temp1 ; Ausgaberegister "temp" push temp2 mov temp2, temp1 ldi temp1, 0x30 ; nums3: subi temp2, 10 ; Berechnung Zehner brcs nums4 inc temp1 rjmp nums3 ; nums4: mov temp, temp1 rcall senden ; Ausgabe Zehnerstelle auf RS232 subi temp2, -10 ; Berechnung Einer ldi temp1, 0x30 add temp1, temp2 mov temp, temp1 rcall senden ; Ausgabe Einerstelle auf RS232 pop temp2 pop temp1 pop temp ret ; ;- - - - - - Zahlenumwandlung(1b) binaer=>dezimal - - - - - - numx: ; wandelt Byte auf "temp1" (LCD- und RS232-Ausgabe) ; ; nach ASCII dezimal und gibt auf "temp" aus ; ; Format: 2 Ziffern mit fuehrender Null push temp ; Eingaberegister "temp1", push temp1 ; Ausgaberegister "temp" push temp2 mov temp2, temp1 ldi temp1, 0x30 ; numx3: subi temp2, 10 ; Berechnung Zehner brcs numx4 inc temp1 rjmp numx3 ; numx4: mov temp, temp1 rcall char2lcd ; Ausgabe Zehnerstelle auf LCD rcall senden ; Ausgabe Zehnerstelle auf RS232 subi temp2, -10 ; Berechnung Einer ldi temp1, 0x30 add temp1, temp2 mov temp, temp1 rcall char2lcd ; Ausgabe Einerstelle auf LCD rcall senden ; Ausgabe Einerstelle auf RS232 pop temp2 pop temp1 pop temp ret ; ;- - - - - - - Zahlenumwandlung(2) BCD=>binaer - - - - - - ; ; Eingaberegister "temp" bcdbin: ; r1 = Zehner,r0 = Einer clr temp ; Ergebnisregister loeschen ldi temp1, 0x0A ; Vorladewert 10 ; bcdbin1: tst r1 ; Zehner = 0 ? breq bcdbin2 ; ja =>Einer direkt bearbeiten add temp, temp1 ; nein=>jedesmal 10 zu Ausgabe add. dec r1 ; so lange Zehner erniedrigen, rjmp bcdbin1 ; bis r1 Null ; bcdbin2: add temp, r0 ; Einer addieren; Ausgabe auf temp ret ; ;- - - - - - LCD Positionierungen (2x16) - - - - - - ; locate1: ; Anfang Zeile 1 push temp ldi temp, 0x80 rcall comd2lcd pop temp ret ; locate1a: ; Zeile 1, Spalte 4 push temp ldi temp, 0x83 rcall comd2lcd pop temp ret ; locate1b: ; Zeile 1, Spalte 6 push temp ldi temp, 0x85 rcall comd2lcd pop temp ret ; locate1c: ; Zeile 1, Spalte 8 push temp ldi temp, 0x8B rcall comd2lcd pop temp ret ; locate1d: ; Zeile 1, Spalte 15 push temp ldi temp, 0x8E rcall comd2lcd pop temp ret ; locate2: ; Anfang Zeile 2 push temp ldi temp, 0xC0 rcall comd2lcd pop temp ret ; locate2a: ; Zeile 2, Spalte 4 push temp ldi temp, 0xC3 rcall comd2lcd pop temp ret ; locate2b: ; Zeile 2, Spalte 10 push temp ldi temp, 0xC9 rcall comd2lcd pop temp ret ; locate2c: ; Zeile 2, Spalte 15 push temp ldi temp, 0xCE rcall comd2lcd pop temp ret ; ;*** Fin ***