ARC - Arbitrary Row and Column keyboard scanner
Peter Jakacki
Posts: 10,193
Here is a keyboard scanner that is not limited by the number or positions of the rows and columns in a keyboard matrix. Essentially you can take a bunch of unused pins from your Prop, even though they may be scattered here and there, and use these to scan a keyboard/keypad. My original implementation had all the rows and columns neatly together but the keypad didn't match up. So this code will handle those different keypads and/or allow you to use any combination of port pins for your matrix.
This code is not fully tested although it seems to work fine. I polled this every 1ms and also every 10ms and keys were captured just as well in the latter. Also, this code is part of a combination SmartSerialLCD object I am preparing for possible release. Contrary to the name it doesn't have to be serial but accessed as if it were serial rather than having many call methods so therefore it can easily be tethered over a serial link.
The hardware it is being developed for is the MultiLCD which backpacks onto a 20x4 character or 128x64 graphic LCD. Besides LCD and keyboard interfaces it includes an SD card, raw piezo transducer, and options for RS485, audio out, USB/PS2 keypad etc.
This code is not fully tested although it seems to work fine. I polled this every 1ms and also every 10ms and keys were captured just as well in the latter. Also, this code is part of a combination SmartSerialLCD object I am preparing for possible release. Contrary to the name it doesn't have to be serial but accessed as if it were serial rather than having many call methods so therefore it can easily be tethered over a serial link.
The hardware it is being developed for is the MultiLCD which backpacks onto a 20x4 character or 128x64 graphic LCD. Besides LCD and keyboard interfaces it includes an SD card, raw piezo transducer, and options for RS485, audio out, USB/PS2 keypad etc.
'************************************************************************* ' ' ARC KEYBOARD SCANNER V1.0 ' October 2011 Peter Jakacki ' ' ARBITRARY ROW & COLUMN KEYBOARD SCANNER ' Any combination of row and column pins can be used ' Port pins that are non-sequential can therefore be used ' Also a change of keypad which has different row and column conections ' can easily be accommodated ' ' Hardware requirments are that each port pin has a current limit resistor (1K) along ' with a corresponding pullup at least 5 times the value of the CLR ' ' VDD---10K---| ' port pin)------1K----|--COLUMN or ROW ' '************************************************************************* var long rowmask,colmask,lastkey,debounce ' ' Application informs the keypad scanner of which pins it wants for rows and which for columns ' i.e. InitKeys(%11001100,%100000110010) ' note that the pins are scattered ' pub Initkeys(rows,columns) ' bitmasks of rows and columns - can be arbitrary rowmask := rows colmask := columns ' Application should poll "key" on a regular basis from 100 to 1000 times a second ' 'key' will return -1 if there is no new key ' pub key | i result := scankeys if result+1 ' process as long as keycode is not -1 i~ ' scan through scancode to ASCII translation table repeat until word[@keytbl][i] == 0 ' end of table? if result == word[@keytbl][i] ' do we have a match? bip ' short little bip return word[@keytbl][i+1] ' yes, return with ASCII (or 16-bit code) i += 2 ' jump to next table entry ' application specific short key beep (bip) pri Bip dira[piezo]~~ sound(80,50) ' Application can also call scankeys which will return the 10-bit scancode if a key is pressed ' pub scankeys | n,i,j ' scan keypad and return with code else -1 result := -1 outa &= !colmask ' drive all columns low with pullups dira |= colmask ' all columns active n := ina & rowmask if n <> rowmask ' active column detected if result does not match rowmask dira &= !colmask ' return columns inactive debounce := 3 ' preset debounce for long enough time to cover debounce if lastkey == -1 ' process key as long as it's a new key press (must be idle before) repeat i from 0 to 31 ' check all possible mask positions if colmask & |<i ' column in this position? dira[i]~~ ' drive this column low? (open-drain) n := ina & rowmask dira[i]~ ' release column if n <> rowmask ' found the column yet? ' yes, column found, now find row that's different ' if rowmask = 110011 and n = 100011 ' 110011 xor 100011 = 10000 n ^= rowmask ' get active bit n := >|n ' convert mask to a value+1 n-- ' zero based n += i<<5 ' merge row and column codes lastkey := n result := n ' return with an intermediate 10-bit scan code else if debounce debounce-- else lastkey := -1 dat keytbl word $012b,"1" word $010b,"2" word $00cb,"3" word $012a,"4" word $010a,"5" word $00ca,"6" word $0120,"7" word $0100,"8" word $00c0,"9" word $0122,"*" word $0102,"0" word $00c2,"#" word 0
Comments
BTW, only the pull-up resistors are really needed, the other 1K resistor is only if you are using the port pins for other functions such as driving LCDs.