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 #.
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 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'.
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 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.
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.