A 4×4 membrane keypad is the input for door locks, safe boxes and quiz buzzers. It has no electronics inside — just a grid of switches — so the Nano scans it with eight digital pins.
This guide uses D2–D9, which sit in a neat row on the Nano. The sketch checks a PIN code: type the digits, press #, and the on-board LED lights for 3 seconds if it is right. * clears the entry.
Wiring
| Arduino Nano | 4×4 matrix membrane keypad | Wire | Notes |
|---|---|---|---|
| D9 | R1 | orange | |
| D8 | R2 | orange | |
| D7 | R3 | orange | |
| D6 | R4 | orange | |
| D5 | C1 | blue | |
| D4 | C2 | blue | |
| D3 | C3 | blue | |
| D2 | C4 | blue |
No supply — passive switch matrix part, 5 V board. The keypad has no electronics, so it works at 3.3 V or 5 V. It does need eight GPIOs; on ESP32 avoid the strapping pins (0, 2, 5, 12, 15) and the input-only pins (34–39) for the row outputs.
Board quirks
- The keypad’s 8-pin ribbon reads R1–R4 then C1–C4 from left to right (keys facing you). The eight wires line up with D9…D2 on the Nano’s right column, so a straight ribbon works.
- This leaves A0–A5 free — including A4/A5 for an I2C LCD to show the code. A6/A7 cannot scan a keypad (analog-only).
- If you run out of pins, A0–A3 work as digital pins 14–17:
byte colPins[] = {14, 15, 16, 17};. - No resistors needed — the library uses the internal pull-ups on the columns.
Code
// 4x4 membrane keypad on an Arduino Nano as a PIN-code check.
// R1-R4 → D9, D8, D7, D6; C1-C4 → D5, D4, D3, D2. Correct code + # lights the on-board LED for 3 s.
#include <Keypad.h>
const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'},
};
byte rowPins[ROWS] = {9, 8, 7, 6};
byte colPins[COLS] = {5, 4, 3, 2};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
const char CODE[] = "2580"; // change this
char entry[9];
uint8_t len = 0;
void setup() {
Serial.begin(115200);
pinMode(LED_BUILTIN, OUTPUT);
Serial.println(F("Enter code then # (* clears)"));
}
void loop() {
char key = keypad.getKey();
if (!key) return;
if (key == '*') {
len = 0;
Serial.println(F("Cleared"));
} else if (key == '#') {
entry[len] = '\0';
bool ok = strcmp(entry, CODE) == 0;
Serial.println(ok ? F("Code OK") : F("Wrong code"));
if (ok) {
digitalWrite(LED_BUILTIN, HIGH);
delay(3000);
digitalWrite(LED_BUILTIN, LOW);
}
len = 0;
} else if (len < sizeof(entry) - 1) {
entry[len++] = key;
Serial.print('*'); // don't echo the digits
Serial.println();
}
}// 4x4 membrane keypad on an Arduino Nano as a PIN-code check.
// R1-R4 → D9, D8, D7, D6; C1-C4 → D5, D4, D3, D2. Correct code + # lights the on-board LED for 3 s.
#include <Keypad.h>
const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'},
};
byte rowPins[ROWS] = {9, 8, 7, 6};
byte colPins[COLS] = {5, 4, 3, 2};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
const char CODE[] = "2580"; // change this
char entry[9];
uint8_t len = 0;
void setup() {
Serial.begin(115200);
pinMode(LED_BUILTIN, OUTPUT);
Serial.println(F("Enter code then # (* clears)"));
}
void loop() {
char key = keypad.getKey();
if (!key) return;
if (key == '*') {
len = 0;
Serial.println(F("Cleared"));
} else if (key == '#') {
entry[len] = '\0';
bool ok = strcmp(entry, CODE) == 0;
Serial.println(ok ? F("Code OK") : F("Wrong code"));
if (ok) {
digitalWrite(LED_BUILTIN, HIGH);
delay(3000);
digitalWrite(LED_BUILTIN, LOW);
}
len = 0;
} else if (len < sizeof(entry) - 1) {
entry[len++] = key;
Serial.print('*'); // don't echo the digits
Serial.println();
}
}Library: Keypad (Mark Stanley, Alexander Brevig) — compiled with Keypad 3.1.1.
Expected serial output
Enter code then # (* clears)
*
*
*
*
Code OKEnter code then # (* clears) * * * * Code OK
Common errors
Wrong keys, or some keys do nothing
Rows and columns swapped or the ribbon reversed. Press each key and print it to find the mapping.
Keypad.h: No such file or directory
Install “Keypad” by Mark Stanley and Alexander Brevig. Full fix.