PyRaspBeta

4×4 keypad

A 4×4 membrane keypad is sixteen momentary keys wired as a matrix: four row lines and four column lines, with a key closing its row to its column. It costs $4 and takes eight GPIOs; there is no chip inside, so the "driver" is a scan loop you write. Under the hood each key is just a push button at a crossing — the membrane's contacts are even a little resistive (about 100 Ω).

4×4 keypad

Pins

PinWhat it isType
R1Row 1passive
R2Row 2passive
R3Row 3passive
R4Row 4passive
C1Column 1passive
C2Column 2passive
C3Column 3passive
C4Column 4passive

The key labels follow the printed layout, row by row:

C1C2C3C4
R1123A
R2456B
R3789C
R4*0#D

No pin is a power pin — all eight are signal lines, and the KEYS table in main.py matches this layout.

Wiring it in circuit.py

circuit.py
from wiring import *

pi = Pi()

keypad = Keypad()

keypad.r1 >> pi.GPIO17
keypad.r2 >> pi.GPIO27
keypad.r3 >> pi.GPIO22
keypad.r4 >> pi.GPIO23
keypad.c1 >> pi.GPIO24
keypad.c2 >> pi.GPIO25
keypad.c3 >> pi.GPIO5
keypad.c4 >> pi.GPIO6

Any eight GPIOs work, in any order — just keep the wiring and the pin lists in main.py in agreement.

Driving it in main.py

Scan one row at a time: drive it low, then read the four columns (pulled up) — a low column is the pressed key.

main.py
import RPi.GPIO as GPIO
from time import sleep

ROWS, COLS = [17, 27, 22, 23], [24, 25, 5, 6]
KEYS = ["123A", "456B", "789C", "*0#D"]

GPIO.setmode(GPIO.BCM)
GPIO.setup(ROWS, GPIO.OUT, initial=GPIO.HIGH)
GPIO.setup(COLS, GPIO.IN, pull_up_down=GPIO.PUD_UP)

def scan():
    for r, row in enumerate(ROWS):
        GPIO.output(row, GPIO.LOW)
        for c, col in enumerate(COLS):
            if GPIO.input(col) == GPIO.LOW:
                GPIO.output(row, GPIO.HIGH)
                return KEYS[r][c]
        GPIO.output(row, GPIO.HIGH)
    return None

while True:
    key = scan()
    if key:
        print(f"key {key}")
    sleep(0.02)

The loop prints a held key repeatedly; remember the last key if you want one event per press. The keypad lock recipe does exactly that.

Electrical notes

  • The columns are inputs with the Pi's internal pull-ups enabled (PUD_UP, about 50 kΩ). With no key pressed every column floats to 3.3 V; a key pulled low by the driven row reads 0.
  • Membrane contacts are about 100 Ω when closed and bounce for 1–5 ms. Add a 20 ms "same key twice" check, or your own debounce, before counting presses.
  • There are no diodes in the matrix, so pressing several keys at once can produce a phantom key at a fourth crossing. Real keypads accept that (or you enforce one key at a time in software).
  • Never drive a row high while the keypad's other side touches a supply — the keypad only ever sees the GPIOs' own 3.3 V, so keep it that way.

Simulator vs real hardware

  • Click keys on the canvas while the simulation runs, or give the datafeed an autoType string and the keypad types it by itself: each key closes for keyHoldMs (150 ms default) with a gapMs pause.
  • The behaviour is sixteen ideal switches, one per key, each joining its row to its column. The keypad's contacts switch instantly — the model does not reproduce the membrane bounce, so software that would double-read on a bench may behave cleanly here.
  • The scan order and pull-ups are all software: any row/column assignment works, exactly as on hardware.
  • Real membranes wear through and need more pressure at the edges; nothing here fails that way.

Going deeper

Further reading