; ATmega328.V3.asm Nov 05, 2021 ; cd ~/Desktop/freddieneil.com/kitsandparts.com/tutorials/328/ ; avra ATmega328.V3.asm ; avrdude -P usb -p m328p -c avrispv2 -U ATmega328.V3.hex ; avrdude -P usb -p m328p -c avrispv2 -U flash:w:ATmega328.V3.hex -U eeprom:w:ATmega328.V3.eep.hex ; avrdude -P usb -p m328p -c avrispv2 -U eeprom:r:eeprom:i ; avrdude -P usb -p m328p -c avrispv2 -U lfuse:w:0x62:m -U hfuse:w:0xD9:m -U efuse:w:0xFF:m .include "../include/m328Pdef.inc" .equ encoder_type = 0 ; Declares decoder. 0=none, 1=mechanical, 2=optical .equ LCD_DRS= PC0 .equ LCD_CP = PC1 .equ LCD_E = PC2 .equ LED = PC3 .equ button = PD1 .equ output_a = PD2 .equ output_b = PD3 .def mx0 = r2 .def mx1 = r3 .def mx2 = r4 .def mx3 = r5 .def mz0 = r6 .def mz1 = r7 .def mz2 = r8 .def mz3 = r9 .def mz4 = r10 .def mz5 = r11 .def mz6 = r12 .def mz7 = r13 .def press = r14 .def encoder =r15 .def temp1 =r16 .def temp2 =r17 .def temp3 =r18 .def temp4 =r19 .def temp5 =r20 .def delay =r21 .def my0 = r22 .def my1 = r23 .def my2 = r24 .def my3 = r25 .def XL = r26 .def XH = r27 .def YL = r28 .def YH = r29 .def ZL = r30 .def ZH = r31 .eseg .org 0 frequency_memory_0: .db "12345678" frequency_memory_1: .db "12345678" frequency_memory_2: .db "12345678" frequency_memory_3: .db "12345678" frequency_memory_4: .db "12345678" frequency_memory_5: .db "12345678" frequency_memory_6: .db "12345678" frequency_memory_7: .db "12345678" frequency_memory_8: .db "12345678" frequency_memory_9: .db "12345678" cursor_number_eeprom: .db $05 .dseg .org SRAM_START test_buffer: .byte 8; buffer for displaying memory data frequency: .byte 8; ascii displayed frequency freq_hex: .byte 4 ; 32 bit Hex frequency cursor_number_sram: .byte 1 .cseg .org 0 jmp RESET jmp EXT_INT0 ; External Interrupt Request 0 jmp EXT_INT1 ; External Interrupt Request 1 jmp NOT_USED ; Pin Change Interrupt Request 0 jmp NOT_USED ; Pin Change Interrupt Request 1 jmp NOT_USED ; Pin Change Interrupt Request 2 jmp NOT_USED ; Watchdog Time-out Interrupt jmp NOT_USED ; Timer/Counter2 Compare Match A jmp NOT_USED ; Timer/Counter2 Compare Match A jmp NOT_USED ; Timer/Counter2 Overflow jmp NOT_USED ; Timer/Counter1 Capture Event jmp NOT_USED ; Timer/Counter1 Compare Match A jmp NOT_USED ; Timer/Counter1 Compare Match B jmp NOT_USED ; Timer/Counter1 Overflow jmp NOT_USED ; TimerCounter0 Compare Match A jmp NOT_USED ; TimerCounter0 Compare Match B jmp OVF0 ; Timer/Counter0 Overflow jmp NOT_USED ; SPI Serial Transfer Complete jmp NOT_USED ; USART Rx Complete jmp NOT_USED ; USART, Data Register Empty jmp NOT_USED ; USART Tx Complete jmp NOT_USED ; ADC Conversion Complete jmp NOT_USED ; EEPROM Ready jmp NOT_USED ; ;Analog Comparator jmp NOT_USED ; Two-wire Serial Interface jmp NOT_USED ; Store Program Memory Read NOT_USED: reti RESET: ldi temp1, low(RAMEND) out SPL, temp1 ; Set stack pointer to last internal RAM location ldi temp1, high(RAMEND) out SPH, temp1 ;init ports ldi temp1,$0F out DDRC,temp1 ;make PC0,PC1,PC2,PC3 pins an output cbi PORTC,LCD_E ;set LCD_E low cbi PORTC,LCD_CP ;set LCD_CP low sbi PORTC,LED ;turn LED off ldi temp1, 0 out DDRD, temp1 ;all of portd is input ;init misc ; set System Clock Prescaler - system default clock is 8.0 MHz ldi temp1, 0b10000000 ; init for prescaler change sts CLKPR, temp1 ; else out instruction to CLKPS will not take effect ; ldi temp1, 0b00000000 ; prescaler / 1 - ( 8.0 MHz / 1) = 8.000 MHz = 125 nanoseconds ; ldi temp1, 0b00000001 ; prescaler / 2 - ( 8.0 MHz / 2) = 4.000 MHz = 250 nanoseconds ; ldi temp1, 0b00000010 ; prescaler / 4 - ( 8.0 MHz / 4) = 2.000 MHz = 500 nanoseconds ldi temp1, 0b00000011 ; prescaler / 8 - factory default; set by Fuse Low Byte ( 8.0 MHz / 8) = 1.000 MHz = 1.000 microsecond ; ldi temp1, 0b00000100 ; prescaler / 16 - ( 8.0 MHz / 16) = 500 KHz = 2.000 microseconds ; the setting below disable reprogramming the uP - must use "-B 500" with AVRDUDE to fix ; ldi temp1, 0b00000101 ; prescaler / 32 - ( 8.0 MHz / 32) = 250 KHz = 4.000 microseconds ; ldi temp1, 0b00000110 ; prescaler / 64 - ( 8.0 MHz / 64) = 125 KHz = 8.000 microseconds ; ldi temp1, 0b00000111 ; prescaler / 128 - ( 8.0 MHz / 128) = 62.5 KHz = 16.000 microseconds ; ldi temp1, 0b00001000 ; prescaler / 256 - ( 8.0 MHz / 256) = 31250 Hz = 32.000 microseconds sts CLKPR, temp1 ; with prescaler set to 8: ; ldi temp1, 0b00000001 ; no prescaling ldi temp1, 0b00000010 ; CLK 1/8 from prescaler (8.000 uS) ; ldi temp1, 0b00000011 ; CLK 1/64 ; ldi temp1, 0b00000100 ; CLK 1/256 ; ldi temp1, 0b00000101 ; CLK 1/1024 out TCCR0B, temp1 ; set timer prescaler ldi temp1, 0b00000001 ; overflow interrupt enable bit sts TIMSK0,temp1 ;enable TIMER0 overflow interrupts ldi temp1,0b00000101 ; Any change of INT0 & INT1 generate an interrupt request sts EICRA,temp1 sbi EIMSK,0 ;enable INT0 interrupts sbi EIMSK,1 ;enable INT1 interrupts clr encoder ;clear encoder interrupt counts sei ;global all interrupt enable ldi YH,high(cursor_number_eeprom) ldi YL,low(cursor_number_eeprom) rcall EEPROM_READ tst temp1 breq MOVE_DEFAULT_CURSOR_TO_EEPROM cpi temp1,$09 brlo CURSOR_NUMBER_IN_EEPROM_OK MOVE_DEFAULT_CURSOR_TO_EEPROM: ldi temp1,3 rcall EEPROM_WRITE CURSOR_NUMBER_IN_EEPROM_OK: ld temp1,Y ldi XH,high(cursor_number_sram) ldi XL,low(cursor_number_sram) st X,temp1 MSG_PORK: ; "1234567890123456" .db " 04 Oct 2021 ",0,0 MSG_CMD: ; "1234567890123456" .db "Porkalyzer.328v0",0,0 PORK: rcall INIT_LCD ldi ZH,high(2*MSG_PORK) ldi ZL,low(2*MSG_PORK) ldi temp2,$80 ;display on line 1 rcall LCDCMD rcall DISPLAY_LINE ldi temp1,3 ;blink LED 3x to show system is working rcall BLINK_LED ; has effect of a delay 1.5 seconds rcall load_last_entered_frequency rcall ShowFreq call ASCII8_HEX4 MENU: ldi ZH,high(2*MSG_CMD) ldi ZL,low(2*MSG_CMD) ldi temp2,$C0 ;display on line 2 rcall LCDCMD rcall DISPLAY_LINE GET_CMD: CMD025: tst encoder breq CMD049 jmp process_encoder CMD049: rjmp GET_CMD MSG_CURSOR: ; 1234567890123456789012345678901234567890 .db " Cursor Loc: 1 ",0,0 set_default_cursor: ldi ZH,high(2*MSG_CURSOR) ldi ZL,low(2*MSG_CURSOR) ldi temp2,$C0 ;display on line 1 rcall LCDCMD rcall DISPLAY_LINE ldi XH,high(cursor_number_sram) ldi XL,low(cursor_number_sram) ld temp3,X ; default cursor value ori temp3,$30 SC103: ldi temp2,$CD ; set CURSOR rcall LCDCMD SC105: rcall get_keypad ; return character in temp1 tst temp1 breq SC105 cpi temp1,'0' ; '0' is illegal breq SC105 cpi temp1,'#' ; enter key breq SC120 ; all done with keypad entry cpi temp1,'*' ; enter key breq SC999 ; Escape key (*) cpi temp1,$39 ; disregard keys 9,A,B,C,D brge SC105 mov temp3,temp1 rcall LCDCHR rjmp SC103 SC120: ldi YH,high(cursor_number_eeprom) ldi YL,low(cursor_number_eeprom) subi temp3,$30 st X,temp3 mov temp1,temp3 rcall EEPROM_WRITE SC999: rjmp MENU rjmp MENU MSG_LM: ; 1234567890123456789012345678901234567890 .db "Load from Mem: 1",0,0 load_from_memory: ldi ZH,high(2*MSG_LM) ldi ZL,low(2*MSG_LM) ldi temp2,$C0 ;display on line 1 rcall LCDCMD rcall DISPLAY_LINE ldi temp3,$31 ; default save memory number LM103: ldi temp2,$CF ; set CURSOR rcall LCDCMD LM105: rcall get_keypad ; return character in temp1 tst temp1 breq LM105 cpi temp1,'#' ; enter key breq LM120 ; all done with keypad entry cpi temp1,'*' ; escape key breq LM999 ; Escape key (*) cpi temp1,$3A ; disregard keys A,B,C brge LM105 mov temp3,temp1 rcall LCDCHR rjmp LM103 LM120: ldi ZH,high(frequency) ldi ZL,low(frequency) ldi YH,high(frequency_memory_0) ldi YL,low(frequency_memory_0) subi temp3,$30 breq LM140 LM130: adiw YL,8 ; move EEPROM memory pointer to next frequency memory dec temp3 brne LM130 LM140: ldi my3,8 LM150: rcall EEPROM_READ st Z+,temp1 adiw YL,1 ; increment EEPROM memory pointer dec my3 brne LM150 call ASCII8_HEX4 LM999: rjmp MENU load_last_entered_frequency: ldi ZH,high(frequency) ldi ZL,low(frequency) ldi YH,high(frequency_memory_0) ldi YL,low(frequency_memory_0) ldi my3,8 LLEF5: rcall EEPROM_READ st Z+,temp1 adiw YL,1 ; increment EEPROM memory pointer dec my3 brne LLEF5 ret MSG_SM: ; "1234567890123456" .db " Save to Mem: 1 ",0,0 save_to_memory: ldi ZH,high(2*MSG_SM) ldi ZL,low(2*MSG_SM) ldi temp2,$C0 ;display on line 1 rcall LCDCMD rcall DISPLAY_LINE ldi temp3,$31 ; default save memory number SM103: ldi temp2,$CE ; set CURSOR rcall LCDCMD SM105: rcall get_keypad ; return character in temp1 tst temp1 breq SM105 cpi temp1,'#' ; enter key breq SM120 ; all done with keypad entry cpi temp1,'*' ; enter key breq SM999 ; Escape key (*) cpi temp1,$3A ; disregard keys A,B,C brge SM105 mov temp3,temp1 rcall LCDCHR rjmp SM103 SM120: ldi ZH,high(frequency) ldi ZL,low(frequency) ldi YH,high(frequency_memory_0) ldi YL,low(frequency_memory_0) subi temp3,$30 breq SM140 SM130: adiw YL,8 ; move EEPROM memory pointer to next frequency memory dec temp3 brne SM130 SM140: ldi my3,8 SM150: ld temp1,Z+ rcall EEPROM_WRITE adiw YL,1 ; increment EEPROM memory pointer dec my3 brne SM150 SM999: rjmp MENU MSG_EF: ; 1234567890123456789012345678901234567890 .db "Freq:",0 enter_frequency: ldi ZH,high(2*MSG_EF) ldi ZL,low(2*MSG_EF) ldi temp2,$C0 ;display on line 1 rcall LCDCMD rcall DISPLAY_LINE ldi temp1,' ' ; space ldi ZH,high(frequency) ldi ZL,low(frequency) ; clear frequency buffer ldi temp1,' ' st Z+,temp1 ldi temp1,' ' st Z+,temp1 ldi temp1,' ' st Z+,temp1 ldi temp1,' ' st Z+,temp1 ldi temp1,' ' st Z+,temp1 ldi temp1,' ' st Z+,temp1 ldi temp1,' ' st Z+,temp1 ldi temp1,' ' st Z,temp1 EF100: ldi temp2,$C5 ; set CURSOR rcall LCDCMD rcall display_freq_buffer EF103: ldi temp2,$CE ; set CURSOR rcall LCDCMD EF105: rcall get_keypad ; return character in temp1 tst temp1 breq EF105 cpi temp1,'*' ; backspace key brne EF108 ; *** start update_freq_buffer_right *** ldi ZH,high(frequency+7) ldi ZL,low(frequency+7) ld temp2,Z+ cpi temp2,' ' brne EF106 rjmp MENU EF106: st Z,temp2 sbiw ZL,2 ld temp2,Z+ st Z,temp2 sbiw ZL,2 ld temp2,Z+ st Z,temp2 sbiw ZL,2 ld temp2,Z+ st Z,temp2 sbiw ZL,2 ld temp2,Z+ st Z,temp2 sbiw ZL,2 ld temp2,Z+ st Z,temp2 sbiw ZL,2 ld temp2,Z+ st Z,temp2 sbiw ZL,2 ld temp2,Z+ st Z,temp2 sbiw ZL,1 ldi temp2,' ' st Z,temp2 ; *** end of update_freq_buffer_right *** ldi temp2,$C5 ; set CURSOR rcall LCDCMD rcall display_freq_buffer rjmp EF103 EF108: cpi temp1,'#' ; enter key breq EF115 ; all done with keypad entry cpi temp1,$3A ; disregard keys A,B,C,D brge EF103 rcall update_freq_buffer_left ldi temp2,$C5 ; set CURSOR rcall LCDCMD rcall display_freq_buffer rjmp EF103 EF115: rcall ASCII8_HEX4 rcall save_last_entered_frequency rjmp MENU ASCII8_HEX4: ; convert ascii freq to 4 byte hex ldi ZH,high(freq_hex) ldi ZL,low(freq_hex) clr temp1 st Z+,temp1 ; clear freq_hex st Z+,temp1 st Z+,temp1 st Z,temp1 ldi temp2,8 ; convert 8 ascii freq bytes to 4 hex bytes ldi ZH,high(frequency) ldi ZL,low(frequency) EF122: ld temp1,Z+ cpi temp1,' ' breq EF123 subi temp1,$30 rcall multiply_freq_hex_by_10_and_add EF123: dec temp2 brne EF122 rcall ShowFreq ret save_last_entered_frequency: ldi ZH,high(frequency) ldi ZL,low(frequency) ldi YH,high(frequency_memory_0) ldi YL,low(frequency_memory_0) ldi my3,8 SLEF5: ld temp1,Z+ rcall EEPROM_WRITE adiw YL,1 ; increment EEPROM memory pointer dec my3 brne SLEF5 ret ;********************************** ;* ShowFreq ;* uses temp1 & temp2 ;*********************************** ShowFreq: ;display freq on LCD ldi temp2,$80 rcall LCDCMD ldi temp1,' ' rcall LCDCHR ldi ZH,high(frequency) ldi ZL,low(frequency) ld temp1,Z+ rcall LCDCHR ld temp1,Z+ rcall LCDCHR cpi temp1,' ' breq ShowFreq3 ldi temp1,',' ShowFreq3: rcall LCDCHR ld temp1,Z+ rcall LCDCHR ld temp1,Z+ rcall LCDCHR ld temp1,Z+ rcall LCDCHR cpi temp1,' ' breq ShowFreq5 ldi temp1,',' ShowFreq5: rcall LCDCHR ld temp1,Z+ rcall LCDCHR ld temp1,Z+ rcall LCDCHR ld temp1,Z+ rcall LCDCHR ldi temp1,' ' rcall LCDCHR ldi temp1,'H' rcall LCDCHR ldi temp1,'z' rcall LCDCHR ldi temp1,' ' rcall LCDCHR ret multiply_freq_hex_by_10_and_add: push ZL push ZH push temp1 ldi ZH,high(freq_hex) ldi ZL,low(freq_hex) ld mx3,Z+ mov my3,mx3 ld mx2,Z+ mov my2,mx2 ld mx1,Z+ mov my1,mx1 ld mx0,Z+ mov my0,mx0 lsl mx0 rol mx1 rol mx2 rol mx3 lsl mx0 rol mx1 rol mx2 rol mx3 lsl mx0 rol mx1 rol mx2 rol mx3 add mx0,my0 adc mx1,my1 adc mx2,my2 adc mx3,my3 add mx0,my0 adc mx1,my1 adc mx2,my2 adc mx3,my3 pop temp1 clr my0 add mx0,temp1 st -Z,mx0 adc mx1,my0 st -Z,mx1 adc mx2,my0 st -Z,mx2 adc mx3,my0 st -Z,mx3 pop ZH pop ZL ret update_freq_buffer_left: ldi ZH,high(frequency+1) ldi ZL,low(frequency+1) ld temp2,Z st -Z,temp2 adiw ZL,2 ld temp2,Z st -Z,temp2 adiw ZL,2 ld temp2,Z st -Z,temp2 adiw ZL,2 ld temp2,Z st -Z,temp2 adiw ZL,2 ld temp2,Z st -Z,temp2 adiw ZL,2 ld temp2,Z st -Z,temp2 adiw ZL,2 ld temp2,Z st -Z,temp2 adiw ZL,1 st Z,temp1 ret display_freq_buffer: ldi ZH,high(frequency) ldi ZL,low(frequency) ld temp1,Z+ rcall LCDCHR ld temp1,Z+ rcall LCDCHR cpi temp1,' ' breq dfb10 ldi temp1,',' dfb10: rcall LCDCHR ld temp1,Z+ rcall LCDCHR ld temp1,Z+ rcall LCDCHR ld temp1,Z+ rcall LCDCHR cpi temp1,' ' breq dfb20 ldi temp1,',' dfb20: rcall LCDCHR ld temp1,Z+ rcall LCDCHR ld temp1,Z+ rcall LCDCHR ld temp1,Z mov temp3,temp1 ; save last character rcall LCDCHR ret get_keypad: sbi DDRB,0 ; make PB0 an output cbi PORTB,0 ; Clear Bit in I/O Register nop ; at least one 'nop' required for keypad operation nop ldi temp1,'1' sbis PIND,6 ; Skip if Bit in I/O Register is Set rjmp grk_exit ldi temp1,'2' sbis PIND,7 ; Skip if Bit in I/O Register is Set rjmp grk_exit ldi temp1,'3' sbis PINB,4 ; Skip if Bit in I/O Register is Set rjmp grk_exit ;ldi temp1,'A' ;sbis PINB,5 ; Skip if Bit in I/O Register is Set ;rjmp grk_exit sbi PORTB,0 ; Set Bit in I/O Register cbi DDRB,0 ; make PB0 an input sbi DDRB,1 ; make PB1 an output cbi PORTB,1 ; Clear Bit in I/O Register nop ; at least one 'nop' required for keypad operation nop ldi temp1,'4' sbis PIND,6 ; Skip if Bit in I/O Register is Set rjmp grk_exit ldi temp1,'5' sbis PIND,7 ; Skip if Bit in I/O Register is Set rjmp grk_exit ldi temp1,'6' sbis PINB,4 ; Skip if Bit in I/O Register is Set rjmp grk_exit ;ldi temp1,'B' ;sbis PINB,5 ; Skip if Bit in I/O Register is Set ;rjmp grk_exit sbi PORTB,1 ; Set Bit in I/O Register cbi DDRB,1 ; make PB1 an input sbi DDRB,2 ; make PB2 an output cbi PORTB,2 ; Clear Bit in I/O Register nop ; at least one 'nop' required for keypad operation nop ldi temp1,'7' sbis PIND,6 ; Skip if Bit in I/O Register is Set rjmp grk_exit ldi temp1,'8' sbis PIND,7 ; Skip if Bit in I/O Register is Set rjmp grk_exit ldi temp1,'9' sbis PINB,4 ; Skip if Bit in I/O Register is Set rjmp grk_exit ;ldi temp1,'C' ;sbis PINB,5 ; Skip if Bit in I/O Register is Set ;rjmp grk_exit sbi PORTB,2 ; Set Bit in I/O Register cbi DDRB,2 ; make PB2 an input sbi DDRB,3 ; make PB3 an output cbi PORTB,3 ; Clear Bit in I/O Register nop ; at least one 'nop' required for keypad operation nop ldi temp1,'*' sbis PIND,6 ; Skip if Bit in I/O Register is Set rjmp grk_exit ldi temp1,'0' sbis PIND,7 ; Skip if Bit in I/O Register is Set rjmp grk_exit ldi temp1,'#' sbis PINB,4 ; Skip if Bit in I/O Register is Set rjmp grk_exit ;ldi temp1,'D' ;sbis PINB,5 ; Skip if Bit in I/O Register is Set ;rjmp grk_exit sbi PORTB,3 ; Set Bit in I/O Register cbi DDRB,3 ; make PB3 an input clr temp1 rjmp grk_exit2 grk_exit: ldi delay,250 ; wait 250 milliseconds to remove bounce rcall WAIT grk_exit2: sbi PORTB,0 ; Set Bit in I/O Register sbi PORTB,1 ; Set Bit in I/O Register sbi PORTB,2 ; Set Bit in I/O Register sbi PORTB,3 ; Set Bit in I/O Register cbi DDRB,0 ; make PB0 an input cbi DDRB,1 ; make PB1 an input cbi DDRB,2 ; make PB2 an input cbi DDRB,3 ; make PB3 an input ret DISPLAY_LINE: lpm temp1,Z+ tst temp1 breq DISPLAY_LINE_FINIS rcall LCDCHR rjmp DISPLAY_LINE DISPLAY_LINE_FINIS: ldi XH,high(cursor_number_sram) ldi XL,low(cursor_number_sram) ld temp2,X cpi temp2,4 brlo cursor9 inc temp2 cpi temp2,8 brlo cursor9 inc temp2 cursor9: ldi temp1,$8B sub temp1,temp2 mov temp2,temp1 rcall LCDCMD ret ;************************************ ;* WAIT ;* temp1 = WAIT time in milliseconds ;************************************ WAIT: tst delay brne WAIT ret ;************************************ ;* BLINK_LED ;* temp1 = number of times LED BLINKS ;************************************ BLINK_LED: tst temp1 breq BLINK_LED_EXIT BLINK_LED2: cbi PORTC,LED ;turn LED on ldi delay,250 ;250 mSec rcall WAIT sbi PORTC,LED ;turn LED off ldi delay,250 ;250 mSec rcall WAIT dec temp1 rjmp BLINK_LED BLINK_LED_EXIT: ret ;************************************ ;* LCDCMD - Send a command to the LCD ;* temp2 = cmd ;***************************************** ;* LCDCHR - Display a character on the LCD ;* temp1 = data ;************************************ LCDCMD: push temp1 mov temp1,temp2 rcall SENDBYTE cbi PORTC,LCD_DRS ;set RS low rjmp LCDEXEC LCDCHR: push temp1 rcall SENDBYTE sbi PORTC,LCD_DRS ;set RS High LCDEXEC: sbi PORTC,LCD_E ;E clocks on rising edge ldi delay,2 ;wait 2 milliseconds cbi PORTC,LCD_E ;set E low rcall WAIT pop temp1 ret ;********************************** ;* SENDBYTE clock byte into 74hc164 ;* temp1 = data ;* temp2 = bitcounter ;*********************************** SENDBYTE: push temp1 push temp2 ldi temp2,8 ;bit counter ShiftBits: cbi PORTC,LCD_DRS ;set LCD Data bit to 0 lsl temp1 ;shift bits in AReg into carry brcc ClockBit ;if zero, clock it out sbi PORTC,LCD_DRS ;if 1, set LCD Data bit to 1 ClockBit: sbi PORTC,LCD_CP ;bit clocks on rising edge cbi PORTC,LCD_CP ;bring clock back to 0 dec temp2 ;shift out 8 bits brne ShiftBits pop temp2 pop temp1 ret .if encoder_type == 2 EXT_INT0: ; logic change on INT0 (PD2, output_a) push temp1 ;save temp1 register in temp1,SREG ;save the status register push temp1 in temp1, PIND ; andi temp1, $0C breq INT0_1 ; if both bits are clear decrement encoder cpi temp1, $0C breq INT0_1 ; if both bits are set decrement encoder inc encoder ; else increment encoder rjmp INT0_EXIT INT0_1: dec encoder INT0_EXIT: pop temp1 out SREG,temp1 ;restore the status register pop temp1 ;restore temp1 register reti EXT_INT1: ; logic change on INT1 (PD3, output_b) push temp1 ;save temp1 register in temp1,SREG ;save the status register push temp1 in temp1, PIND ; andi temp1, 0b00001100 breq INT1_1 ; if both bits are clear decrement encoder cpi temp1, 0b00001100 breq INT1_1 ; if both bits are set decrement encoder dec encoder ; else increment encoder rjmp INT1_EXIT INT1_1: inc encoder INT1_EXIT: pop temp1 out SREG,temp1 ;restore the status register pop temp1 ;restore temp1 register reti .elif encoder_type == 1 EXT_INT0: reti EXT_INT1: push temp1 ;save temp1 register in temp1,SREG ;save the status register push temp1 lds temp1,EICRA cpi temp1,0b00001000 ; test falling edge breq int15 ldi temp1,0b00001000 ; set int1 on falling edge sts EICRA,temp1 sbis PIND,PHASE ; test PHASE rjmp int11 dec encoder rjmp int19 int11: inc encoder rjmp int19 int15: ldi temp1,0b00001100 ; set int1 for rising edge sts EICRA,temp1 sbis PIND,PHASE ; test PHASE rjmp int16 inc encoder rjmp int19 int16: dec encoder int19: pop temp1 out SREG,temp1 ;restore the status register pop temp1 ;restore temp1 register reti .else EXT_INT1: reti .endif ;********************************** ;* Timer 0 Overflow ;* gets here every 1 millisecond ;* decrements the DELAY counter ;*********************************** OVF0: push temp1 in temp1, SREG push temp1 ldi temp1, 256-125 ; 1 ms using default clock values out TCNT0, temp1 ; set for next overflow tst delay breq OVF0_EXIT dec delay OVF0_EXIT: pop temp1 out SREG, temp1 pop temp1 reti ;********************************** ;* SHOWHEX_LINE ;* display HEX bytes from non-program memory on line 2 ;* byte count in temp2 ;*********************************** SHOWHEX_LINE: ldi temp2,8 ;display 8 hex bytes SHOWHEX_LINE_2: ld temp1,Z+ ;get display byte ;preserves temp1 and temp2 values push temp1 push temp2 push temp1 swap temp1 andi temp1,$0F ori temp1,$30 cpi temp1,$3A brlo SHOWHEX2 ldi temp2,$07 add temp1,temp2 SHOWHEX2: rcall LCDCHR pop temp1 andi temp1,$0F ori temp1,$30 cpi temp1,$3A brlo SHOWHEX3 ldi temp2,$07 add temp1,temp2 SHOWHEX3: rcall LCDCHR pop temp2 pop temp1 dec temp2 brne SHOWHEX_LINE_2 ret EEPROM_READ: cli sbic EECR,EEPE rjmp EEPROM_READ ; Wait for completion of previous write out EEARH,YH ; Set up address register out EEARL,YL sbi EECR,EERE ; Start eeprom read by writing EERE in temp1,EEDR ; Read data from data register sei ret EEPROM_WRITE: cli sbic EECR,EEPE rjmp EEPROM_WRITE; Wait for completion of previous write ldi temp2,0 ; Set Programming mode out EECR,temp2 out EEARH,YH ; Set up address register out EEARL,YL out EEDR,temp1 ; Write data temp1 to data register sbi EECR,EEMPE ; Write logical one to EEMPE sbi EECR,EEPE ; Start eeprom write by setting EEPE sei ret ;************************************ INIT_LCD: ;* uses temp2 ;************************************ ldi delay,20 ;wait 20 milliseconds for system to stabilize rcall WAIT ldi temp2,$30 rcall LCDCMD ldi delay,4 ;wait 4 milliseconds rcall WAIT ldi temp2,$38 ;set for 8 bits, 2 lines, default font rcall LCDCMD ldi temp2,$01 ;Clear screen, CURSOR home rcall LCDCMD ldi temp2,$0E ;Display on, CURSOR on, blink off rcall LCDCMD ret process_encoder: ldi XH,high(cursor_number_sram) ldi XL,low(cursor_number_sram) sbic PIND,button ; Skip if Bit in I/O Register is Cleared (button is proessed) rjmp PE050 ld temp2,X tst encoder brpl cursor_right inc temp2 cpi temp2,9 brlo cursor_exit ldi temp2,1 rjmp cursor_exit cursor_right: dec temp2 brne cursor_exit ldi temp2,8 cursor_exit: st X,temp2 clr encoder rcall ShowFreq rjmp MENU PE050: ldi ZH,high(frequency+8) ldi ZL,low(frequency+8) ld temp1,X ; get cursor ldi temp2,8 sub temp2,temp1 PE100: sbiw ZL,1 dec temp1 brne PE100 tst encoder brpl freq_positive freq_negative: ld temp1,Z dec temp1 cpi temp1,$30 brsh SP200 ldi temp1,$39 st Z,temp1 sbiw ZL,1 rjmp freq_negative rjmp SP200 freq_positive: ld temp1,Z inc temp1 cpi temp1,$3A brlo SP200 ldi temp1,$30 st Z,temp1 sbiw ZL,1 rjmp freq_positive SP200: st Z,temp1 call ASCII8_HEX4 PE999: clr encoder jmp MENU