There are few things that make me as giddy as I get when I have an idea which I really fall in love with and I can’t wait to implement. This is exactly as giddy as I felt when I thought of a different way to handle a keypad as a source of input into an embedded system.
Very many of the examples you’d find online that pertain to a keypad, are implemented using a blocking routine. Which means that the keypad is read in cycles, and as it’s being read, the processor is not doing anything else. If you’ve interacted with embedded systems from an engineering perspective, you know how inefficient this can be. If the processor gets caught up in some other long-running operation, you might end up pressing the keys 10 or even 20 times to get them to respond. Especially when you’re dealing with tiny, low memory, low processor-speed microcontrollers, such operations can basically render the application very inefficient. (I say low-speed microcontrollers because their speeds can’t even begin to compare to cutting edge microcontrollers, let alone microprocessors. In this instance I was using a microcontroller that runs at 16 MHz)
But that’s not what made me try to come up with an algorithm to handle it myself. Of course it was at the back of my mind as efficiency was a big part of the system that I was creating at the time. The method seems so inelegant. Scaling it would be a nightmare, and I was developing a fairly involved system. Surely there has to be a better way to do this!
Rather than set out on a backpacking trip across Google to look for a solution to my problem, I felt something cooking in my mind. It was an idea of how I could create a completely interrupt-based low-level keypad driver. Which brings us to the core of this entire rant. (or should I call it an enthusiastic chatter – I was most definitely excited by what my mind was cooking up). There’s definitely an even more efficient way of handling this, which would be using a keypad scan integrated circuit (a hardware chip that does the identification for us). But this didn’t matter as much at the time, I was already too excited to not see this through to the end.

Looking at the construction of a keypad, in this case a 4×4 keypad, you may notice that the keypad is made up of a series of rows and columns of buttons, or rather keys in this case. To detect key presses on any of the 16 keys on the 4×4 keypad, we require 8 hardware pins from our microcontroller to connect to the keypad. These would connect to 4 keys which connect to each of the keypad rows, and another 4 keys that connect to each of the keypad columns.
My intriguing idea would have to use interrupts to ensure that the key presses were responded to in real-time. And my task was then to figure out how to make the entire system interrupt-based.
The process I settled on would require a discrete number of steps for the system to work as intended and detect each key press nearly instantaneously.
- Initialize the row pins as inputs with internal pull-ups and the column pins as outputs with a default low state.
- Simply by doing this, we are well on our way to making our solution respond to keypad presses in real time.
- This creates a situation in which any single key-press changes the state of the corresponding row input pin to a low-level.
- But that’s only a part of the solution. From this, we can directly tell what row the pressed key is on, but we have no idea of the corresponding column.
- Setting up the row input pins with pin change interrupts to be triggered on a change of state.
- Setting up an interrupt service routine (ISR) to service these requests, immediately interrupts the program running and executes our code to identify the key pressed before resuming normal execution.
- Within the ISR, we change the initial state of all our column pins to high, and then toggle one of them at a time to the low state, and check for a change on our row pin which we had previously identified.
- We can then identify the corresponding column from this sequence.
And with this short fast-executing sequence (worst case of about 20 microseconds) we have identified the key that has been pressed. We can then pass this on to a callback that notifies the higher-level program of this event, and the program can then respond appropriately, and in real-time.
The biggest penalty to using this method is the hardware cost, we end up using 8 physical pins on the micro-controller where we could potentially use a lot less with a keypad scan ic, which we could interface to with i2c or 4 data lines for each of the bits that can be used in uniquely identifying 16 discrete values.
GitHub
The corresponding code is available on GitHub: