Keypad Module

This module is responsible for detecting and reporting valid keypresses. The interrupt does most of the hard stuff and all the program needs to do is to call KeyGet when it needs to know what key was pressed, if any.

The keys are detected in KeyChk, by scanning each row individually via KeyRow. This tallies up the number of detected keys, and if exactly one was pressed, the scan code of that key is returned. If none, or more than one, is pressed then the routine indicates that nothing has been pressed. The interrupt continually checks for keys every milisecond, and if one is held down for longer than 10ms then it is saved in the buffer upon being released.

Download:
; ///////////////////////////////////////////////////////////// ; // Keypad Module II ; // (c) 1999 Geoff Knagge, Andrew Carr, Mark Lynn ; // last modified : 22/10/1999 ; // ; // Assumes Key I/O port has been previously initialised for ; // output on bits 0-3, and input on bits 4-7. Only ; // KeyInterrupt and KeyGet should be called from outside this ; // module. ; // ; // KeyInterrupt should be called regularly (e.g. every 1 ms) ; // ; // Valid keypresses result in a scan code being copied to ; // KeyStore. KeyGet returns the code in A and clears KeyStore ; ///////////////////////////////////////////////////////////// ; Scan codes are: 00 = "1" 04 = "2" 08 = "3" ; 01 = "4" 05 = "5" 09 = "6" ; 02 = "7" 06 = "8" 0A = "9" ; 03 = "*" 07 = "0" 0B = "#" ; // Data lastkey: .byte KS_none timeDown: .byte 0 KSetWhenReleased: .byte 0 KeyStore: .byte KS_none ; // Hardware Addresses used... KeyPort = 42 ; port 2C ; // Constants KeyDebounce = 0A ; milliseconds ; //Scan Code Constants : KS_Invalid = 0FF KS_None = 0FF KS_1 = 00 KS_2 = 04 KS_3 = 08 KS_4 = 01 KS_5 = 05 KS_6 = 09 KS_7 = 02 KS_8 = 06 KS_9 = 0A KS_0 = 07 KS_Star = 03 KS_Hash = 0B KDelay: push AF mvi A,20 KDRL: dcr A cpi 0 jnz KDRL pop AF ret ;////////////////////////////////////// KeyRow: ; reads the current row. ; in: A =output data, b = count, ; c = base scan code, e = old scan code ; out : b = new count, e = scan code out keyport call KDelay in keyport ; read the column bits ani 70 ; mask off column bits cpi 0 jz kr4 cpi 10 ; check column 1 jnz kr2 inr b ; col 1 pressed mov e,c ; e = scan code jmp kr4 kr2: inr c inr c inr c inr c cpi 20 jnz kr3 inr b ; col 2 pressed mov e,c jmp kr4 kr3: inr c ; check if col 3 pressed inr c inr c inr c cpi 40 ; test that col 3 only is down jnz kr5 ; if not, error inr b ; otherwise increase counter mov e,c ; save the scan code jmp kr4 ; then exit kr5: inr b ; more than one pressed inr b ; so increase counter past invalid count kr4: ret KeyChk: ; output: A=scan code push hl push de push bc mvi B,0 ; B = counter of keys mvi c,0 mvi a,11111110# ; row 1 call keyrow mvi c,1 mvi a,11111101# ; row 2 call keyrow mvi c,2 mvi a,11111011# ; row 3 call keyrow mvi c,3 mvi a,11110111# ; row 4 call keyrow mov a,b cpi 1 ; was one key only pressed? jz kc2 ; yes, no error cpi 0 jz kc3 mvi e,ks_invalid jmp kc2 kc3: mvi e,ks_none kc2: mov a,e pop bc pop de pop hl ret ;///////////////////////////////////// ;//////////////////// Key Handler... returns nothing, but destroys ;//////////////////// the contents of the A, H and L registers. KeyInterrupt: lhld times2 inx hl shld times2 lxi hl,timedown mov a,m inr a mov m,a call KeyChk ; get the key scan code in A lxi hl,lastkey ; point hl to the last scan code read cpi KS_None ; was any key pressed this time? jz KI_nokey cpi KS_invalid ; was a valid key pressed? jnz KI_valid ; mov m,A ; store the invalid code in lastkey jmp KI_end KI_valid: cmp m ; is this key the same as last check? jnz KI_newkey ; no, go somewhere else... lxi hl,timeDown mov a,m cpi KeyDebounce ; has it been down long enough? jnz KI_end ; no, nothing more to do mvi a,1 ; yes, set the SetWhenReleased flag lxi hl,KsetWhenReleased mov m,A jmp KI_end ; nothing more to do KI_newkey: ; a new key press has occurred mov m,A ; store that code in lastkey xra a ; A = 0 lxi hl,KsetWhenReleased; clear setWhenreleased (though it ; should be clear anyway... best to be safe) mov m,A; lxi hl,timeDown ; set timeDown to zero mov m,A lxi hl,0 shld times2 jmp KI_end ; nothing more to do KI_nokey: ; no key is pressed xra A ; A = 0 lxi hl,0 shld times2 lxi hl,timeDown mov m,a ; reset time down counter lxi hl,KsetWhenReleased cmp m ; check SetWhenReleased flag jz KI_nopress ; if clear, no valid key press detected mov m,A ; otherwise, clear the flag lxi hl,lastkey mov a,m ; get the scan code lxi hl,KeyStore mov m,a ; and store it in the buffer KI_nopress: mvi a,KS_None ; set lastkey to none lxi hl,lastkey mov m,a; KI_end: ret ;/////////////////////// KeyGet: push bc push hl lxi hl, keystore mov a,m ; retrieve the scan code, if any mvi c,KS_None mov m,c ; clear the key from memory pop hl pop bc ret

This is page designed, maintained and
(C)opyright 1999 by Geoff Knagge