; ============================================================ ; ATmega8 FM-Radio mit LM7001 & 7-Segment ; Verbesserte Version mit PB4–PB7 als EEPROM-Adresse ; ============================================================ .include "m8def.inc" ; ----------------------------- ; Register ; ----------------------------- .def temp = r16 .def temp2 = r17 .def FREQ_L = r18 ; Aktuelle Frequenz LSB .def FREQ_H = r19 ; Aktuelle Frequenz MSB .def DIG0 = r20 .def DIG1 = r21 .def DIG2 = r22 .def DIG3 = r23 .def last_addr = r24 ; ----------------------------- ; EEPROM-Adresse (Basis, nur symbolisch) ; ----------------------------- .equ EE_FREQ = 0x00 ; ----------------------------- ; Pins ; ----------------------------- .equ LM_EN = 5 ; PD5 Enable LM7001 .equ LM_SIN = 3 ; PD3 SIN / DATA .equ LM_SCK = 4 ; PD4 SCK / CLK .equ DISP_LATCH = 6 ; PD6 Latch Display ; Digit-Select .equ ZIFA = 0 ; PD0 A0 .equ ZIFB = 1 ; PD1 A1 ; ----------------------------- ; RESET-Vektor ; ----------------------------- .org 0x0000 rjmp RESET ; ============================================================ ; RESET & Init ; ============================================================ RESET: clr r1 ldi temp, high(RAMEND) out SPH, temp ldi temp, low(RAMEND) out SPL, temp ; PORTD als Ausgang ldi temp, 0xFF out DDRD, temp ; PORTB als Eingang, interne Pullups ldi temp, 0x00 out DDRB, temp ldi temp, 0xFF out PORTB, temp ; Default Frequenz ldi FREQ_L, low(982) ldi FREQ_H, high(982) rcall Programm_lesen ; PB4–PB7 merken in last_addr, PINB andi last_addr, 0xF0 rcall TUNER_WRITE ; ============================================================ ; Hauptschleife ; ============================================================ MAIN: rcall Delay_1ms sbis PINB, 0 rjmp INC_FREQ sbis PINB, 1 rjmp PROGW sbis PINB, 2 rjmp DEC_FREQ rcall ToBCD rcall DISPLAY ; Adresse prüfen in temp2, PINB andi temp2, 0xF0 cp temp2, last_addr breq NO_ADDR_CHANGE ; Adresse neu -> neu laden mov last_addr, temp2 rcall Programm_lesen rcall TUNER_WRITE NO_ADDR_CHANGE: rjmp MAIN PROGW: rcall Programm_speichern rcall Delay_1ms rjmp MAIN INC_FREQ: 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 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 ; ============================================================ ToBCD: mov XH, FREQ_H mov XL, FREQ_L 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, DIG3 rcall ShowDigit sbi PORTD, ZIFA sbi PORTD, ZIFB rcall Delay_1ms mov temp, DIG2 rcall ShowDigit cbi PORTD, ZIFA sbi PORTD, ZIFB rcall Delay_1ms mov temp, DIG1 rcall ShowDigit sbi PORTD, ZIFA cbi PORTD, ZIFB rcall Delay_1ms mov temp, DIG0 rcall ShowDigit cbi PORTD, ZIFA cbi PORTD, ZIFB 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 (LM7001) ; ============================= TUNER_WRITE: sbi PORTD, LM_EN mov temp, FREQ_L rcall SHIFT_OUTLM mov temp, FREQ_H rcall SHIFT_OUTLM ldi temp, 128 rcall SHIFT_OUTLM cbi PORTD, LM_EN 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 ; ============================================================ 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 ; ============================================================ ; 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 ; ============================================================ ; Delays ; ============================================================ Delay_1ms: ldi temp, 200 W1: dec temp brne W1 ret Delay_300ms: ldi temp, 150 D300: rcall Delay_1ms dec temp brne D300 ret ; ============================================================ ; EEPROM mit PB4–PB7 als Adresse ; ============================================================ 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