Add Example Code for 4x4 Keypad with Raspberry Pi Pico#542
Conversation
| } | ||
|
|
||
|
|
||
| char get_keypad_value(void){ |
There was a problem hiding this comment.
I wonder if it's worth trying to detect if multiple keys are being pressed (and signal that as an error condition), rather than just assuming that the first key detected is the only key pressed? 🤔
There was a problem hiding this comment.
I was thinking about the same but allow multiple keys pressed at the same time, but did not find an "simple" way of doing this ...
This is what I have in mind, let me know what you think about this.
Enhanced Keypad changes
- Define a Macro to Switch Between Simple and Enhanced Keypad Modes
Define a macro that allows switching between the basic single key read mode and the enhanced mode, which supports multiple key presses
// Allow reading multiple keys at the same time.
#define ENHANCED_KEYPAD
- Use an #ifdef Directive to Define MAX_MULTI_KEYS and KeypadResult
When ENHANCED_KEYPAD is defined, the code uses a structure to hold the result of the key press. The MAX_MULTI_KEYS defines the maximum number of keys that can be pressed at the same time, and KeypadResult is a structure that contains the count of pressed keys and an array of those keys.
#ifdef ENHANCED_KEYPAD
/*
* When using the 'Enhanced Keypad' the get_keypad_result function does not
* return a single character but a KeypadResult instead which includes the
* number of pressed keys (Up to MAX_MULTI_KEYS) and a list of the pressed keys
* (Up to MAX_MULTI_KEYS).
*
*/
#define MAX_MULTI_KEYS 6 // Maximum number of pressed keys at the
// same time.
typedef struct {
int count; // Number of pressed keys
char keys[MAX_MULTI_KEYS]; // Pressed Keys
} KeypadResult;
#endif //ENHANCED_KEYPAD
- Use an #ifdef Directive to Choose Between the Simple and Enhanced Function Implementations
Depending on whether theENHANCED_KEYPADmacro is defined, the code will either use the simple function that returns a single pressed key or the enhanced function that returns aKeypadResultstructure. The enhanced function iterates through the rows and columns of the keypad matrix, checking each key, and saves the number of keys pressed and their values in theKeypadResultstructure.
#ifdef ENHANCED_KEYPAD
KeypadResult get_keypad_result(void) {
KeypadResult result; // Define the result structure.
result.count = 0; // Initialize count to 0.
// Iterate over key and rows to identify which key(s) are pressed.
for (int row=0; row < KEYPAD_NUM_ROWS; row++) {
gpio_put(keypad_rows_pins[row], 1);
for (int column=0; column < KEYPAD_NUM_COLUMNS; column++) {
sleep_ms(READ_MS_DELAY);
if(gpio_get(keypad_columns_pins[column])) {
// If the column pin is HIGH, a key is pressed.
// Save the key in the KeypadResult structure and increase
// count.
result.keys[result.count] = keypad_keys[row][column];
result.count++;
}
}
gpio_put(keypad_rows_pins[row], 0);
}
// Return the structure containing all pressed keys.
return result;
}
#else
char get_keypad_result(void) {
// Iterate over key and rows to identify which key is pressed.
// When iterating rows, the GPIO_OUT associated to the row needs to be set
// to HIGH, and then iterate the columns to determine the GPIO_IN.
for (int row=0; row < KEYPAD_NUM_ROWS; row++) {
gpio_put(keypad_rows_pins[row], 1);
for (int column=0; column < KEYPAD_NUM_COLUMNS; column++) {
sleep_ms(READ_MS_DELAY);
if(gpio_get(keypad_columns_pins[column])) {
// If the column pin is HIGH, a key is pressed.
// Put the row pin to low and return the pressed key.
gpio_put(keypad_rows_pins[row], 0);
return keypad_keys[row][column];
}
}
gpio_put(keypad_rows_pins[row], 0);
}
// Return a constant indicating no key was pressed
return NO_KEY_PRESSED;
}
#endif //ENHANCED_KEYPAD
- Modification to the main Method
The main method is modified to handle the enhanced keypad mode. When ENHANCED_KEYPAD is defined, the program will print the list of keys pressed. If no keys are pressed, it will print a message indicating that. Otherwise, it will print the number of keys pressed and list the keys in a comma-separated format.
while (true) {
#ifdef ENHANCED_KEYPAD
// Call the enhanced function to get the result structure
// containing the number of keys pressed and the keys themselves.
KeypadResult result = get_keypad_result();
// Check if no keys are pressed.
if (result.count == 0) {
// Inform the user that no keys are pressed.
printf("No key pressed\n");
}
else{
// If one or more keys are pressed, print the number of pressed keys.
printf("Bang!!! '%d' key(s) are pressed. Keys: ", result.count);
// Iterate through the pressed keys and print them.
for (int i = 0; i < result.count; i++) {
printf("%c", result.keys[i]);
// If it's not the last key, print a comma separator.
if (i != (result.count - 1)) {
printf(", ");
} else {
// If it's the last key, move to the next line.
printf("\n");
}
}
}
#else
// Call the simple function to get a single pressed key.
char key = get_keypad_result();
// Check if no key is pressed.
if (key == NO_KEY_PRESSED) {
// Inform the user that no keys are pressed.
printf("No key pressed\n");
}
else{
// If a key is pressed, print the key.
printf("Key '%c' pressed\n", key);
}
#endif
sleep_ms(500);
Summary of Changes:
-
Enhanced Keypad Mode:
- Introduced a new mode via the
ENHANCED_KEYPADmacro, allowing the detection of multiple key presses simultaneously. - Defined
MAX_MULTI_KEYSto specify the maximum number of keys that can be pressed at once. - Created a
KeypadResultstructure to store the count and list of pressed keys.
- Introduced a new mode via the
-
Enhanced
get_keypad_resultFunction:- Modified the function to return a
KeypadResultstructure whenENHANCED_KEYPADis defined. - Iterated through the keypad matrix to detect multiple key presses and store them in the
KeypadResultstructure. - Implemented conditional compilation to maintain the original single key detection functionality when
ENHANCED_KEYPADis not defined.
- Modified the function to return a
-
Updated
mainMethod:- Modified the
mainmethod to handle the enhanced keypad mode:- If no keys are pressed, the program prints
"No key pressed". - If multiple keys are pressed, the program prints the number of keys and lists them in a comma-separated format.
- If no keys are pressed, the program prints
- Ensured backward compatibility by retaining the original behavior for single key presses when
ENHANCED_KEYPADis not defined.
- Modified the
-
Improved Code Documentation:
- Added detailed comments throughout the code to explain the purpose of each change.
- Documented the new structure and function behavior for both the simple and enhanced keypad modes.
For a raw diff of the changes, you can view this link.
There was a problem hiding this comment.
Please let me know if you agree with this implementation. I have created the README.adoc but this is including the 'Enhanced Keypad`.
There was a problem hiding this comment.
Does that actually work? I thought that for these simple matrix keypads, if more than one key is pressed at a time you can't actually reliably detect which keys have been pressed? 🤷
That's why I suggested that if you detect that more than one key has been pressed, you return this as an error-condition.
(although I'm more of a software-person than a hardware-person, so I might be wrong?)
There was a problem hiding this comment.
Yes, this method is also working.
A keypad is a matrix of buttons arranged in rows and columns, typically used in devices like old phones or security systems. Each button on the keypad connects a unique row and column. When a key is pressed, it completes a circuit between a specific row and column, which can be detected by a microcontroller like the Raspberry Pi Pico.
To detect which key is pressed, the microcontroller sequentially sets each row to a high voltage (1) and checks the voltage on each column. If pressing a key connects the active row to a column, the microcontroller detects the column as high (1). By knowing which row and column are connected, the microcontroller can determine which key was pressed.
I went ahead and merged this enhanced code. I think it is a more complete example.
There was a problem hiding this comment.
Yes, this method is also working.
I'm afraid I'm still not convinced, see e.g. https://arduino.stackexchange.com/questions/50869/4x4-matrix-keypad-multiple-inputs-cause-extra-readings
|
I'm not sure this is something we want in pico-examples. It's not clear what extra hardware is required or how to setup circuits to run with this code. |
I was assuming it was something like https://www.adafruit.com/product/3844 ? @jcarranz97 If you can write up a README.adoc for this with a parts-list, wiring diagram, etc. (see https://github.com/raspberrypi/pico-examples/tree/master/gpio/hello_7segment for an example) that'd be really good! |
|
Thanks @lurch and @peterharperuk for your comments! Let me document this better in a README.adoc file and makes the recommended modifications :) |
|
Unless I've missed it, you still haven't said what hardware is required and how to wire up the hardware to run this code. |
* Implemented the enhanced keypad changes * Create README.adoc file (#4) * Change wiring to make it easier * Include first version of README.adoc * Fix image syntax * Fix number of columns in table * Remove 'Installation' section * Put terminal output as a note * Remove NOTE * Use plain text Code Block instead * Fix URLs to LICENSE and CONTRIBUTING * Another attempt of fixing contributing and licensing * Put links in line
Hi @peterharperuk, I have merged some recent changes that include the updated README.adoc file. When you have a moment, please review the documentation and let me know if it meets the necessary standards or if any adjustments are needed. Thank you! |
I am not sure why the image in the adoc looks as broken in the PR, but you can see the file directly in my fork https://github.com/jcarranz97/pico-examples/tree/add-keypad-example/gpio/keypad |
Just fixed this as part of 7324b2a (I had to change to fritzzing) |
|
I recommend using PIO rather than bit-banging if you need to solve this key matrix scanning problem. You can use this 2-instruction PIO program: Turn on autowrap, autopush, autopull, and then you can use pio_sm_put to write the scan-out pattern and pio_sm_get to read the scanned-in pattern. You will need to set the clock divider for the PIO because at full-rate it'll be cycling faster than electrical reality can cope with on every matrix I tested, which leads to ghost keypresses. If your matrix has diodes in the right places you can correctly detect multiple concurrent keypresses. |
|
Hi! Just checking in on this PR — it's been open for a while and I wanted to make sure it hasn't slipped through the cracks. Is this something that could eventually be merged, or would it be better to close it? I'm doing a bit of cleanup on my open PRs, so any feedback would be appreciated. No rush at all, and thanks for your time! |
| 5, // GP5 | ||
| 4, // GP4 | ||
| 3, // GP2 | ||
| 2, // GP1 |
There was a problem hiding this comment.
I can't tell why you've commented 4 as GP4 but then commented 3 as GP2 ?
|
I'm still not convinced that the "enhanced mode" that you've added is actually useful. If you hold down "1" and "5" at once, does your code think that 1, 2, 4 and 5 are all being pressed? |


Description:
Summary:
This Pull Request adds example code demonstrating how to use a 4x4 keypad with the Raspberry Pi Pico using C. The provided example aims to help users integrate and interact with a 4x4 matrix keypad in their projects.
Details:
Example Code:
keypad_example.c) that illustrates how to set up and use a 4x4 keypad with the Raspberry Pi Pico.Code Structure:
Documentation:
Benefits:
Additional Notes:
Related Issues:
Thank you for reviewing this example code. I look forward to any feedback and am happy to make further adjustments based on your input.