Skip to content

Add Example Code for 4x4 Keypad with Raspberry Pi Pico #542

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

Open
wants to merge 9 commits into
base: develop
Choose a base branch
from
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
1 change: 1 addition & 0 deletions gpio/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)
17 changes: 17 additions & 0 deletions gpio/keypad/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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})
120 changes: 120 additions & 0 deletions gpio/keypad/README.adoc
Original file line number Diff line number Diff line change
@@ -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.
178 changes: 178 additions & 0 deletions gpio/keypad/keypad.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/

#include <stdio.h>
#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);
}
}
Binary file added gpio/keypad/pico_keypad_connection.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.