; ============================================================ ; ATmega8 Maker-Clock-FM-Radio mit PLL & 7-Segment + DS1307 ; CPU: 4 MHz RC-Oszillator intern ; Ports: ; SDA = PC4, SCL = PC5 (I²C DS1307) ; PORTD: Display-ZIFA/B/C/D, LATCH, SEGI, LM_SIN, LM_SCK ; PORTB: Tasten, EEPROM-Adr ; ============================================================ .include "m8def.inc" ; ----------------------------- ; Register ; ----------------------------- .def temp = r16 .def temp2 = r17 .def FREQ_L = r18 .def FREQ_H = r19 .def DIG0 = r12 .def DIG1 = r13 .def DIG2 = r14 .def DIG3 = r15 .def last_addr = r11 .def RTC_SEC = r9 .def RTC_MIN = r20 .def RTC_HOUR = r21 .def i_tmp = r22 .def i2cdelay = r23 .def i2cdata = r25 .def i2cstat = r24 .def i2cadr = r10 ; ----------------------------- ; Pins ; ----------------------------- .equ LM_SIN = 1 .equ LM_SCK = 0 .equ DISP_LATCH = 2 .equ ZIFA = 3 .equ ZIFB = 4 .equ ZIFC = 5 .equ ZIFD = 6 .equ SEGI = 7 .equ SDAP = 4 ; PC4 .equ SCLP = 5 ; PC5 ; ============================================================ ; RESET ; ============================================================ .org 0x0000 rjmp RESET RESET: clr r1 ldi temp, high(RAMEND) out SPH, temp ldi temp, low(RAMEND) out SPL, temp sbi DDRC, 1 ; PC1 Ausgang ldi temp, 0xFF out DDRD, temp ldi temp, 0x00 out DDRC, temp ldi temp, 0x00 out DDRB, temp ; I²C Init rcall i2c_init rcall RTC_INIT ; Frequenz default ldi FREQ_L, low(982) ldi FREQ_H, high(982) rcall Programm_lesen in temp, PINB andi temp, 0xF0 mov last_addr, temp rcall TUNER_WRITE ; ============================================================ ; Schleife ; ============================================================ MAIN: rcall TIMEDISPLAY sbis PINB, 3 rcall TIME_ADJUST sbis PINB, 0 rjmp INC_FREQ sbis PINB, 1 rjmp PROGW sbis PINB, 2 rjmp DEC_FREQ rcall ToBCD rcall DISPLAY ; EEPROM-Adresse prüfen in temp2, PINB andi temp2, 0xF0 cp temp2, last_addr breq NO_ADDR_CHANGE mov last_addr, temp2 rcall Programm_lesen rcall TUNER_WRITE NO_ADDR_CHANGE: mov XL, last_addr lsr XL lsr XL lsr XL lsr XL inc XL rcall ShowProgSlot rcall DISPLAY_CLOCK rjmp MAIN ; ============================================================ ; RTC Initialisierung (SQWE auf 1Hz, CH-Bit löschen) ; Startzeit: 12:34:00, 13. März 2019 ; ============================================================ RTC_INIT: ; ------------------------ ; CH-Bit löschen (Sekunden-Register) ldi temp, 0b11010000 mov i2cadr, temp rcall i2c_start ldi i2cdata, 0x00 ; Register 0 = Sekunden rcall i2c_write ldi i2cdata, 0x00 ; Sekunden = 00 rcall i2c_write rcall i2c_stop ; ------------------------ ; SQWE setzen (Control Reg = 0x07) ldi temp, 0b11010000 mov i2cadr, temp rcall i2c_start ldi i2cdata, 0x07 ; Register 7 = Control rcall i2c_write ldi i2cdata, 0x10 ; SQWE=1, 1Hz rcall i2c_write rcall i2c_stop ret ; ============================================================ ; RTC lesen ; ============================================================ RTC_CHECK: ; ------------------------ ; Pointer auf Register 0 setzen (Sekunden) ldi temp, 0b11010000 ; DS1307 Write mov i2cadr, temp rcall i2c_start ldi i2cdata, 0x00 ; Register 0 = Sekunden rcall i2c_write rcall i2c_stop ; ------------------------ ; jetzt lesen ldi temp, 0b11010001 ; DS1307 Read mov i2cadr, temp rcall i2c_start ; Sekunden clc ; ACK rcall i2c_read mov temp, i2cdata andi temp, 0x7F ; nur 0..59 mov RTC_SEC, temp rcall i2c_put_ack ; Minuten clc rcall i2c_read mov RTC_MIN, i2cdata andi RTC_MIN, 0x7F ; nur 0..59 rcall i2c_put_ack ; Stunden clc rcall i2c_read mov RTC_HOUR, i2cdata andi RTC_HOUR, 0x3F ; nur 0..23 (bei 24h Modus) rcall i2c_put_ack ; Wochentag clc rcall i2c_read ; Tag clc rcall i2c_read ; Monat clc rcall i2c_read ; Status sec ; NACK für letztes Byte rcall i2c_read rcall i2c_stop ret ; ============================================================ ; BCD zu BINÄR ; ============================================================ ; Eingabe: temp = BCD ; Ausgabe: temp = Binär BCD2BIN: mov XH, temp andi XH, 0x0F ; Einer extrahieren swap temp andi temp, 0x0F ; Zehner extrahieren ldi XL, 10 mul temp, XL add r0, XH mov temp, r0 ret ; ============================================================ ; DISPLAY_CLOCK mit Doppelpunkt ; ============================================================ TIMEDISPLAY: rcall RTC_CHECK ; RTC_SEC, RTC_MIN, RTC_HOUR auslesen ; Sekunden LSB ? Doppelpunkt blinken mov temp, RTC_SEC andi temp, 1 brne colon_off rcall COLON_ON rjmp colon_done colon_off: rcall COLON_OFF2 colon_done: rcall DISPLAY_CLOCK ret DISPLAY_CLOCK: ; Minuten Zehner mov temp, RTC_MIN swap temp andi temp, 0x0F cbi PORTD, ZIFA sbi PORTD, ZIFB cbi PORTD, ZIFC sbi PORTD, ZIFD sbi PORTD, SEGI rcall ShowDigit rcall Delay_1ms ldi temp, 0xFF rcall SHIFT_OUT sbi PORTD, DISP_LATCH cbi PORTD, DISP_LATCH rcall Delay_1ms ; Minuten Einer mov temp, RTC_MIN andi temp, 0x0F sbi PORTD, ZIFA sbi PORTD, ZIFB cbi PORTD, ZIFC sbi PORTD, ZIFD sbi PORTD, SEGI rcall ShowDigit rcall Delay_1ms ldi temp, 0xFF rcall SHIFT_OUT sbi PORTD, DISP_LATCH cbi PORTD, DISP_LATCH rcall Delay_1ms ; Stunden Zehner mov temp, RTC_HOUR swap temp andi temp, 0x0F cbi PORTD, ZIFA cbi PORTD, ZIFB cbi PORTD, ZIFC sbi PORTD, ZIFD sbi PORTD, SEGI rcall ShowDigit rcall Delay_1ms ldi temp, 0xFF rcall SHIFT_OUT sbi PORTD, DISP_LATCH cbi PORTD, DISP_LATCH rcall Delay_1ms ; Stunden Einer mov temp, RTC_HOUR andi temp, 0x0F sbi PORTD, ZIFA cbi PORTD, ZIFB cbi PORTD, ZIFC sbi PORTD, ZIFD sbi PORTD, SEGI rcall ShowDigit rcall Delay_1ms ldi temp, 0xFF rcall SHIFT_OUT sbi PORTD, DISP_LATCH cbi PORTD, DISP_LATCH rcall Delay_1ms ret ; ============================================================ ; Doppelpunkt Routinen ; ============================================================ COLON_ON: ldi temp, 0xFE rcall SHIFT_OUT cbi PORTD, ZIFA cbi PORTD, ZIFB sbi PORTD, ZIFC sbi PORTD, ZIFD sbi PORTD, SEGI sbi PORTD, DISP_LATCH cbi PORTD, DISP_LATCH rcall Delay_1ms ldi temp, 0xFF rcall SHIFT_OUT cbi PORTD, ZIFA cbi PORTD, ZIFB sbi PORTD, ZIFC sbi PORTD, ZIFD sbi PORTD, SEGI sbi PORTD, DISP_LATCH cbi PORTD, DISP_LATCH rcall Delay_1ms ret COLON_OFF2: ldi temp, 0xFF rcall SHIFT_OUT sbi PORTD, ZIFA sbi PORTD, ZIFB sbi PORTD, ZIFC sbi PORTD, ZIFD sbi PORTD, SEGI sbi PORTD, DISP_LATCH cbi PORTD, DISP_LATCH rcall Delay_1ms ldi temp, 0xFF rcall SHIFT_OUT cbi PORTD, ZIFA cbi PORTD, ZIFB sbi PORTD, ZIFC sbi PORTD, ZIFD sbi PORTD, SEGI sbi PORTD, DISP_LATCH cbi PORTD, DISP_LATCH rcall Delay_1ms ret ;********************************************************* ;* * ;* I²C ATMEL-Routine, welche immer funktioniert! * ;* * ;********************************************************* ;*************************************************************************** ;* ;* FUNCTION ;* i2c_hp_delay ;* i2c_qp_delay ;* ;* DESCRIPTION ;* ;* SEE DOCUMENTATION !!! ;* ;* USAGE ;* no parameters ;* ;* RETURN ;* none ;* ;*************************************************************************** i2c_hp_delay: ldi i2cdelay,8 i2c_hp_delay_loop: dec i2cdelay brne i2c_hp_delay_loop ret i2c_qp_delay: ldi i2cdelay,2 i2c_qp_delay_loop: dec i2cdelay brne i2c_qp_delay_loop ret ;*************************************************************************** ;* ;* FUNCTION ;* i2c_rep_start ;* ;* DESCRIPTION ;* Assert repeated start condition and sends slave address. ;* ;* USAGE ;* i2cadr - Contains the slave address and transfer direction. ;* ;* RETURN ;* Carry flag - Cleared if a slave responds to the address. ;* ;* NOTE ;* IMPORTANT! : This funtion must be directly followed by i2c_start. ;* ;*************************************************************************** i2c_rep_start: sbi DDRC,SCLP ; force SCL low cbi DDRC,SDAP ; release SDA rcall i2c_hp_delay ; half period delay cbi DDRC,SCLP ; release SCL rcall i2c_qp_delay ; quarter period delay ;*************************************************************************** ;* ;* FUNCTION ;* i2c_start ;* ;* DESCRIPTION ;* Generates start condition and sends slave address. ;* ;* USAGE ;* i2cadr - Contains the slave address and transfer direction. ;* ;* RETURN ;* Carry flag - Cleared if a slave responds to the address. ;* ;* NOTE ;* IMPORTANT! : This funtion must be directly followed by i2c_write. ;* ;*************************************************************************** i2c_start: mov i2cdata,i2cadr ; copy address to transmitt register sbi DDRC,SDAP ; force SDA low rcall i2c_qp_delay ; quarter period delay ;*************************************************************************** ;* ;* FUNCTION ;* i2c_write ;* ;* DESCRIPTION ;* Writes data (one byte) to the I2C bus. Also used for sending ;* the address. ;* ;* USAGE ;* i2cdata - Contains data to be transmitted. ;* ;* RETURN ;* Carry flag - Set if the slave respond transfer. ;* ;* NOTE ;* IMPORTANT! : This funtion must be directly followed by i2c_get_ack. ;* ;*************************************************************************** i2c_write: sec ; set carry flag rol i2cdata ; shift in carry and out bit one rjmp i2c_write_first i2c_write_bit: lsl i2cdata ; if transmit register empty i2c_write_first: breq i2c_get_ack ; goto get acknowledge sbi DDRC,SCLP ; force SCL low brcc i2c_write_low ; if bit high nop ; (equalize number of cycles) cbi DDRC,SDAP ; release SDA rjmp i2c_write_high i2c_write_low: ; else sbi DDRC,SDAP ; force SDA low rjmp i2c_write_high ; (equalize number of cycles) i2c_write_high: rcall i2c_hp_delay ; half period delay cbi DDRC,SCLP ; release SCL rcall i2c_hp_delay ; half period delay rjmp i2c_write_bit ;*************************************************************************** ;* ;* FUNCTION ;* ;* DESCRIPTION ;* Get slave acknowledge response. ;* ;* USAGE ;* (used only by i2c_write in this version) ;* ;* RETURN ;* Carry flag - Cleared if a slave responds to a request. ;* ;*************************************************************************** i2c_get_ack: sbi DDRC,SCLP ; force SCL low cbi DDRC,SDAP ; release SDA rcall i2c_hp_delay ; half period delay cbi DDRC,SCLP ; release SCL i2c_get_ack_wait: sbis PINC,SCLP ; wait SCL high ;(In case wait states are inserted) rjmp i2c_get_ack_wait clc ; clear carry flag sbic PINC,SDAP ; if SDA is high sec ; set carry flag rcall i2c_hp_delay ; half period delay ret ;*************************************************************************** ;* ;* FUNCTION ;* i2c_do_transfer ;* ;* DESCRIPTION ;* Executes a transfer on bus. This is only a combination of i2c_read ;* and i2c_write for convenience. ;* ;* USAGE ;* i2cadr - Must have the same direction as when i2c_start was called. ;* see i2c_read and i2c_write for more information. ;* ;* RETURN ;* (depends on type of transfer, read or write) ;* ;* NOTE ;* IMPORTANT! : This funtion must be directly followed by i2c_read. ;* ;*************************************************************************** i2c_do_transfer: sbrs i2cadr,0 ; if dir = write rjmp i2c_write ; goto write data ;*************************************************************************** ;* ;* FUNCTION ;* i2c_read ;* ;* DESCRIPTION ;* Reads data (one byte) from the I2C bus. ;* ;* USAGE ;* Carry flag - If set no acknowledge is given to the slave ;* indicating last read operation before a STOP. ;* If cleared acknowledge is given to the slave ;* indicating more data. ;* ;* RETURN ;* i2cdata - Contains received data. ;* ;* NOTE ;* IMPORTANT! : This funtion must be directly followed by i2c_put_ack. ;* ;*************************************************************************** i2c_read: rol i2cstat ; store acknowledge ; (used by i2c_put_ack) ldi i2cdata,0x01 ; data = 0x01 i2c_read_bit: ; do sbi DDRC,SCLP ; force SCL low rcall i2c_hp_delay ; half period delay cbi DDRC,SCLP ; release SCL rcall i2c_hp_delay ; half period delay clc ; clear carry flag sbic PINC,SDAP ; if SDA is high sec ; set carry flag rol i2cdata ; store data bit brcc i2c_read_bit ; while receive register not full ;*************************************************************************** ;* ;* FUNCTION ;* i2c_put_ack ;* ;* DESCRIPTION ;* Put acknowledge. ;* ;* USAGE ;* (used only by i2c_read in this version) ;* ;* RETURN ;* none ;* ;*************************************************************************** i2c_put_ack: sbi DDRC,SCLP ; force SCL low ror i2cstat ; get status bit brcc i2c_put_ack_low ; if bit low goto assert low cbi DDRC,SDAP ; release SDA rjmp i2c_put_ack_high i2c_put_ack_low: ; else sbi DDRC,SDAP ; force SDA low i2c_put_ack_high: rcall i2c_hp_delay ; half period delay cbi DDRC,SCLP ; release SCL i2c_put_ack_wait: sbis PINC,SCLP ; wait SCL high rjmp i2c_put_ack_wait rcall i2c_hp_delay ; half period delay ret ;*************************************************************************** ;* ;* FUNCTION ;* i2c_stop ;* ;* DESCRIPTION ;* Assert stop condition. ;* ;* USAGE ;* No parameters. ;* ;* RETURN ;* None. ;* ;*************************************************************************** i2c_stop: sbi DDRC,SCLP ; force SCL low sbi DDRC,SDAP ; force SDA low rcall i2c_hp_delay ; half period delay cbi DDRC,SCLP ; release SCL rcall i2c_qp_delay ; quarter period delay cbi DDRC,SDAP ; release SDA rcall i2c_hp_delay ; half period delay ret ;*************************************************************************** ;* ;* FUNCTION ;* i2c_init ;* ;* DESCRIPTION ;* Initialization of the I2C bus interface. ;* ;* USAGE ;* Call this function once to initialize the I2C bus. No parameters ;* are required. ;* ;* RETURN ;* None ;* ;* NOTE ;* PORTC and DDRC pins not used by the I2C bus interface will be ;* set to Hi-Z (!). ;* ;* COMMENT ;* This function can be combined with other PORTC initializations. ;* ;*************************************************************************** i2c_init: clr i2cstat ; clear I2C status register (used ; as a temporary register) out PORTC,i2cstat ; set I2C pins to open colector out DDRC,i2cstat ret ;***************************************************************************************************** ;* * ;* Ende der ATMEL-Applikation * ;* * ;***************************************************************************************************** ; ============================================================ ; EEPROM-Routinen ; ============================================================ Programm_speichern: in temp2, PINB andi temp2, 0xF0 lsr temp2 lsr temp2 lsr temp2 lsr temp2 lsl temp2 Warten_EEWE1: sbic EECR, EEWE rjmp Warten_EEWE1 out EEARL, temp2 out EEDR, FREQ_L sbi EECR, EEMWE sbi EECR, EEWE Warten_Schreiben1: sbic EECR, EEWE rjmp Warten_Schreiben1 inc temp2 Warten_EEWE2: sbic EECR, EEWE rjmp Warten_EEWE2 out EEARL, temp2 out EEDR, FREQ_H sbi EECR, EEMWE sbi EECR, EEWE Warten_Schreiben2: sbic EECR, EEWE rjmp Warten_Schreiben2 ret Programm_lesen: in temp2, PINB andi temp2, 0xF0 lsr temp2 lsr temp2 lsr temp2 lsr temp2 lsl temp2 Warten_EEWE3: sbic EECR, EEWE rjmp Warten_EEWE3 out EEARL, temp2 sbi EECR, EERE in temp, EEDR mov FREQ_L, temp inc temp2 out EEARL, temp2 sbi EECR, EERE in temp, EEDR mov FREQ_H, temp cpi FREQ_L, 0xFF brne OK cpi FREQ_H, 0xFF brne OK ldi FREQ_L, low(1029) ldi FREQ_H, high(1029) OK: ret ; ============================================================ ; Uhrzeit einstellen ; ============================================================ TIME_ADJUST: sbis PINB, 0 rjmp TIME_DEC_MIN sbis PINB, 2 rjmp TIME_INC_MIN ret TIME_INC_MIN: inc RTC_MIN cpi RTC_MIN, 60 brlo TIME_INC_HALT ldi RTC_MIN, 0 inc RTC_HOUR cpi RTC_HOUR, 24 brlo TIME_INC_HALT ldi RTC_HOUR, 0 TIME_INC_HALT: ret TIME_DEC_MIN: cpi RTC_MIN, 0 brne TIME_DEC_OK ldi RTC_MIN, 59 dec RTC_HOUR cpi RTC_HOUR, 0 brsh TIME_DEC_HALT ldi RTC_HOUR, 23 rjmp TIME_DEC_HALT TIME_DEC_OK: dec RTC_MIN TIME_DEC_HALT: ret ; ============================================================ ; Warteschleifen ; ============================================================ Delay_100us: ldi temp, 25 ; Feintuning nötig! L1: dec temp brne L1 ret ; ============================================================ ; Frequenzwahl und Speicherung ; ============================================================ PROGW: rcall Programm_speichern rcall ShowProgSlot ldi temp, 0xFF rcall SHIFT_OUT sbi PORTD, DISP_LATCH cbi PORTD, DISP_LATCH cbi PORTD, ZIFA cbi PORTD, ZIFB cbi PORTD, ZIFC cbi PORTD, ZIFD sbi PORTD, SEGI rcall Delay_1ms cbi PORTD, SEGI rcall Delay_1ms sbi PORTD, SEGI sbis PINB, 1 rjmp PROGW rjmp MAIN INC_FREQ: ldi temp, 0b01111111 rcall SHIFT_OUT cbi PORTD, ZIFA sbi PORTD, ZIFB sbi PORTD, ZIFC cbi PORTD, ZIFD sbi PORTD, SEGI sbi PORTD, DISP_LATCH cbi PORTD, DISP_LATCH rcall Delay_1ms rcall ToBCD rcall DISPLAY sbis PINB, 0 rjmp INC_FREQ inc FREQ_L brne INC_CHECK_MAX inc FREQ_H INC_CHECK_MAX: ; >= 1189 ? mov XH, FREQ_H mov XL, FREQ_L ldi temp, low(1189) cp XL, temp ldi temp, high(1189) cpc XH, temp brlo INC_DONE ; >= ? zurücksetzen auf 982 ldi FREQ_L, low(982) ldi FREQ_H, high(982) INC_DONE: rcall TUNER_WRITE rjmp MAIN DEC_FREQ: ; Anzeige zeigen während gedrückt ldi temp, 0b01111111 rcall SHIFT_OUT cbi PORTD, ZIFA cbi PORTD, ZIFB sbi PORTD, ZIFC cbi PORTD, ZIFD sbi PORTD, SEGI sbi PORTD, DISP_LATCH cbi PORTD, DISP_LATCH rcall Delay_1ms rcall ToBCD rcall DISPLAY ; Warten bis losgelassen sbis PINB, 2 rjmp DEC_FREQ ; Zähler runter dec FREQ_L brne DEC_CHECK_MIN dec FREQ_H DEC_CHECK_MIN: ; Prüfen ob < 982 mov XH, FREQ_H mov XL, FREQ_L ldi temp, low(982) cp XL, temp ldi temp, high(982) cpc XH, temp brsh DEC_OK ; Wenn ? 982 ? OK DEC_WRAP: ldi FREQ_L, low(1189) ldi FREQ_H, high(1189) rjmp MAIN DEC_OK: rcall TUNER_WRITE rjmp MAIN ; ============================================================ ; 16-Bit -> BCD Vorstufe ; ============================================================ ToBCD: mov XH, FREQ_H mov XL, FREQ_L rcall WANDEL ret ; ===================================== ; Anzeige Programmplatz als "P01".."P16" ; Erwartet: XL = 1..16 ; ===================================== ShowProgSlot: ; ---- P ---- ldi temp, 10 ; Index 10 in SEG_TABLE = "P" rcall ShowDigit ; Digit-Select für erste Stelle cbi PORTD, ZIFA cbi PORTD, ZIFB sbi PORTD, ZIFC cbi PORTD, ZIFD sbi PORTD, SEGI rcall Delay_1ms ; ---- Zehner ---- mov temp, XL ldi temp2, 10 cp temp, temp2 brlo ProgUnitsOnly ; kleiner 10 ? Zehner = 0 ldi temp, 1 ; 10..16 ? Zehner = 1 rcall ShowDigit ; Digit-Select zweite Stelle sbi PORTD, ZIFA cbi PORTD, ZIFB sbi PORTD, ZIFC cbi PORTD, ZIFD sbi PORTD, SEGI rcall Delay_1ms rjmp ProgUnits ProgUnitsOnly: ; optional führende Null: ldi temp, 0 rcall ShowDigit ; Digit-Select zweite Stelle sbi PORTD, ZIFA cbi PORTD, ZIFB sbi PORTD, ZIFC cbi PORTD, ZIFD sbi PORTD, SEGI rcall Delay_1ms ProgUnits: ; ---- Einer ---- mov temp, XL cpi temp, 10 brlo NoSub10 subi temp, 10 NoSub10: rcall ShowDigit ; Digit-Select dritte Stelle cbi PORTD, ZIFA sbi PORTD, ZIFB sbi PORTD, ZIFC cbi PORTD, ZIFD sbi PORTD, SEGI rcall Delay_1ms ; ---- Letzte Stelle blank ---- ldi temp, 0xFF ; Annahme: 0xFF = alle Segmente aus rcall SHIFT_OUT sbi PORTD, DISP_LATCH cbi PORTD, DISP_LATCH ; Digit-Select vierte Stelle sbi PORTD, ZIFA sbi PORTD, ZIFB sbi PORTD, ZIFC cbi PORTD, ZIFD sbi PORTD, SEGI rcall Delay_1ms ret ; ============================================================ ; 16-Bit -> BCD ; ============================================================ WANDEL: ldi temp, low(107) sub XL, temp ldi temp, high(107) sbc XH, temp rcall Div16_10 mov DIG0, XL mov XH, YH mov XL, YL rcall Div16_10 mov DIG1, XL mov XH, YH mov XL, YL rcall Div16_10 mov DIG2, XL mov DIG3, YL ret ; ============================================================ ; Schnelle 16-bit durch 10 Division ; ============================================================ Div16_10: push r2 push r19 push r18 push r17 ldi YH,0xCC ldi YL,0xCD clr r2 mul XH, YH movw r19:r18, r1:r0 mul XL, YL mov r17, r1 mul XH, YL add r17, r0 adc r18, r1 adc r19, r2 mul YH, XL add r17, r0 adc r18, r1 adc r19, r2 lsr r19 ror r18 lsr r19 ror r18 lsr r19 ror r18 ldi r17,10 mul r18, r17 sub XL, r0 clr XH mov YH, r19 mov YL, r18 pop r17 pop r18 pop r19 pop r2 ret ; ============================================================ ; Anzeige ; ============================================================ DISPLAY: mov temp, DIG0 rcall ShowDigit sbi PORTD, ZIFA sbi PORTD, ZIFB cbi PORTD, ZIFC cbi PORTD, ZIFD sbi PORTD, SEGI rcall Delay_1ms mov temp, DIG1 rcall ShowDigit cbi PORTD, ZIFA sbi PORTD, ZIFB cbi PORTD, ZIFC cbi PORTD, ZIFD sbi PORTD, SEGI rcall Delay_1ms mov temp, DIG2 rcall ShowDigit sbi PORTD, ZIFA cbi PORTD, ZIFB cbi PORTD, ZIFC cbi PORTD, ZIFD sbi PORTD, SEGI rcall Delay_1ms mov temp, DIG3 rcall ShowDigit cbi PORTD, ZIFA cbi PORTD, ZIFB cbi PORTD, ZIFC cbi PORTD, ZIFD sbi PORTD, SEGI rcall Delay_1ms ret DISPLAY2: mov temp, DIG1 rcall ShowDigit cbi PORTD, ZIFA sbi PORTD, ZIFB sbi PORTD, ZIFC cbi PORTD, ZIFD sbi PORTD, SEGI rcall Delay_1ms mov temp, DIG0 rcall ShowDigit sbi PORTD, ZIFA cbi PORTD, ZIFB sbi PORTD, ZIFC cbi PORTD, ZIFD sbi PORTD, SEGI rcall Delay_1ms ldi temp, 10 rcall ShowDigit cbi PORTD, ZIFA cbi PORTD, ZIFB sbi PORTD, ZIFC cbi PORTD, ZIFD sbi PORTD, SEGI rcall Delay_1ms ret ShowDigit: ldi ZL, low(SEG_TABLE * 2) ldi ZH, high(SEG_TABLE * 2) add ZL, temp adc ZH, r1 lpm temp, Z rcall SHIFT_OUT sbi PORTD, DISP_LATCH cbi PORTD, DISP_LATCH ret ; ============================= ; TUNER schreiben (PLL) ; ============================= TUNER_WRITE: ; Noch in Test ret ; ============================================================ ; Shift-Out-Display ; ============================================================ SHIFT_OUT: ldi temp2, 8 SHIFT_BIT: rol temp brcs SHIFT_ONE cbi PORTD, LM_SIN rjmp SHIFT_CLK SHIFT_ONE: sbi PORTD, LM_SIN SHIFT_CLK: sbi PORTD, LM_SCK cbi PORTD, LM_SCK dec temp2 brne SHIFT_BIT ret ; ============================================================ ; Shift-Out-Tuner (Reserve) ; ============================================================ SHIFT_OUTLM: ldi temp2, 8 SHIFT_BITLM: rol temp brcs SHIFT_ONELM cbi PORTD, LM_SIN rjmp SHIFT_CLK SHIFT_ONELM: sbi PORTD, LM_SIN SHIFT_CLKLM: dec temp2 brne SHIFT_BITLM ret MULT25: ; XH:XL = FREQ_H:FREQ_L mov XH, FREQ_H mov XL, FREQ_L ; temp2:temp = Ergebnis clr temp clr temp2 ; tmp1 = FREQ << 4 movw r30:r31, XH:XL lsl XL rol XH lsl XL rol XH lsl XL rol XH lsl XL rol XH ; Ergebnis = tmp1 mov temp, XL mov temp2, XH ; tmp1 = FREQ << 3 movw XH:XL, FREQ_H:FREQ_L lsl XL rol XH lsl XL rol XH lsl XL rol XH ; Ergebnis += tmp1 add temp, XL adc temp2, XH ; Ergebnis += FREQ add temp, FREQ_L adc temp2, FREQ_H ; Speichere zurück mov FREQ_L, temp mov FREQ_H, temp2 ret DIV25: ; XH:XL = FREQ_H:FREQ_L (mit 25 multipliziert) ; Ergebnis = durch 25 geteilt -> zurück in FREQ mov XH, FREQ_H mov XL, FREQ_L clr temp ; Quotient low clr temp2 ; Quotient high DIV25_LOOP: ; Subtrahiere 25 subi XL, low(25) sbci XH, high(25) brcs DIV25_DONE ; Wenn negativ: fertig ; Inkrementiere Quotient inc temp brne DIV25_LOOP inc temp2 rjmp DIV25_LOOP DIV25_DONE: ; Ergebnis speichern mov FREQ_L, temp mov FREQ_H, temp2 ret ; ============================================================ ; Segment-Tabelle ; ============================================================ SEG_TABLE: .db 0b11000000 , 0b11111001 ; 0, 1 .db 0b10100100 , 0b10110000 ; 2, 3 .db 0b10011001 , 0b10010010 ; 4, 5 .db 0b10000010 , 0b11111000 ; 6, 7 .db 0b10000000 , 0b10010000 ; 8, 9 .db 0b10001100 , 0b10001001 ; P, H .db 0b10000110 , 0b10000110 ; E, E .db 0b10000110 , 0b10000110 ; E, E ; ============================================================ ; Warteschleifen 2 ; ============================================================ Delay_1ms: ldi temp, 200 W1: dec temp brne W1 ret ; ============================================================ ; Ende des Programms ; ============================================================