;------------------------------------------------- ;Program: MODkey.ASM ;Update: 29 July 2003 ;Initial: 17 October 1991 ; ;By: Dr. Marcus O. Durham, PhD, PE ; Tulsa, OK, USA ; mod@superb.org ; www.ThewayCorp.com ;Copyright (c)1991, 2003. All rights reserved ; ;Purpose: ; A set of routines are provided to perform the ; keypad input. ; ;Processor: 8031 family ;PROM: 8k (2000H) onboard ;Crystal: 11.059 MHz ;Baud: 9600 ;Assembler: Intel ASM51 ;################################################# ; ; ASSIGNMENTS ; ;################################################# ;CONSTANTS ;------------------------------------------------- ;SYMBOLS None EQU 0FFH ;blank key AdKey EQU 8001h ;mmio latch ;------------------------------------------------- ;DEFINED VARIABLES ;------------------------------------------------- ;KEYS KeyCol EQU 17H ;present column number KeyBit EQU 16H ;byte moves a bit w/ column KeyRow EQU 15H ;row number pushed KeyMul EQU 14H ;multiple key count CharK EQU 13H ;key input character CharD EQU 12H ;debounced ;CHARACTERS, HOLD, COUNT CharP EQU 0FH ;undebounced previous input CharL EQU 0EH ;character to LCD & Serial LoopC EQU 07H ;loop counter ; ;R6 EQU 06H ;size ;R5 EQU 05H ;carry in multiply, GP ;------------------------------------------------- ;BITS ASSIGNMENTS ;------------------------------------------------- ;AT RAM BYTE 20H FgKeyH BIT 00H ;flag key held down ;################################################# ; ; PROGRAM ; ;################################################# ORG 00H START: LJMP INITIAL ORG 0033h DB 25, 1,'Marcus O. Durham, PhD, PE' ;------------------------------------------------- ORG 0080H ;Addres past reserve INITIAL: ;------------------------------------------------- ;INITIALIZE MOV SP,#5Fh ;start stack @ 5f+1 LCALL UART ;config & start UART ;------------------------------------------------- MAIN: ;------------------------------------------------- ; The procedures are to input a key, send it on ; serial, and do a line return. ;PROCESS LCALL KEYS ;check keys MOV A,CharK LCALL SEROUT ;A =message value MAN9: LJMP MAIN ;Repeat ;************************************************* ; KEYPAD ;************************************************* KEYS: ;------------------------------------------------- ; Keypad is used to decode a matrix set of keys. ; Scan is a routine to check if any key is ; pressed. To do so, read the row and debounce. ; Exit with the debounced in CharD and the ; previous undebounced in CharP ; ; For a keypad, decode the row and column value. ; ; The routine waits until a key is pushed before ; returning. ;IS ANY KEY PUSHED? LCALL KEYALLRD ;all cols=0,read row LCALL DEBOUNCE ;CharD=debounced LCALL KEYPAD ;decipher key ;LAST KEY MOV A,CharK ;last key CJNE A,#None,KEYS9 ;<>none, have a key SJMP KEYS ;=none, get a key ;TERMINATE KEYS9: RET ;back to message ;------------------------------------------------- KEYPAD: ;------------------------------------------------- ; KEYPAD is a routine to input buttons pressed on ; keyboard. A 4X4 keypad can be used. ; ; Columns connect to port 2 ; Columns are accessed as an address. ; Rows connect to a memory-mapped latch. ; Row lines are connected to a pull-up to give 5V ; Output '0' to columns. ; Read rows, if any key is '0' it is pressed. ; ; A table is used to decode the value of ; each key to ASCII. ; ; If a key has not been selected, try for a ; serial input. ;ANY KEY BEEN PUSH? MOV A,CharD ;CharD debounced key CJNE A,#0Fh,KEYP3 ;row<>1, one pushed CLR FgKeyH ;fg no key held down SJMP KEYP8 ;return a null ;INITIALIZE KEYP3: JB FgKeyH,KEYP8 ;key held, exit LCALL KEYINIT ;initialize ;SEND EACH COL A 0 KEYP4: LCALL KEYROWRD ;read row CJNE A,#0Fh,KEYP5 ;0 in row pushed SJMP KEYP6 ;no 0 in this row KEYP5: LCALL KEYROWQ ;query, KeyRow=row MOV A,KeyMul ;check multiple key CJNE A,#1,KEYP8 ;<>1, so null ;COLUMN VALUE LCALL KEYCOLQ ;query, KeyCol=col ADD A,KeyRow ;A=KeyCol*4 + KeyRow MOV CharK,A ;upgrade the charac ;NEXT COLUMN KEYP6: DJNZ KeyCol,KEYP4 ;remain col to write ;CHECK RANGE ERROR MOV A,#0Fh ;largest value CLR C SUBB A,CharK ;key JC KEYP8 ;invalid key ;CONVERT TO ASCII MOV A,CharK ;lookup last value MOV DPTR,#TabKey ;start of table MOVC A,@A+DPTR ;conversion MOV CharK,A ;save key SETB FgKeyH ;flag key held down SJMP KEYP9 ;exit ;NULL RESPONSE KEYP8: MOV CharK,#None ;nothing pushed ;SO CHECK SERIAL JNB RI,KEYP9 ;no serial either CLR RI ;receive interrupt MOV CharK,SBUF ;serial input ;TERMINATE KEYP9: RET ;back to message ;------------------------------------------------- KEYINIT: ;------------------------------------------------- ; Initialize is a routine to set variables. ; A 4X4 keypad can be used with a single byte. ; ; KeyCol present column number ; KeyMul multiple key count ; KeyRow row number pushed ; KeyBit byte moves a 0 bit for the column move ;ANY KEY BEEN PUSH? MOV KeyCol,#3 ;column number 0 MOV KeyMul,#0 ;multiple key count MOV KeyRow,#0 ;row number 0 MOV KeyBit,#11110111b;first column w/0 ;TERMINATE RET ;back home ;------------------------------------------------- KEYALLRD: ;------------------------------------------------- ; Row Read is a routine that reads a byte ; corresponding to all the rows. Because of the ; structure, it sends 0 to all columns. A 1 is in ; the place of each row. ; The routine can be used to see if any ; key has been pushed. ; MOV A,#0 ;all columns ;COLUMN OUT MOV DPTR,#AdKey ;all col=0 MOVX @DPTR,A ;key latch MOV A,Pio ;input rows ANL A,#0Fh ;mask hi nibble ;TERMINATE RET ;back to message ;------------------------------------------------- KEYROWRD: ;------------------------------------------------- ; The routine successively sends a 0 to each col. ; Simultaneously the row is read ;BIT TO SEND MOV A,KeyBit ;0 bit is column ;SAVE FOR NEXT BIT RR A MOV KeyBit,A ;keep it RL A ;use it ;INPUT ROW MOVX @DPTR,A ;read row MOV A,Pio ;get row ANL A,#0Fh ;mask hi nibble ;TERMINATE RET ;back to message ;------------------------------------------------- KEYROWQ: ;------------------------------------------------- ; Row Calculate determines the row number that is ; pressed. RowNum = 0,1,2,3 ; ; A counter is set if multiple rows are pushed. ; ; The routine can handle 4 rows. ; If fewer rows are used, simply change the jump ; to the corresponding number of rows. ; If a 1 row pad is used, SJMP to ROW1. ;INITIALIZE CLR C ;initialize test bit ;; SJMP KEYR3 ;pad has only 3 rows ;IS THIS ROW=0 KEYR4: RRC A ;row bit to C JC KEYR3 ;C=1,row not down INC KeyMul ;multiple key count MOV KeyRow,#3 ;row number ;IS THIS ROW=0 KEYR3: RRC A ;row bit to C JC KEYR2 ;C=1,row not down INC KeyMul ;multiple key count MOV KeyRow,#2 ;row number ;IS THIS ROW=0 KEYR2: RRC A ;row bit to C JC KEYR1 ;C=1,row not down INC KeyMul ;multiple key count MOV KeyRow,#1 ;row number ;IS THIS ROW=0 KEYR1: RRC A ;row bit to C JC KEYR9 ;C=1,row not down INC KeyMul ;multiple key count MOV KeyRow,#0 ;row number SJMP KEYR9 ;TERMINATE KEYR9: RET ;back to message ;------------------------------------------------- KEYCOLQ: ;------------------------------------------------- ; Column calculate determines the column that is ; pressed, KeyCol. Then it calculates the value ; for the key. ; ; Rows are numbered 0,1,2,3 ; Columns are numbered 0,1,2,3 ; Columns are valued 0,4,8,12. ; Columns value = column number * number of rows ; With four rows A = KeyCol * 4 ;CALCULATE MOV A,KeyCol ;column w/ 0 DEC A ;column # inc by 1 MOV B,#4 ;qty of rows MUL AB ;A = column value ;TERMINATE RET ;back to message ;+++++++++++++++++++++++++++++++++++++++++++++++++ ;TABLE SETUP - KEYPAD CONVERSION ;------------------------------------------------- ; Tables are used to convert between formats. ; These include keypad & ASCII. ; The table pointer will show a decimal result ; that corresponds to a column/row location. ; ; Row0=Data line 0, Row4=Data line 3. ; Col0=Data line 8. Col4=Data line 4. ;------------------------------------------------- TabKey: ;------------------------------------------------- ; Three column keyboard DB 33H ;0/0-3 DB 36H ;0/1-6 DB 39H ;0/2-9 DB 23H ;0/3-# DB 32H ;1/0-2 DB 35H ;1/1-5 DB 38H ;1/2-8 DB 30H ;1/3-0 DB 31H ;2/0-1 DB 34H ;2/1-4 DB 37H ;2/2-7 DB 2AH ;2/3-* ;************************************************* END ;Program end An alternative approach is to write the columns out as memory mapped io and read the rows on a port. This only requires minor changes to the read procedures. ;------------------------------------------------- KEYALLRD: ;------------------------------------------------- ; Row Read is a routine that reads a byte ; corresponding to all the rows. Because of the ; structure, it sends 0 to all columns. A 1 is in ; the place of each row. ; The routine can be used to see if any ; key has been pushed. ; ;COLUMN OUT MOV DPTR,#AdKey ;all col=0 MOVX A,@DPTR ;key latch ANL A,#0Fh ;mask hi nibble ;TERMINATE RET ;back to message ;------------------------------------------------- KEYROWRD: ;------------------------------------------------- ; The routine successively sends a 0 to each col. ; Simultaneously the row is read ;BIT TO SEND MOV A,KeyBit ;0 bit is column MOV DPH,A ;address of column MOV DPL,#1 ;key input ;SAVE FOR NEXT BIT RR A MOV KeyBit,A ;keep it ;INPUT ROW MOVX A,@DPTR ;read row ANL A,#0Fh ;mask hi nibble ;TERMINATE RET ;back to message