Welcome to the next tutorial of our raspberry pi four programming course. Previously, we discovered how to establish a wireless connection between a Pi 4 and an ESP32. However, this post will show you how simple it is to attach a keypad to a Pi 4 and put it to use in several situations. Many individuals use the popular Raspberry Pi as a development platform for their unique creations. In projects based on the Raspberry Pi, however, it is common for users to need help finding a straightforward method to provide input.

There are a lot of approaches, but many need to be easier to use, more expensive, or error-prone. Input devices like keys, buttons, and switches are often employed in our work. One GPIO pin must interface a single button, key, or switch with the microcontroller. However, interfacing many keys (nine, twelve, sixteen, etc.) requires many general-purpose input/output (GPIO) pins on a microcontroller, resulting in their loss. This article explains how to interface a small keyboard to your Pi 4 projects, offering users a simple and effective means of interacting with the system.

Components

  • Raspberry Pi

  • 4X4 Keypad Membranes

  • Breadboard

  • Connecting Wires

With a Raspberry Pi, users can choose from various input methods. One option is to make use of a 16-button keypad consisting of the standard 0–9 numeric keypad plus several extras:

Interface 4x4 Keypad With raspberry Pi 4. keypad with raspberry pi 4 keypad rpi4, keypad with rpi4, rpi4 keypad

The Basics of the Keyboard

A keypad's plastic construction and lower manufacturing costs make it a more affordable alternative to touchscreens.

A 4x4 keypad can either be integrated within a product or used as a peripheral to facilitate user authentication via personal identification number (PIN). It is generally agreed upon among hardware and software developers that a mechanical keypad's underlying mechanism is fixed.

When working with a 4x4 keypad, it is helpful to consider it a matrix of buttons. The eight connections in a 4x4 keypad are comprised of the row's four and the subsequent columns' four.

Interface 4x4 Keypad With raspberry Pi 4. keypad with raspberry pi 4 keypad rpi4, keypad with rpi4, rpi4 keypad

Membrane keypads can be found in various sizes, including 4 by 3 and 4 by 4. According to the diagram above, a 4 by 4 keypad membrane has its first 4 pins devoted to its rows and its second 4 pins dedicated to its columns. To reduce the need for pins, they are laid out in a matrix pattern, and a membrane switch is used internally.

Interface 4x4 Keypad With raspberry Pi 4. keypad with raspberry pi 4 keypad rpi4, keypad with rpi4, rpi4 keypad

Any microcontroller's GPIO may be used to power this component; thus, there's no need for an additional power supply. A pulse must be sent from the Raspberry Pi to all four columns of the Keypad to determine which button was pressed. If the user pushes a button associated with the currently pulled high line, the column associated with that line will be pushed high.

The pressed button can be identified by deciphering the sequence of lines and columns. When a user hits the B button in the second row of the fourth row, Pi 4 will send a pulse to the second line and then see which of the four rows was pulled high to determine which button was pressed.

Interface 4x4 Keypad With raspberry Pi 4. keypad with raspberry pi 4 keypad rpi4, keypad with rpi4, rpi4 keypad

The graphic above depicts the reasoning behind how we will interpret the keys pressed on the Keypad. As indicated, the membrane switches are laid out in a matrix.

  • Without a key press, the four columns (C1, C2, C3, and C4) are raised to their highest possible positions.

  • A LOW pulse is sent to each row (R1, R2, R3, and R4) in the same manner as if the corresponding pin were connected to GND. Each column's switches are then checked individually to see if anything is pulled low.

  • If the key "1" were hit in the preceding example, the column (C1) would be "shorted" to the ground, resulting in a "LOW" reading. Afterward, it jumps to the following column and continues doing so until it reaches the end.

  • After that, we verify each column in the next row (R4) until we reach the end of the process.

  • Following the iteration of each row, we set it back to High.

Keep these ideas in mind while you examine the diagram.

  • Do not worry about the symbol for a 10K ohm resistor; I only included it to prevent our GPIO from shorting out to the ground.

  • We may swap or flip the data by setting the columns low and the rows high with a Pulse. This can be done in two ways.

The functionality of this is demonstrated in the Code section below.

