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 Ω).
Pins
| Pin | What it is | Type |
|---|---|---|
| R1 | Row 1 | passive |
| R2 | Row 2 | passive |
| R3 | Row 3 | passive |
| R4 | Row 4 | passive |
| C1 | Column 1 | passive |
| C2 | Column 2 | passive |
| C3 | Column 3 | passive |
| C4 | Column 4 | passive |
The key labels follow the printed layout, row by row:
| C1 | C2 | C3 | C4 | |
|---|---|---|---|---|
| R1 | 1 | 2 | 3 | A |
| R2 | 4 | 5 | 6 | B |
| R3 | 7 | 8 | 9 | C |
| 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
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.GPIO6Any 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.
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
autoTypestring and the keypad types it by itself: each key closes forkeyHoldMs(150 ms default) with agapMspause. - 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
- The keys are push buttons in a grid; the pull-up logic is the pull-up primer.
- The scan loop is plain RPi.GPIO; a finished build is the keypad lock recipe.
- The same eight-GPIO scan appears in matrix displays and any multiplexed part.
Further reading
- Adafruit 4×4 membrane keypad — the part the datasheet models.
- RPi.GPIO documentation —
setup,PUD_UPandinput. - Adafruit: Matrix keypad — scanning rows and columns, ghosting, and diodes for large matrices.