Keypad scanning and debouce with PIC18F

Discussion in 'Embedded Systems and Microcontrollers' started by LewisMF, Oct 13, 2015.

  1. LewisMF

    Thread Starter Member

    Nov 15, 2014
    Dear all,

    I'm in the middle of a project that involves a keypad. It's a 3 x 3 matrix pad connected to PORTB of a PIC18F45K22 uC.

    After a little research I have the following questions:

    - Which would be the best way to scan the Keypad?
    - Shall I use a timer based scan or an ISR?
    - Could anyone provide some examples for the C18 compiler?

    I am quite new to programming and have never coded a pad before so please go easy on me.

    Best regards,
    LewisMF :)
  2. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    What keyboard? Got a schematic or is this a secret?
    I would use a timer based ISR for the scan.
    That would mean writing and debugging a keyboard scan for an unknown keyboard for an unknown purpose.

    Basically, you read the keys "every so often" and compare the present read to the last read. If you have the same then you have a new key down. If they differ save the new reading and wait to get another.

    How fast "every so often" is depends on the specific buttons you use. For me, 25-50 mS seems just fine.
  3. Art

    AAC Fanatic!

    Sep 10, 2007
    Gets asked all the time. I wouldn’t waste an ISR or interrupt pins on it unless necessary.
    This is typical:
    Column 0-3 are tied high typical with 10K resistors.
    Set rows 0-3 as outputs and set them all high.

    To begin a scan, set row 0 pin low and check columns 0-3 for low state.
    If any of column 0-3 were read high then the corresponding key was pressed.
    Then set row 0 pin low and turn row 1 pin high.
    Then check column 0-3 for a low state again for a corresponding key.
    Then continue the rest of the columns the same way.
    If you never find a low state then no key was pressed.
    The moment you find any key you can exit the scan and disregard scanning the rest of the columns.

    Depending what your program does you might not need key debounce.
    One way is to check for last key pressed is still being held,
    and only copy a key press to the rest of your program if a previous key was released.
  4. LewisMF

    Thread Starter Member

    Nov 15, 2014
    Hi ErnieM,

    Keyboard is no secret, here is the schematic;


    When you say 'timer based ISR', could you go in to a bit more detail (Sorry about this but as I said in my previous post, I am quite new to embedded programming).

    As you explained in your previous post the keypad will have to be scanned 'every so often' to see if any button has been pressed. But as the uC will also be scanning some sensors from it's ADC channels, I thought it might be better to use an interrupt based timer. That way the uC wont waste time scanning the pad every 25-50mS.

    You have much more experience than me here so, what do you think will be the best way to implement this?

    Thanks once again for your help ;)
  5. LewisMF

    Thread Starter Member

    Nov 15, 2014
    Hi Art,

    I wont be using ISR or interrupt pins for anything else so there is no problem using them if necessary.

    I understand your point of view but as the buttons will be used to navigate a menu on an LCD, I think button debouce will be a problem and this is mainly where I am stuck.

    I have no previous experience with keypads and button deboucing (without using delays of course) therefore I want to avoid delays at all cost, they would just slow down the ADC readings from the sensors and this is not possible.

    Any suggestions? :confused:
  6. Art

    AAC Fanatic!

    Sep 10, 2007
    For debounce with minimal delay you could set a variable to say 200 when a key is pressed
    and decrement that value for every program cycle until it’s zero.
    Then when you register any key press you ignore it if the variable is not zero.
    If the variable is zero you pass the key press to your program and set the variable to 200 again
    (or whatever the value is).
  7. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    I don't see how your keyboard works if for no other reason the 3outputs are undefined when no key is pressed. Unless you want to read buttons thru an A2D typically one needs 6 lines to scan: 3 to drive each row in turn, and 3 to read hi or low.

    My preference for reading buttons is to have a timer interrupt do that for me. Thus my main loop just needs check if a button is pressed, not actually reading the buttons. Also, generating an external interrupt for any key pressed or released is going to need some more parts.

    Scanning the keys continiously is something that just takes a few instructions, mostly the code is sitting in a loop waiting for something to happen.
    JohnInTX likes this.
  8. Art

    AAC Fanatic!

    Sep 10, 2007
    Depends Ernie, at least with some pics you can use interrupt on port change and look at four pins simultaneously for hardware interrupt.
    The four pins can be half of the multiplex pins and they you don’t need any diodes :)

    I figure for debounce with what Ernie describes would be similar,
    or when you reset the hardware timer that generated a periodic interrupt, look for a minimum timer value to qualify a key press,
    or on an interrupt caused externally by a hardware key press, you could disable the interrupt until a timer value was reached.

    A bit of a trick.. I wouldn’t recommend for starters, you can check one key for every cycle of your program if it really is that fast, if you put it in a place a delay was, it was done for free.
    Last edited: Oct 14, 2015
  9. John P

    AAC Fanatic!

    Oct 14, 2008
    There are some things I disagree with there. First, don't use pullup resistors unless you're forced to do it: the processor probably has internal pullups on at least some of its pins, so use those if you can and save some wiring.

    Second, if you set all the outputs (the rows, in this case) high except for one low one while they're all active, you'll have a short circuit if the user presses two buttons in the same column simultaneously. It's better defensive programming to set all the outputs to high-impedance with the port pins set low, and then enable them as outputs one at a time by changing bits of the TRIS register. That way, no high can ever connect to a low. Also, that gets you around the miserable PIC read-modify-write bug, which can mysteriously change port pin outputs when you think you're just changing a single pin.
  10. Jswale


    Jun 30, 2015
    I went through a similar sub-project a few months back...

    I would poll for any buttons pressed because it will take such little time and by the sounds of it your project is not time critical.

    I would also second the use of weak internal pull-ups.

    Also for the debounce, just put in a small delay after a button is recognised and therefore the program will 'wait' and will take no notice of any switch debouncing.