; Key scan Virtual Periperal ; device pins28,pages4,banks8,turbo,oschs,stackx,optionx ; use oschs only for debugging ; set to 4MHz internal RC for actual operation org 8 key_val ds 1 ; contains the key value in 2's complement ; this is for ease of display routine only ; to get real value, please remove the ~ signs in ; the virtual matrix scanb ds 1 ; scan mask, the column to scan will have a zero scan_result ds 1 ; result of scanning cnt1 ds 1 ; column count (3 2 1 0, 3 being leftmost) cnt2 ds 1 ; row count (3 2 1 0, 3 being the top row) ; virtual matrix index is computed as 4*cnt2+cnt1 key_state ds 1 ; store the states of the keyboard scan debounce_cnt ds 1 ; debouncing count temp equ cnt1 ; store the key scanned until key is released ; key scan states fast_scan equ 7 ; scan all columns at once debounce equ 6 ; debounce state detailed_scan equ 5 ; scan a column at a time release equ 4 ; wait until key is released reset start ; goto 'start' on reset org 0 ; interrupt routine sb key_state.fast_scan ; current state=fast scan? jmp chk_debounce ; no, check if debounce state ;do fast scan mov rb,#%11110000 ; set all scan lines to low mov scan_result,rb ; store result and scan_result,#%11110000 ; mask all output lines csne scan_result,#%11110000 ; to examine only inputs jmp key_done ; no key pressed if results is 11110000 ; key pressed, go to debounce state clrb key_state.fast_scan ; clear current state setb key_state.debounce ; next state= debounce mov debounce_cnt,#20 ; 20 ms debouncing time jmp key_done ; change state on next interrupt chk_debounce sb key_state.debounce ; current state=debouncing? jmp chk_rescan ; no, check if detailed scan ;do debounce decsz debounce_cnt ; count down jmp key_done ; and continue on next interrupt if not done ; 20 ms elapsed clrb key_state.debounce ; clear current state setb key_state.detailed_scan ; next state=detailed scan jmp key_done ; state transition on next interrupt chk_rescan sb key_state.detailed_scan ; current state=detailed scan? jmp chk_release ; no, check if it is key release check mov cnt1,#3 ; leftmost column=3 ;detailed scan mov scanb,#%11110111 ; scan leftmost column first detail_scan mov rb,scanb ; send scan mask out mov scan_result,rb ; store result and scan_result,#%11110000 ; examine only inputs cse scan_result,#%11110000 ; any key? jmp encode ; yes, encode it dec cnt1 ; scan next column stc ; maintain the 1's rr scanb ; scan next column by moving the 0 to the right snc ; no carry means last column has been scanned jmp detail_scan ; still more to scan ; no key detected after scanning all columns, may be just noise on port clrb key_state.detailed_scan ; clear current state setb key_state.fast_scan ; return to fast scan jmp key_done ; on next interrupt encode mov cnt2,#0 ; find out on which row the key is pressed stc ; we are looking for a zero so set carry to 1 first cont_enc rl scan_result ; put the scan result in carry bit sc ; skip if zero is not there jmp lookup ; zero found, look up for value inc cnt2 ; increment the row number jmp cont_enc ; and continue ;virtual matrix offset=4 cnt2+cnt1 lookup clc ; clear carry to prepare for multiplication rl cnt2 ; multiply by 2 rl cnt2 ; multiply by 4 and add cnt2,cnt1 ; +cnt1 mov w,#virtual_matrix ; start of table add w,cnt2 ; index into table mov m,#0 ; prepare for iread which load the value at m:w iread ; read the value into m:w mov temp,w ; store mov m,#$f ; restore m to eliminate side effects clrb key_state.detailed_scan ; clear current state setb key_state.release ; next state=check key release jmp key_done ; on next interrupt virtual_matrix dw ~$f dw ~0ドル dw ~$f dw ~$f dw ~9 dw ~8 dw ~7 dw ~$f dw ~6 dw ~5 dw ~4 dw ~$f dw ~3 dw ~2 dw ~1 dw ~$f chk_release sb key_state.release ; check key release state? jmp key_done ; no mov rb,scanb ; use last scanned column mask mov scan_result,rb ; get key and scan_result,#%11110000 ; mask outputs cse scan_result,#%11110000 ; equ to $F0 if no key pressed anymore jmp key_done ; key still pressed ; key released mov key_val,temp ; store final value clrb key_state.release ; state transition setb key_state.fast_scan ; next state is scan again key_done mov w,#-250 ; 1 ms per interrupt at 4MHz, prescaler is /8 retiw ; return from interrupt now start ;initialize port B mov m,#0ドルf ; Points mode register to set data direction mov !rb,#%11110000 ; RB0-3 will be outputs, and RB4-7 will be inputs ;set inputs with weak pull ups mov m,#0ドルe ; points mode register to pull-up enable mov !rb,#%00001111 ; Enable pull-ups on Port B inputs mov m,#0ドルc ; set Schmitt-trigger to increase noise immunity mov !rb,#%00001111 ; on RB4-7 mov m,#$F ; restore mode register mov !option,#%10000010 ; RTCC divide rate=8 setb key_state.fast_scan ; initial state is fast scan mov key_val,#0 ; no key pressed initially loop mov rb,key_val ; put key pressed on LEDs jmp loop ; loop forever
.