• Pic® Basic


  • Keypad 3 Wire

    If you don't know exactly how a keypad works I suggest you look at the Keypad article first

    The standard way of using a 3 x 4 keypad is to use 7 pic pins. This method uses 3 pic pins, saving 4 pic pins. This enables one to use smaller pics while still have enough pins left for other I/O's. The trade-off in this case is the pic must have 3 A/D inputs.



    How it works is really simple. The 5 x 1k resistors between 5V and GND forms a volatge devider that gives about 1V, 2V, 3V and 4V voltage drop over the resistors measured from ground. If a 10-bit A/D is used, you have a count of 1024 for the full 5V.

    This means that about 205 counts per devider resistor is going to be counted. I say about, because it is easy to compensate for variations of counts and component tolerances in the software as you will see.

    Looking at the circuit you can see that if no key is pressed, 0V will go to the A/D input.

    Row 1, 2 and 3 gets pulled to GND by the 100k resistors.
    If the * key is pressed, row 1 will output about 1V (or about 205 counts in AN1)
    The 7 key will give about 2V (or about 410 counts in AN1)
    The4 key will give about 3V (or about 615 counts in AN1)
    The1 key will give about 4V (or about 820 counts in AN1)
    The same will values will be read by AN2 if you press keys 0, 8, 5 and 2
    and again the same values will be read by AN0 if you press keys #, 9, 6 and 3
    So by reading the values with the different A/D's, you know which key is pressed.

    Here's a neat trick. The three A/D inputs can be used as 5V logic inputs as well, but you will have to compensate in the software for that. The code below only provides for reading the keys voltages, you will have to add -

    If Vin > 950 Then Disp1 = 12 ' Logic Input on this pin
    If Vin > 950 Then Disp1 = 13 ' Logic Input on this pin
    If Vin > 950 Then Disp1 = 14 ' Logic Input on this pin
    to the bottom of KeyIn1, KeyIn2 and KeyIn3 (i.e. before the 'GoTo KeyIn4')

    Dim Disp1 As Byte ' The key pressed is returned in this variable
    Dim Vin As Dword ' The A/D Value of the key pressed

    '************************************************* *****************
    ' Read keypad input call routine
    '************************************************* **************
    KeyIn:
    DelayMS 10 'Debounce
    Disp1 = 15 'dummy value in case no key pressed

    KeyIn1:
    Vin = ADIn 1 'Read A/D Input cha 1
    'Compare lowest value first, if a higher value is compared,
    'that key will be the key that was pressed.

    If Vin < 50 Then GoTo KeyIn2 ' No key pressed, do next column
    If Vin > 150 Then Disp1 = 10 ' Key * pressed
    If Vin > 350 Then Disp1 = 7 ' Key 7 pressed instead
    If Vin > 550 Then Disp1 = 4 ' Key 4 pressed instead
    If Vin > 750 Then Disp1 = 1 ' Key 1 pressed instead
    GoTo KeyIn4 ' Do key release Routine

    KeyIn2:'
    Vin = ADIn 2 'Read A/D Input cha 2
    If Vin < 50 Then GoTo KeyIn3 ' No key pressed, do next column
    If Vin > 150 Then Disp1 = 0 ' Key 0 pressed
    If Vin > 350 Then Disp1 = 8 ' Key 8 pressed instead
    If Vin > 550 Then Disp1 = 5 ' Key 5 pressed instead
    If Vin > 750 Then Disp1 = 2 ' Key 2 pressed instead
    GoTo KeyIn4 ' Do key release Routine

    KeyIn3:
    Vin = ADIn 0''' 'Read A/D Input cha 0
    If Vin < 50 Then Return ' No key pressed, return to the main loop
    If Vin > 150 Then Disp1 = 11 ' Key # pressed
    If Vin > 350 Then Disp1 = 9 ' Key 9 pressed instead
    If Vin > 550 Then Disp1 = 6 ' Key 6 pressed instead
    If Vin > 750 Then Disp1 = 3 ' Key 3 pressed instead

    '************************************************* ********************
    KeyIn4: 'Key release Routine if required – keeps from reading the same key over and
    'over by mistake if you have fingers slower than the code ;-)
    Vin = ADIn 1
    If Vin > 50 Then GoTo KeyIn4
    Vin = ADIn 2
    If Vin > 50 Then GoTo KeyIn4
    Vin = ADIn 0
    If Vin > 50 Then GoTo KeyIn4
    Return

    End
    The code compiles to about 407 program words. It is advisable that you make sure the rest of the code will also fit. I use this in quite a few 16F684's that has 2k of program memory. The code above will return with the following values in Disp1 -

    Key 1 Returns a 1
    Key 2 Returns a 2
    Key 3 Returns a 3
    Key 4 Returns a 4
    Key 5 Returns a 5
    Key 6 Returns a 6
    Key 7 Returns a 7
    Key 8 Returns a 8
    Key 9 Returns a 9
    Key 0 Returns a 0
    Key * Returns a 10
    Key # Returns a 11
    Logic on ADIn1 (if implemented) Returns a 12
    Logic on ADIn2 (if implemented) Returns a 13
    Logic on ADIn0 (if implemented) Returns a 14
    No key pressed Returns a 15
    All you need to do when the code returns with a value in Disp1 is decide what to do with it.

    If Disp1 = 5 then goto.... ' Keypad key 5 pressed or -
    If Disp1 = # then Relay1 = 1 ' Key # pressed, switch lights relay on
    Note – the same can be done with a 16 key keypad using 4 A/D pic pins. Not bad saving 4 pic pins in using either a 12 key or 16 key keypad.

    In low power apps the 5V supply for the keypad resistors can be supplied by a pic pin. The keypad will consume no power when that pin is made low or 0

    Should work as well with 3V3 pics, keypad also gets supplied with 3v3 then.

    contributed by Fanie.