Keyboard to Raspberry Pi 4 Connection

This kind of Keypad does not require battery power to function. You can easily link the Keypad's eight data lines to the Pi's GPIO pins:

Interface 4x4 Keypad With raspberry Pi 4. keypad with raspberry pi 4 keypad rpi4, keypad with rpi4, rpi4 keypad

Like the image up top, I used a monochromatic color palette. The rows are denoted by the blue connections, while the orange ones show the columns.

Short Code Sample

After making the necessary connections described above, the next step is to run a test program that outputs the Keypad's button push to the Pi 4's console.

Interface 4x4 Keypad With raspberry Pi 4. keypad with raspberry pi 4 keypad rpi4, keypad with rpi4, rpi4 keypad

# GPIO setup and imports omitted

def readLine(line, characters):

GPIO.output(line, GPIO.HIGH)

if(GPIO.input(C1) == 1):

         print(characters[0])

if(GPIO.input(C2) == 1):

             print(characters[1])

if(GPIO.input(C3) == 1):

         print(characters[2])

if(GPIO.input(C4) == 1):

         print(characters[3])

GPIO.output(line, GPIO.LOW)

try:

while True:

         readLine(L1, ["1","2","3","A"])

         readLine(L2, ["4","5","6","B"])

         readLine(L3, ["7","8","9","C"])

         readLine(L4, ["*","0","#","D"])

         time.sleep(0.1)

except KeyboardInterrupt:

print("\nApplication stopped!")

You can see that the test program has a function labeled readLine. To determine which buttons were depressed when the line was pushed high, the readLine function sends the pulse above to a single line. All four rows are just made up of a repetition of this. The approach also requires a dictionary of button-to-symbol correspondences.

Interface 4x4 Keypad With raspberry Pi 4. keypad with raspberry pi 4 keypad rpi4, keypad with rpi4, rpi4 keypad

You can think of this code as a basic demo. You can't even press and hold a button and have it register that. Each pulse it transmits on the output line will identify a new keystroke. Below is a program that can accurately identify individual key presses and use them to activate a basic code lock.

Interface 4x4 Keypad With raspberry Pi 4. keypad with raspberry pi 4 keypad rpi4, keypad with rpi4, rpi4 keypad

Most low-end keypads have the same functionality. There are four of everything. To figure out which button was pressed, send a pulse down each line and examine each column.

While writing the code for a basic app is simple, adding more complicated features might take a lot more time.

Example 2

import RPi.GPIO as GPIO

import time

L1 = 5

L2 = 6

L3 = 13

L4 = 19

C1 = 12

C2 = 16

C3 = 20

C4 = 21

GPIO.setwarnings(False)

GPIO.setmode(GPIO.BCM)

GPIO.setup(L1, GPIO.OUT)

GPIO.setup(L2, GPIO.OUT)

GPIO.setup(L3, GPIO.OUT)

GPIO.setup(L4, GPIO.OUT)

