diff --git a/README.md b/README.md index d6809a1fc..18204e94e 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,7 @@ App|Description [hello_7segment](gpio/hello_7segment) | Use the GPIOs to drive a seven segment LED display. [hello_gpio_irq](gpio/hello_gpio_irq) | Register an interrupt handler to run when a GPIO is toggled. [dht_sensor](gpio/dht_sensor) | Use GPIO to bitbang the serial protocol for a DHT temperature/humidity sensor. +[keypad](gpio/keypad) | Use GPIO to get key pressed on a 4x4 Keypad. See also: [blink](blink), blinking an LED attached to a GPIO. diff --git a/gpio/CMakeLists.txt b/gpio/CMakeLists.txt index d1f842383..7ef00d8ae 100644 --- a/gpio/CMakeLists.txt +++ b/gpio/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory_exclude_platforms(dht_sensor host) add_subdirectory_exclude_platforms(hello_7segment host) add_subdirectory_exclude_platforms(hello_gpio_irq host) +add_subdirectory_exclude_platforms(keypad host) diff --git a/gpio/keypad/CMakeLists.txt b/gpio/keypad/CMakeLists.txt new file mode 100644 index 000000000..9833d5854 --- /dev/null +++ b/gpio/keypad/CMakeLists.txt @@ -0,0 +1,17 @@ +set(TARGET_NAME keypad) +add_executable(${TARGET_NAME} + keypad.c + ) + +# pull in common dependencies +target_link_libraries(keypad pico_stdlib) + +# Enable printing via USB serial +pico_enable_stdio_usb(${TARGET_NAME} 1) +pico_enable_stdio_uart(${TARGET_NAME} 0) + +# create map/bin/hex file etc. +pico_add_extra_outputs(${TARGET_NAME}) + +# add url via pico_set_program_url +example_auto_set_url(${TARGET_NAME}) diff --git a/gpio/keypad/README.adoc b/gpio/keypad/README.adoc new file mode 100644 index 000000000..b059a886f --- /dev/null +++ b/gpio/keypad/README.adoc @@ -0,0 +1,120 @@ += Keypad Example for Raspberry Pi Pico + +This document provides details about the 4x4 keypad example included in the larger repository of examples for Raspberry Pi Pico. This example demonstrates how to interface a 4x4 matrix keypad with the Pico and includes both simple and enhanced key detection modes. + +== Introduction + +This example shows how to use a 4x4 matrix keypad with the Raspberry Pi Pico. It has been enhanced to support detecting multiple key presses simultaneously, alongside the original single key press functionality. + +== Features + +* Simple key detection (one key press at a time) +* Enhanced key detection (multiple keys pressed simultaneously) +* Configurable maximum number of simultaneous key presses +* Mode switching via macro definition + +== Hardware Requirements + +* Raspberry Pi Pico +* 4x4 matrix keypad +* Connecting wires + +== Wiring Instructions + +Follow these wiring instructions to connect the 4x4 matrix keypad to the Raspberry Pi Pico: + +[image2] +image::pico_keypad_connection.png[Keypad Connection Diagram] + +=== Wiring Table + +The following table shows the GPIO pins used for the rows and columns of the keypad: + +[width="50%",cols="1,1,1",options="header"] +|=== +| Keypad Row/Column | GPIO Pin | Pin Number + +| Row 0 | GP9 | 9 +| Row 1 | GP8 | 8 +| Row 2 | GP7 | 7 +| Row 3 | GP6 | 6 + +| Column 0 | GP5 | 5 +| Column 1 | GP4 | 4 +| Column 2 | GP3 | 3 +| Column 3 | GP2 | 2 +|=== + +Ensure that the keypad rows and columns are connected to the GPIO pins on the Pico as indicated in the table. + +== Usage + +This example can be compiled and run to interact with the keypad. + +=== Simple Mode + +In simple mode, the `get_keypad_value` function returns a single character corresponding to the pressed key. If no key is pressed, it returns a constant value indicating no key press. + +[source,c] +---- +char get_keypad_value(); +---- + +=== Enhanced Mode + +In enhanced mode, the `get_keypad_result` function returns a `KeypadResult` structure containing the count of pressed keys and a list of those keys. + +[source,c] +---- +KeypadResult get_keypad_result(); +---- + +The `KeypadResult` structure is defined as follows: + +[source,c] +---- +typedef struct { + int count; // Number of pressed keys + char keys[MAX_MULTI_KEYS]; // Pressed keys +} KeypadResult; +---- + +== Example Output + +=== Simple Mode + +If a key is pressed, the output will be: + +[source, plain] +---- +Key 'A' pressed +---- + +If no key is pressed, the output will be: + +[source, plain] +---- +No key pressed +---- + +=== Enhanced Mode + +If multiple keys are pressed, the output will be: + +[source, plain] +---- +Bang!!! '2' key(s) are pressed. Keys: A, B +---- + +If no keys are pressed, the output will be: + +[source, plain] +---- +No key pressed +---- + +== Additional Information + +For contributing to the repository, refer to the link:../../CONTRIBUTING.md[CONTRIBUTING.md] file. + +For licensing information, see the link:../../LICENSE.TXT[LICENSE.TXT] file. diff --git a/gpio/keypad/keypad.c b/gpio/keypad/keypad.c new file mode 100644 index 000000000..c2eb0442a --- /dev/null +++ b/gpio/keypad/keypad.c @@ -0,0 +1,178 @@ +/** + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include "pico/stdlib.h" + + +#define KEYPAD_NUM_ROWS 4 +#define KEYPAD_NUM_COLUMNS 4 +#define NO_KEY_PRESSED '\0' // Just a character that unlikely be + // present in keyboards, so it can be used + // to determine if no key is pressed. +#define READ_MS_DELAY 10 // Delay between read to avoid noise + +// Enable enhanced mode to allow reading multiple keys simultaneously. +#define ENHANCED_KEYPAD + + +#ifdef ENHANCED_KEYPAD +/* + * When using the Enhanced Keypad mode, the get_keypad_value function + * returns a KeypadResult structure instead of a single character. + * + * KeypadResult includes: + * - count: The number of keys pressed (up to MAX_MULTI_KEYS). + * - keys: An array containing the pressed keys (up to MAX_MULTI_KEYS). + */ +#define MAX_MULTI_KEYS 6 // Maximum number of keys that can be pressed simultaneously. + +typedef struct { + int count; // Number of keys pressed. + char keys[MAX_MULTI_KEYS]; // Array of pressed keys. +} KeypadResult; +#endif // ENHANCED_KEYPAD + + +const uint8_t keypad_rows_pins[KEYPAD_NUM_ROWS] = { + 9, // GP9 + 8, // GP8 + 7, // GP7 + 6, // GP6 +}; + + +const uint8_t keypad_columns_pins[KEYPAD_NUM_COLUMNS] = { + 5, // GP5 + 4, // GP4 + 3, // GP2 + 2, // GP1 +}; + + +const char keypad_keys[KEYPAD_NUM_ROWS][KEYPAD_NUM_COLUMNS] = { + {'1', '2', '3', 'A'}, + {'4', '5', '6', 'B'}, + {'7', '8', '9', 'C'}, + {'*', '0', '#', 'D'}, +}; + + +void pico_keypad_init(void) { + // Initialize GPIOs + //Initialize row pins as GPIO_OUT + for (int i=0; i < KEYPAD_NUM_ROWS; i++) { + uint8_t pin_number = keypad_rows_pins[i]; + gpio_init(pin_number); + gpio_set_dir(pin_number, GPIO_OUT); + gpio_put(pin_number, 0); // Make sure GPIO_OUT is LOW + } + //Initialize column pins as GPIO_IN + for (int i=0; i < KEYPAD_NUM_COLUMNS; i++) { + uint8_t pin_number = keypad_columns_pins[i]; + gpio_init(pin_number); + gpio_set_dir(pin_number, GPIO_IN); + } +} + + +#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 + + +int main() { + stdio_init_all(); + pico_keypad_init(); + 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); + } +} diff --git a/gpio/keypad/pico_keypad_connection.png b/gpio/keypad/pico_keypad_connection.png new file mode 100644 index 000000000..083d44c7a Binary files /dev/null and b/gpio/keypad/pico_keypad_connection.png differ