PIC Tutorial Nine - HEX Keypad
For
these tutorials you require the Main Board, Keypad Board, LCD Board, IR
Board and RS232 Board. Download zipped
tutorial files.
These
tutorials demonstrate how to read a HEX keypad, these are a standard device
with 16 keys connected in a 4x4 matrix, giving the characters 0-9 and A-F.
You can also use a 4x3 keypad, which gives the numbers 0-9, * and #.
 |
This
is how the HEX keypad is connected, each square with a number or
letter in it is a push to make switch, which connects the horizontal
wires (rows) with the vertical wires (columns). So if you press button
'A' it will connect COL1 with ROW4, or pressing button '6' will
connect COL3 with ROW2. For a numeric (4x3) keypad COL4 will be
missing, and 'A' and 'B' replaced with '*' and '#' but is otherwise
the same. The sample programs use a lookup table for the keys, this
would need to be changed to insert the correct values for the
non-numeric characters. |
As the
switches are all interconnected, we need a way to differentiate between the
different ones - the four resistors on the interface board pull lines COL1
to COL4 high, these four lines are the ones which are read in the program.
So in the absence of any switch been pressed these lines will all read high.
The four ROW connections are connected to output pins, and if these are set
high the switches will effectively do nothing - connecting a high level to a
high level, results in a high level.
In
order to detect a switch we need to take the ROW lines low, so if we take
all the ROW lines low - what happens?. Assuming we press button 1, this
joins COL1 with ROW1, as ROW1 is now at a low level, this will pull COL1
down resulting in a low reading on COL1. Unfortunately if we press button 4,
this joins COL1 with ROW2, as ROW2 is at a low level this also results in a
low reading at COL1. This would only give us four possible choices, where
each four buttons in a COL do exactly the same (e.g. 1, 4, 7, and A are the
same).
The
way round this is to only switch one ROW at a time low, so assuming we set
ROW1 low we can then read just the top row of buttons, button 1 will take
COL1 low, button2 will take COL2 low, and the same for buttons '3' and 'F'
in COL3 and COL4. The twelve lower buttons won't have any effect as their
respective ROW lines are still high. So to read the other buttons we need to
take their respective ROW lines low, taking ROW2 low will allow us to read
the second row of buttons (4, 5, 6, and E), again as the other three ROW
lines are now high the other 12 buttons have no effect. We can then repeat
this for the last two ROW's using ROW3 and ROW4, so we read four buttons at
a time, taking a total of four readings to read the entire keypad - this is
a common technique for reading keyboards, and is called 'Keyboard Scanning'.
One
obvious problem is what happens if you press more than one key at a time?,
there are a number of ways to deal with this, one way would be to check for
multiple key presses and ignore them, a simpler way (and that used in the
examples) is to accept the first key you find which is pressed. You will
find that various commercial products deal with this situation in similar
ways, some reject multiple key presses, and some just accept the first one.
As
with previous tutorials, the idea is to give a tested working routine which
can be used elsewhere, the subroutine to be called is Chk_Keys, the first
thing this does is check to see if any of the 12 keys are pressed (by making
all the ROW lines low) and waiting until no keys are pressed - this avoids
problems with key presses repeating. Once no keys are pressed it jumps to
the routine Keys which repeatedly scans the keyboard until a key is pressed,
a call to one of my standard delay routines (call Delay20) provides a
suitable de-bouncing delay. Once a key has been pressed the result is
returned in the variable 'key', this is then logically ANDed with 0x0F to
make absolutely sure it's between 0 and 15. Next this value is passed to a
look-up table which translates the key to it's required value (in this case
the ASCII value of the labels on the keys). Finally the ASCII value is
stored back in the 'key' variable (just in case you might need it storing)
and the routine returns with the ASCII value in the W register.
;Keypad subroutine
Chk_Keys movlw 0x00 ;wait until no key pressed
movwf KEY_PORT ;set all output pins low
movf KEY_PORT, W
andlw 0x0F ;mask off high byte
sublw 0x0F
btfsc STATUS, Z ;test if any key pressed
goto Keys ;if none, read keys
call Delay20
goto Chk_Keys ;else try again
Keys call Scan_Keys
movlw 0x10 ;check for no key pressed
subwf key, w
btfss STATUS, Z
goto Key_Found
call Delay20
goto Keys
Key_Found movf key, w
andlw 0x0f
call Key_Table ;lookup key in table
movwf key ;save back in key
return ;key pressed now in W
Scan_Keys clrf key
movlw 0xF0 ;set all output lines high
movwf KEY_PORT
movlw 0x04
movwf rows ;set number of rows
bcf STATUS, C ;put a 0 into carry
Scan rrf KEY_PORT, f
bsf STATUS, C ;follow the zero with ones
;comment out next two lines for 4x3 numeric keypad.
btfss KEY_PORT, Col4
goto Press
incf key, f
btfss KEY_PORT, Col3
goto Press
incf key, f
btfss KEY_PORT, Col2
goto Press
incf key, f
btfss KEY_PORT, Col1
goto Press
incf key, f
decfsz rows, f
goto Scan
Press return
For
the full code, with the equates, variable declarations and look-up table,
consult the code for the examples below.
Tutorial 9.1
Tutorial
9.1 simply reads the keyboard and displays the value of the key pressed on
the LCD module, it shows this as both HEX and ASCII, so if you press key '0'
it will display '30 0'.
Tutorial 9.2
This
tutorial implements a simple code lock, you enter a 4 digit code and it
responds on the LCD with either 'Correct Code' or 'Wrong Code', it uses all
sixteen available I/O lines on a 16F628 which leaves no spare I/O line for
opening an electrical lock. However, using a 4x3 keypad would free one I/O
line, or a 16F876 could be used giving plenty of free I/O. I've set the code
length at 4 digits, it could very easily be altered from this. The secret
code is currently stored within the program source code, as the 16F628 and
16F876 have internal EEPROM the code could be stored there and be changeable
from the keypad.
Tutorial 9.3
Tutorial
9.3 reads the keypad and sends the ASCII code via RS232 at 9600 baud, you
can use HyperTerminal on a PC to display the data. Basically this is the
same as 9.1 but uses a serial link to a PC instead of the LCD screen.
Tutorial 9.4
A
common use for keyboard scanning applications, this example reads the keypad
and transmits IR remote control signals to control a Sony TV, this works in
a very similar way to the circuit used in your TV remote control. For this
application I've modified the keypad routines slightly - as we want the keys
to repeat I've removed the first part which waits for a key to be released,
and as we don't need ASCII values back from the key presses, I've removed
the look-up table which gave us the ASCII values. I've replaced that with a
jump table, this jumps to one of 16 different small routines which send the
correct SIRC code for each button pressed - it's a lot neater than checking
which button was pressed. The controls I've chosen to include are, 0-9, Prog
Up, Prog Down, Vol Up, Vol Down, On Off, and Mute. If you want to change
which button does what, you can either alter the equates for the button
values, or change the order of the Goto's in the jump table, notice that
these are currently in a peculiar order, this is to map the numeric buttons
correctly.
|