-
Notifications
You must be signed in to change notification settings - Fork 838
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Example Code for 4x4 Keypad with Raspberry Pi Pico #542
base: develop
Are you sure you want to change the base?
Conversation
keypad/keypad.c
Outdated
} | ||
|
||
|
||
char get_keypad_value(void){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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_KEYPAD
macro is defined, the code will either use the simple function that returns a single pressed key or the enhanced function that returns aKeypadResult
structure. 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 theKeypadResult
structure.
#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_KEYPAD
macro, allowing the detection of multiple key presses simultaneously. - Defined
MAX_MULTI_KEYS
to specify the maximum number of keys that can be pressed at once. - Created a
KeypadResult
structure to store the count and list of pressed keys.
- Introduced a new mode via the
-
Enhanced
get_keypad_result
Function:- Modified the function to return a
KeypadResult
structure whenENHANCED_KEYPAD
is defined. - Iterated through the keypad matrix to detect multiple key presses and store them in the
KeypadResult
structure. - Implemented conditional compilation to maintain the original single key detection functionality when
ENHANCED_KEYPAD
is not defined.
- Modified the function to return a
-
Updated
main
Method:- Modified the
main
method 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_KEYPAD
is 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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. |
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.