Convenient Way of Reading Keypad Buttons

Most of microcontroller coding tutorials’ second page is dedicated to reading pin or buttons. But for sure, that never means this is a trivial task and a keypad reader is easy to implement for a well designed MCU program that you should never underestimate. With this C keypad reader, you don’t have to struggle.

The Best Practice

The very first problem that you will face when you try to implement a general purpose keypad reader library is mechanical and electrical spikes that come from the buttons, so called bouncing effect. Although you already implemented hardware filters to reduce, it is still out there and can be prevented only with a good software filter.

Another reason that drives me to write this post is that reading multiple buttons at once is a very complex task. Even when you try to make the most basic user interface, you will need multiple buttons. Let’s imagine we have a no-touch display with a settings menu. In this scenario ENTER, UP, DOWN and EXIT look like the most common buttons. What if you want to have a secret button combination to enter hidden service menu? Then you need to sense multiple button press, i.e. ENTER-while-UP-and-DOWN for 3 seconds. I bet you would find the following piece of code a trash.

And I am pretty sure that you would desire such a clean code instead:

Good news: this is possible with “PushME” keypad reader library 😋

Features of PushME

The fancy name doesn’t only for show but it has several features that you will find useful. Let’s talk about technical details. PushME is implemented in C language and aimed to real-time applications. The library supports up to 15 buttons (KEY00 to KEY14) by default. it doesn’t mean that you can’t extend it for more buttons or compact it for less resource consumption.

Key Definitions

To add a button to be polled by the library, just assign it to one of the library-specific defines. Respectively; the pin definition (architecture specific) and active state of the button.

Here, GPIOA,0 is the pin definition that i use in Porty project if you haven’t read it yet. But it is always possible to use with any microcontroller like Microchip for example PORTAbits.RB0. If PIN access is not available, defining the pin as (PORTC & 0x80) and the active state as 0x80 will do the work.

What is better than pooling a button? To be able to pool any signal of course. I used capacitive touch buttons on a Cypress PSoC (which has its own API calls to read the buttons) by replacing the pin definitions with these functions like the following and the keypad library worked seamlessly.

Debounce Filter

The most important one is debouncing of all buttons with no need for extra filtering. There is a specific minimum time limit KEY_DEBOUNCE_TIME for continuous key press in milliseconds defined in  keypad.h. It simply keeps reading the PIN value for the given amount of time and if detects a bouncing, resets the time and keeps reading again until it catches a clear active signal. The library uses a timeout framework that I call Punctual to implement debouncing filter and other time events. This framework is already embedded in the attached project below.

LongPress or KeyHold

Long press is useful for many applications and PushME supports longpress events. Just assign a value to KEY_LONGPRESS_TIME in milliseconds that you wish to count as a long press and that’s all.

Repeated Events

PushME allows you to hold a button longer than KEY_LONGPRESS_TIME to create repeated events. You can imagine this as increasing the volume of your TV by holding VOL+ button on remote. Those repeated events start when KEY_LONGPRESS_TIME ends and repeats in every KEY_LONGPRESS_REPEAT_TIME milliseconds which can be set in keypad.h. It can be set to 0 to disable repeating.

Boosted Repeats

Another feature is boosted repeated events. Let’s say you have a menu and you want to increase a number field from 0 to 100. This takes a long time by pressing 100 times and still takes time with repeated long press (that has been mentioned above). To solve this, PushME sends repeated events in the beginning and changes the repetition interval to something smaller after some number of repetitions. Settings for this 2 are KEY_LONGPRESS_BOOST_TIME and KEY_LONGPRESS_BOOST_THRESHOLD. To disable boost feature, just set KEY_LONGPRESS_BOOST_TIME equal to KEY_LONGPRESS_TIME.

In other words, when KEY_LONGPRESS_TIME is over, 1 signal is sent in every KEY_LONGPRESS_REPEAT_TIME milliseconds for KEY_LONGPRESS_BOOST_THRESHOLD times, then it sends the rest of the signals in every KEY_LONGPRESS_BOOST_TIME milliseconds.

Key Labels

As explained above, every button label is created individually using KEYnn definitions and this is the low-level name of the button. User friendly case is that you define your own labels using or combining them. Available low-level labels are KEYnn and special KEYLONG that are used in the following examples.

Events Explained

Following 3 events are possible with the provided keypad library.

KeyPress

KeyPress is the combination of a KeyDown event is followed by KeyUp event on a specific key or a combination of keys. This event is polled using isKeyPress(...) method and returns true if the given key had a KeyPress event recently. Supports repetition and boost features and returns true  repeatedly.

KeyHold (LongPress)

KeyHold is the combination of a KeyDown event is followed LongPress w.r.t. KEY_LONGPRESS_TIME. KeyUp event on a specific key or a combination of keys. This event is polled using isKeyHold(...) method and returns true on KeyHold event. Supports repetition and boost features and returns true  repeatedly.

This event is actually an overloading of isKeyPress(...) with and addition of KEYLONG to the given key combination. The following lines do exactly the same job.

KeyDown

This event is polled using isKeyDown(...) method and it simply returns if the button is hold-down at the time being, regardless of debounce filter. This method is implemented for instantenaous response that requires fast action rather than regular button events. Use with caution.

Usage

To poll the keys keypadRead()  method has to be called in a fast infinite loop. The following code turns an LED on when KEY00 is pressed and turns off (or toggles) by longpress of the same key. When the key is not released, it starts toggling the LED in low frequency. Finally after 8 repeated events, toggling occurs at a high frequency which is the boost.

PushME Files

keypad.h

keypad.c

Download

A complete project that runs on STM32F100 microcontroller: PushME-0.1.0 . For compilation check here.

Conclusion

This project successfully reads digital keypads and every kind of digital signals from any sources. My plan is to add functionality for reading analog keypads since multiple keys on a single line is very advantageous in tightly constrained application. Don’t hesitate to share your comments 😉

Leave a Reply

Your email address will not be published. Required fields are marked *