;***************************************************************************************** ; Mega 128 Scope Controller Program ; (c) Martin Cibulski ;**************************************************************************************** .EQU LCD_PAUSE_LONG = 127 .EQU LCD_PAUSE_SHORT = 31 ;***************************************************************************************** ;HD44780 display commands ;***************************************************************************************** ;constants for handbox control .equ LCD_MODE_MENU = 1 .equ LCD_MODE_MOVE = 0 .equ LCD_KEYENTRY_SIZE = 4 .equ LCD_REPEAT_SHORT = 18 .equ LCD_REPEAT_ACCEL = 65 .equ LCD_REPEAT_START = 100 ;***************************************************************************************** .DSEG lcd_line_1: .byte LCD_LENGTH ;buffer for upper display line lcd_index_1: .byte 1 lcd_line_2: .byte LCD_LENGTH ;buffer for lower display line lcd_index_2: .byte 1 lcd_mode: .byte 1 ;LCD_MODE_MOVE or LCD_MODE_MENU lcd_block_moves: .byte 1 ;blocks move keys after menu command lcd_speed: .byte 1 ;1-5 lcd_lkey_menu: .byte 1 ;previous status of UP/DOWN/RIGHT/LEFT keys lcd_lkey_sp: .byte 1 ; FAST/SLOW keys lcd_lkey_mode: .byte 1 ; MENU/MOVE keys lcd_pause: .byte 1 ;timer for messages (1 sec) lcd_rep_del: .byte 1 lcd_rep_acc: .byte 1 ;***************************************************************************************** .CSEG lcd_label_tab: .dw lcd_irq_active .db L_BRAM ,"LCDIRQACT " .dw 0 .db L_END , 0 ;***************************************************************************************** lcd_init: ldi r16 ,LCD_LENGTH sts lcd_index_1 ,r16 sts lcd_index_2 ,r16 ldi r16 ,LCD_MODE_MOVE sts lcd_mode ,r16 clr r16 sts lcd_block_moves ,r16 ldi r16 ,1 sts lcd_speed ,r16 ldi r16 ,0b11111111 sts lcd_lkey_mode ,r16 sts lcd_lkey_menu ,r16 sts lcd_lkey_sp ,r16 clr r16 sts lcd_sim_index ,r16 ret ;***************************************************************************************** .DSEG lcd_sim_index: .byte 1 .CSEG lcd_sim_key_list: .db LCD_KEY_DOWN ,0 .db 0xFF ,0 .db LCD_KEY_DOWN ,0 .db 0xFF ,0 .db LCD_KEY_DOWN ,0 .db 0xFF ,0 .db LCD_KEY_DOWN ,0 .db 0xFF ,0 .db 0x00 ,0 lcd_sim_key: ldi zl ,low(lcd_sim_key_list<<1) ldi zh ,high(lcd_sim_key_list<<1) lds r16 ,lcd_sim_index mov r17 ,r16 inc r16 sts lcd_sim_index ,r16 lsl r17 add zl ,r17 clr r17 adc zh ,r17 lpm r17 ,Z+ sts hbx_keys ,r17 lpm r17 ,Z+ lpm r17 ,Z ldi r16 ,0x00 cpse r16 ,r17 ret lds r16 ,lcd_sim_index dec r16 sts lcd_sim_index ,r16 ret ;***************************************************************************************** .DSEG lcd_irq_active: .byte 1 .CSEG lcd_irq: lds r0 ,lcd_irq_active ;IRQ handler on ? sbrs r0 ,0 ;YES if 1 ret ;NO, return from interrupt #ifdef SIMULATE ;rcall lcd_sim_key ldi r16 ,LCD_KEY_RIGHT sts hbx_keys ,r16 #else call hbx_read_keys #endif lds r16 ,hbx_keys cpi r16 ,LCD_KEY_LEFT & LCD_KEY_RIGHT & LCD_KEY_UP & LCD_KEY_DOWN brne lcd_irq_00 ldi xh ,high(hbx_init) ldi xl ,low(hbx_init) call mnu_slowfunc_set lcd_irq_00: lds r16 ,lcd_pause ;temporary message active ? tst r16 breq lcd_irq_no_show ;no dec r16 ;timer-- sts lcd_pause ,r16 ;save timer brne lcd_irq_no_show ;still not zero call mnu_show ;if zero, show menu/position again clr r16 sts cor_new_position ,r16 lcd_irq_no_show: lds r16 ,lcd_index_1 ;cursor 1 cpi r16 ,LCD_LENGTH ;output completed ? breq lcd_irq_line_2 ;yes, check line 2 cpi r16 ,0xFF brne lcd_irq_write_1 ldi r16 ,LCD_HOME call hbx_write_command ldi r16 ,0 sts lcd_index_1 ,r16 rjmp lcd_read_keys lcd_irq_write_1: inc r16 ;print character in LCD line 1 sts lcd_index_1 ,r16 ldi xl ,low(lcd_line_1 - 1) ldi xh ,high(lcd_line_1 - 1) add xl ,r16 clr r16 adc xh ,r16 ld r16 ,X call hbx_write_data rjmp lcd_read_keys lcd_irq_line_2: lds r16 ,lcd_index_2 ;cursor 2 cpi r16 ,LCD_LENGTH ;output completed ? breq lcd_irq_check_new_pos ;yes, display new position cpi r16 ,0xFF ;just initial brne lcd_irq_write_2 ldi r16 ,LCD_HOME2 call hbx_write_command ldi r16 ,0 sts lcd_index_2 ,r16 rjmp lcd_read_keys lcd_irq_write_2: inc r16 ;print character in LCD line 2 sts lcd_index_2 ,r16 ldi xl ,low(lcd_line_2 - 1) ldi xh ,high(lcd_line_2 - 1) add xl ,r16 clr r16 adc xh ,r16 ld r16 ,X call hbx_write_data lcd_irq_check_new_pos: lds r16 ,lcd_pause ;temporary message active ? tst r16 brne lcd_read_keys ;yes lds r16 ,lcd_mode ;MOVE mode ? cpi r16 ,LCD_MODE_MOVE brne lcd_read_keys ;no lds r16 ,cor_new_position ;new position to display ? tst r16 breq lcd_read_keys ;no call mnu_show ;show new position clr r16 sts cor_new_position ,r16 ldi r16 ,LCD_PAUSE_SHORT sts lcd_pause ,r16 lcd_read_keys: lds r17 ,lcd_mode cpi r17 ,LCD_MODE_MENU brne lcd_read_keys_nomenu ldi yl ,low(mot_a) ;Motor A ldi yh ,high(mot_a) call mot_speed_null ldi yl ,low(mot_b) ;Motor B ldi yh ,high(mot_b) call mot_speed_null lds r16 ,hbx_keys ori r16 ,LCD_KEY_UP & LCD_KEY_DOWN & LCD_KEY_RIGHT & LCD_KEY_LEFT lds r19 ,lcd_lkey_menu set rcall lcd_key_handler sts lcd_lkey_menu ,r19 rjmp lcd_read_keys_no_move lcd_read_keys_nomenu: lds r17 ,lcd_mode cpi r17 ,LCD_MODE_MOVE brne lcd_read_keys_no_move ;rjmp lcd_read_keys_directions lds r16 ,lcd_block_moves ;just switched to move mode ? tst r16 breq lcd_read_keys_directions ;no, direction keys allowed lds r16 ,hbx_keys ;all direction keys released ? ori r16 ,LCD_KEY_UP & LCD_KEY_DOWN & LCD_KEY_LEFT & LCD_KEY_RIGHT cpi r16 ,0xFF breq lcd_read_keys_allow_dir_keys ;yes, allow direction keys lds r16 ,hbx_keys ;all direction keys released ? ori r16 ,0xFF - (LCD_KEY_UP & LCD_KEY_DOWN & LCD_KEY_LEFT & LCD_KEY_RIGHT) sts hbx_keys ,r16 rjmp lcd_read_keys_directions lcd_read_keys_allow_dir_keys: clr r16 ;allow direction keys sts lcd_block_moves ,r16 lcd_read_keys_directions: ldi yl ,low(mot_b) ;Motor B ldi yh ,high(mot_b) lds r16 ,hbx_keys ori r16 ,LCD_KEY_UP & LCD_KEY_DOWN cpi r16 ,LCD_KEY_UP brne lcd_read_keys_no_up rcall lcd_move_plus rjmp lcd_read_keys_leftright lcd_read_keys_no_up: cpi r16 ,LCD_KEY_DOWN brne lcd_read_keys_no_down rcall lcd_move_minus rjmp lcd_read_keys_leftright lcd_read_keys_no_down: call mot_speed_null lcd_read_keys_leftright: ldi yl ,low(mot_a) ;Motor A ldi yh ,high(mot_a) lds r16 ,hbx_keys ori r16 ,LCD_KEY_LEFT & LCD_KEY_RIGHT cpi r16 ,LCD_KEY_LEFT brne lcd_read_keys_no_left rcall lcd_move_plus rjmp lcd_read_keys_no_move lcd_read_keys_no_left: cpi r16 ,LCD_KEY_RIGHT brne lcd_read_keys_no_right rcall lcd_move_minus rjmp lcd_read_keys_no_move lcd_read_keys_no_right: call mot_speed_null lcd_read_keys_no_move: lds r16 ,hbx_keys ori r16 ,LCD_KEY_MENU & LCD_KEY_MOVE lds r19 ,lcd_lkey_mode clt rcall lcd_key_handler sts lcd_lkey_mode ,r19 lds r16 ,hbx_keys ori r16 ,LCD_KEY_PLUS & LCD_KEY_MINUS lds r19 ,lcd_lkey_sp clt rcall lcd_key_handler sts lcd_lkey_sp ,r19 ret ;***************************************************************************************** lcd_move_plus: lds r16 ,lcd_speed cpi r16 ,5 brne lcd_move_plus_no5 jmp mot_speed_plus5 lcd_move_plus_no5: cpi r16 ,4 brne lcd_move_plus_no4 jmp mot_speed_plus4 lcd_move_plus_no4: cpi r16 ,3 brne lcd_move_plus_no3 jmp mot_speed_plus3 lcd_move_plus_no3: cpi r16 ,2 brne lcd_move_plus_no2 jmp mot_speed_plus2 lcd_move_plus_no2: jmp mot_speed_plus1 ;***************************************************************************************** lcd_move_minus: lds r16 ,lcd_speed cpi r16 ,5 brne lcd_move_minus_no5 jmp mot_speed_minus5 lcd_move_minus_no5: cpi r16 ,4 brne lcd_move_minus_no4 jmp mot_speed_minus4 lcd_move_minus_no4: cpi r16 ,3 brne lcd_move_minus_no3 jmp mot_speed_minus3 lcd_move_minus_no3: cpi r16 ,2 brne lcd_move_minus_no2 jmp mot_speed_minus2 lcd_move_minus_no2: jmp mot_speed_minus1 ;***************************************************************************************** ;r16 pressed key ;r19 last key ;T flag 1=autorepeat allowed lcd_key_handler: cp r16 ,r19 ;same key pressed breq lcd_key_handler_00 ;yes, check if autorepeat allowed ldi r19 ,LCD_REPEAT_START ;new key pressed sts lcd_rep_del ,r19 ;set autorepeat delay lsl r19 sts lcd_rep_acc ,r19 ;set repeat acceleration delay clr r19 sts mnu_index_step+1 ,r19 ;set autorepeat step = 1 ldi r19 ,1 sts mnu_index_step ,r19 rjmp lcd_key_handler_02 ;execute menu function lcd_key_handler_00: brtc lcd_key_handler_norepeat ;no autorepeat allowed ;*********************************************************************** ;autorepeat with acceleration lds r16 ,lcd_rep_acc ;decrement acceleration delay dec r16 sts lcd_rep_acc ,r16 brne lcd_khd_no_accel ;not zero, don't accelerate lds zl ,mnu_child ;get maximum stepsize from menu function lds zh ,mnu_child+1 adiw zh:zl ,MNU_ADRESS lpm r0 ,Z+ lpm r1 ,Z+ mov r16 ,r0 or r16 ,r1 breq lcd_khd_no_accel ;no function adress, no acceleration mov zl ,r0 ;otherwise call function mov zh ,r1 adiw zh:zl ,MNU_CALL_FASTSTEP ;offset in menu item's jump table clt icall ;call into menu item's jump table brtc lcd_khd_no_accel ;no info, don't accelerate lds r0 ,mnu_index_step ;stepsize = stepsize * 1.5 lds r1 ,mnu_index_step+1 push r2 push r3 movw r3:r2 ,r1:r0 lsl r0 ;stepsize * 2 rol r1 asr r3 ;stepsize * 0.5 ror r2 sub r0 ,r2 ;stepsize * 2 - stepzize * 0.5 sbc r1 ,r3 pop r3 pop r2 sts mnu_index_step ,r0 sts mnu_index_step+1 ,r1 cp r16 ,r0 ;stepsize too big ? cpc r17 ,r1 brcc lcd_khd_01 ;no sts mnu_index_step ,r16 ;stepsize = max_stepsize sts mnu_index_step+1 ,r17 lcd_khd_01: ldi r16 ,LCD_REPEAT_ACCEL ;start delay for next acceleration sts lcd_rep_acc ,r16 lcd_khd_no_accel: lds r16 ,lcd_rep_del dec r16 sts lcd_rep_del ,r16 brpl lcd_key_handler_norepeat ldi r16 ,LCD_REPEAT_SHORT sts lcd_rep_del ,r16 mov r16 ,r19 rjmp lcd_key_handler_02 lcd_key_handler_norepeat: mov r16 ,r19 ret ;*********************************************************************** lcd_key_handler_02: ldi yl ,low(lcd_keys_table<<1) ldi yh ,high(lcd_keys_table<<1) lds r17 ,lcd_mode ldi r18 ,12 lcd_key_handler_loop: mov zl ,yl mov zh ,yh lpm r19 ,Z+ cp r19 ,r17 brne lcd_key_handler_next lpm r20 ,Z+ cp r20 ,r16 brne lcd_key_handler_next lpm yl ,Z+ lpm yh ,Z+ mov r18 ,yl or r18 ,yh breq lcd_key_handler_end mov zl ,yl mov zh ,yh push r16 icall pop r19 ret lcd_key_handler_next: adiw yh:yl ,LCD_KEYENTRY_SIZE dec r18 brne lcd_key_handler_loop lcd_key_handler_end: ldi r19 ,0xFF ret lcd_keys_table: .db LCD_MODE_MOVE, LCD_KEY_MENU .dw lcd_modemenu .db LCD_MODE_MOVE, LCD_KEY_MOVE .dw lcd_modemove .db LCD_MODE_MOVE, LCD_KEY_PLUS .dw lcd_speed_fast .db LCD_MODE_MOVE, LCD_KEY_MINUS .dw lcd_speed_slow .db LCD_MODE_MENU, LCD_KEY_LEFT .dw mnu_prev .db LCD_MODE_MENU, LCD_KEY_RIGHT .dw mnu_next .db LCD_MODE_MENU, LCD_KEY_UP .dw mnu_out .db LCD_MODE_MENU, LCD_KEY_DOWN .dw mnu_in .db LCD_MODE_MENU, LCD_KEY_MENU .dw lcd_modemenu .db LCD_MODE_MENU, LCD_KEY_MOVE .dw lcd_modemove .db LCD_MODE_MENU, LCD_KEY_PLUS .dw lcd_speed_fast .db LCD_MODE_MENU, LCD_KEY_MINUS .dw lcd_speed_slow ;***************************************************************************************** lcd_modemenu: lds r16 ,lcd_mode cpi r16 ,LCD_MODE_MENU brne lcd_modemenu_01 ret lcd_modemenu_01: ;rcall mnu_out ldi r16 ,LCD_MODE_MENU sts lcd_mode ,r16 ldi yl ,low(mot_a) ;Motor A ldi yh ,high(mot_a) call mot_speed_null ldi yl ,low(mot_b) ;Motor B ldi yh ,high(mot_b) call mot_speed_null jmp mnu_show ;***************************************************************************************** lcd_modemove: push r16 ldi r16 ,LCD_MODE_MOVE sts lcd_mode ,r16 ldi r16 ,1 sts lcd_block_moves ,r16 pop r16 jmp mnu_show ;***************************************************************************************** lcd_speed_fast: lds r16 ,lcd_speed cpi r16 ,5 breq lcd_speed_print inc r16 sts lcd_speed ,r16 rjmp lcd_speed_print lcd_speed_slow: lds r16 ,lcd_speed cpi r16 ,1 breq lcd_speed_print dec r16 sts lcd_speed ,r16 lcd_speed_print: ldi zl ,low(lcd_speed_msg<<1) ldi zh ,high(lcd_speed_msg<<1) lds r16 ,lcd_speed ;1-5 dec r16 ;0-4 lsl r16 lsl r16 lsl r16 lsl r16 ;*16 add zl ,r16 clr r16 adc zh ,r16 rjmp lcd_print_alarm lcd_speed_msg: .db "SPEED 1", "--------" .db "SPEED 2", "--------" .db "SPEED 3", "--------" .db "SPEED 4", "--------" .db "SPEED 5", "--------" ;***************************************************************************************** ;Print alarm message ; ;zh:zl Word adress of message in program memory (8 words = 16 characters) ;***************************************************************************************** lcd_print_alarm: push r16 push zl push zh rcall lcd_print_z1 rcall lcd_print_z2 ldi r16 ,LCD_PAUSE_LONG sts lcd_pause ,r16 pop zh pop zl pop r16 ret ;***************************************************************************************** lcd_print_z1: push r16 ldi xl ,low(lcd_line_1) ldi xh ,high(lcd_line_1) ldi r16 ,7 lcd_print_z1_loop: lpm r0 ,Z+ st X+ ,r0 dec r16 brpl lcd_print_z1_loop sts lcd_index_1 ,r16 pop r16 ret lcd_print_z2: push r16 push xl push xh ldi xl ,low(lcd_line_2) ldi xh ,high(lcd_line_2) ldi r16 ,7 lcd_print_z2_loop: lpm r0 ,Z+ st X+ ,r0 dec r16 brpl lcd_print_z2_loop sts lcd_index_2 ,r16 pop xh pop xl pop r16 ret ;***************************************************************************************** lcd_print_x1: push r16 push zl push zh ldi zl ,low(lcd_line_1) ldi zh ,high(lcd_line_1) ldi r16 ,7 lcd_print_x1_loop: ld r0 ,X+ st Z+ ,r0 dec r16 brpl lcd_print_x1_loop sts lcd_index_1 ,r16 pop zh pop zl pop r16 ret lcd_print_x2: push r16 push zl push zh ldi zl ,low(lcd_line_2) ldi zh ,high(lcd_line_2) ldi r16 ,7 lcd_print_x2_loop: ld r0 ,X+ st Z+ ,r0 dec r16 brpl lcd_print_x2_loop sts lcd_index_2 ,r16 pop zh pop zl pop r16 ret ;*****************************************************************************************