GPIO.setup(C1, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

GPIO.setup(C2, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

GPIO.setup(C3, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

GPIO.setup(C4, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

def readLine(line, characters):

    GPIO.output(line, GPIO.HIGH)

    if(GPIO.input(C1) == 1):

        print(characters[0])

    if(GPIO.input(C2) == 1):

        print(characters[1])

    if(GPIO.input(C3) == 1):

        print(characters[2])

    if(GPIO.input(C4) == 1):

        print(characters[3])

    GPIO.output(line, GPIO.LOW)

try:

    while True:

        readLine(L1, ["1","2","3","A"])

        readLine(L2, ["4","5","6","B"])

        readLine(L3, ["7","8","9","C"])

        readLine(L4, ["*","0","#","D"])

        time.sleep(0.1)

except KeyboardInterrupt:

    print("\nApplication stopped!")

Complete code

import RPi.GPIO as GPIO

import time

L1 = 5

L2 = 6

L3 = 13

L4 = 19

C1 = 12

C2 = 16

C3 = 20

C4 = 21

keypadPressed = -1

secretCode = "4789"

input = ""

GPIO.setwarnings(False)

GPIO.setmode(GPIO.BCM)

GPIO.setup(L1, GPIO.OUT)

GPIO.setup(L2, GPIO.OUT)

GPIO.setup(L3, GPIO.OUT)

GPIO.setup(L4, GPIO.OUT)

GPIO.setup(C1, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

GPIO.setup(C2, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

GPIO.setup(C3, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

GPIO.setup(C4, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

def keypadCallback(channel):

    global keypadPressed

    if keypadPressed == -1:

        keypadPressed = channel

GPIO.add_event_detect(C1, GPIO.RISING, callback=keypadCallback)

GPIO.add_event_detect(C2, GPIO.RISING, callback=keypadCallback)

GPIO.add_event_detect(C3, GPIO.RISING, callback=keypadCallback)

GPIO.add_event_detect(C4, GPIO.RISING, callback=keypadCallback)

def setAllLines(state):

    GPIO.output(L1, state)

    GPIO.output(L2, state)

    GPIO.output(L3, state)

    GPIO.output(L4, state)

def checkSpecialKeys():

    global input

    pressed = False

    GPIO.output(L3, GPIO.HIGH)

    if (GPIO.input(C4) == 1):

        print("Input reset!");

        pressed = True

    GPIO.output(L3, GPIO.LOW)

    GPIO.output(L1, GPIO.HIGH)

    if (not pressed and GPIO.input(C4) == 1):

        if input == secretCode:

            print("Code correct!")

            # TODO: Unlock a door, turn a light on, etc.

        else:

            print("Incorrect code!")

        pressed = True

    GPIO.output(L3, GPIO.LOW)

    if pressed:

        input = ""

    return pressed

def readLine(line, characters):

    global input

    # We have to send a pulse on each line to

    # detect button presses

    GPIO.output(line, GPIO.HIGH)

    if(GPIO.input(C1) == 1):

        input = input + characters[0]

    if(GPIO.input(C2) == 1):

        input = input + characters[1]

    if(GPIO.input(C3) == 1):

        input = input + characters[2]

    if(GPIO.input(C4) == 1):

        input = input + characters[3]

    GPIO.output(line, GPIO.LOW)

try:

    while True:

        if keypadPressed != -1:

            setAllLines(GPIO.HIGH)

            if GPIO.input(keypadPressed) == 0:

                keypadPressed = -1

            else:

                time.sleep(0.1)

        else:

            if not checkSpecialKeys():

                readLine(L1, ["1","2","3","A"])

                readLine(L2, ["4","5","6","B"])

                readLine(L3, ["7","8","9","C"])

                readLine(L4, ["*","0","#","D"])

                time.sleep(0.1)

            else:

                time.sleep(0.1)

except KeyboardInterrupt:

    print("\nApplication stopped!")

Programming using interrupt

You may have noticed that the "while" loop we used above is polling for each row of our Keypad. This is OK for a basic project, but it may not function properly if your project requires interaction with a more complex system, such as a GUI.

The other option is to utilize a library that relies on "interrupts," allowing us to assign a different event controller to each key on our Keypad. The Pi 4  would be alerted to a click on the membrane switch or interrupted.

The following code will walk you through the process step by step. You can see that the code that iteratively scans each row no longer uses polling while loop. You will receive feedback whenever the button is pressed or released by pressing the number one on your Keypad.

Interface 4x4 Keypad With raspberry Pi 4. keypad with raspberry pi 4 keypad rpi4, keypad with rpi4, rpi4 keypad

import RPi.GPIO as GPIO

import time

def event_callback(pin):

    value = GPIO.input(pin)

    print(f"pin :: {pin}, value is {value}")

if __name__ == '__main__':

    button_pin = 23

    row_pin = 17

    GPIO.setmode(GPIO.BCM)

    GPIO.setwarnings(False)

    GPIO.setup(row_pin, GPIO.OUT)

    GPIO.setup(button_pin, GPIO.IN, pull_up_down = GPIO.PUD_UP)

    GPIO.output(row_pin, GPIO.LOW)

    # events can be GPIO.RISING, GPIO.FALLING, or GPIO.BOTH

    GPIO.add_event_detect(button_pin, GPIO.BOTH,

                          callback=event_callback,

                          bouncetime=300)

    try:

        time.sleep(1000)

    except KeyboardInterrupt:

        GPIO.cleanup()

Please enter the following into your terminal to execute this code. When I press the switch, its value drops to zero, and when I let go of it, it jumps to one.

Interface 4x4 Keypad With raspberry Pi 4. keypad with raspberry pi 4 keypad rpi4, keypad with rpi4, rpi4 keypad

Programming using pad4pi interrupt package

With this knowledge in hand, I searched for a library that provides a similar capability. I came across pad4pi in the pypi repository, which does the trick—type in the following command to set it up on your Raspberry Pi.

Interface 4x4 Keypad With raspberry Pi 4. keypad with raspberry pi 4 keypad rpi4, keypad with rpi4, rpi4 keypad

pip install pad4pi

This is the test script I eventually came up with afterward. Check out the source and sample test scripts on the library's main page.

Interface 4x4 Keypad With raspberry Pi 4. keypad with raspberry pi 4 keypad rpi4, keypad with rpi4, rpi4 keypad

#!/usr/bin/python

from pad4pi import rpi_gpio

import time

KEYPAD = [

    [1, 2, 3, "A"],

    [4, 5, 6, "B"],

    [7, 8, 9, "C"],

    ["*", 0, "#", "D"]

]

ROW_PINS = [17, 27, 22, 5] # BCM numbering

COL_PINS = [23, 24, 25, 16] # BCM numbering

def print_key(key):

    print(f"Received key from interrupt:: {key}")

try:

    factory = rpi_gpio.KeypadFactory()

    keypad = factory.create_keypad(keypad=KEYPAD,row_pins=ROW_PINS, col_pins=COL_PINS) # makes assumptions about keypad layout and GPIO pin numbers

    Keypad.registerKeyPressHandler(print_key)

    print("Press buttons on your keypad. Ctrl+C to exit.")

    while True:

        time.sleep(1)

except KeyboardInterrupt:

    print("Goodbye")

finally:

    keypad.cleanup()

  • Import required modules on lines 3 and 4.

  • GPIO pins and rows are defined on lines 6-14.

  • A toggle activates the callback feature on the Keypad, located at lines 16–18.

  • Initialization script for pad4pi and callback handler registration lines 19–31.

Here is the output of this program.

Interface 4x4 Keypad With raspberry Pi 4. keypad with raspberry pi 4 keypad rpi4, keypad with rpi4, rpi4 keypad

Strategies for Creating a 4x4 Keypad Circuit

Keyboard Debouncing

The hardware diagrams call for almost no more parts, and the firmware is based on a straightforward technique that any newbie can quickly grasp. Pay attention to these two details if you really care about giving people a pleasant time while using the Keypad. These images demonstrate the use of a capacitor for debouncing in hardware.

Interface 4x4 Keypad With raspberry Pi 4. keypad with raspberry pi 4 keypad rpi4, keypad with rpi4, rpi4 keypad

The extra pulse that a button may send to the input as it is released is one of the most typical problems with a mechanical keypad. The button's spring mechanism is responsible for this behavior. As a result, it's common for the firmware to save conflicting settings for the same button. Debouncing is used to prevent the Keypad from being read incorrectly. This can be accomplished mechanically by installing a capacitor to block the after-button-release micro pulses.

Instead, firmware writers can opt to use software debouncing. The firmware now filters out the infinitesimally brief pulses from samples that can never be activated by human contact instead of examining each individual triggering input. It's also useful for keeping the Keypad traces free of noisy signals that could couple through the background electricity. To avoid such problems, correct design principles must be established.

Conclusion

This article has shown how a basic keypad can be connected to Pi 4 to give users a quick and easy way to enter data and communicate with their own Raspberry Pi-based applications. A small number of digital I/O pins can power the Keypad. Since the key matrix only comprises push buttons, the Raspberry Pi is not required to provide power to the device. Every Keypad's internal matrix row receives pulses from the Raspberry Pi 4. When a user presses a button, it closes a contact that links a specific row to a particular column. To determine which key the user has pressed, the Raspberry Pi monitors the column signals and responds accordingly. Any language compatible with a Pi 4 can accomplish this method. Following this, we'll get into the specifics of connecting a joystick mcp3008 to a Raspberry Pi 4.