Preview build — page text is a draft awaiting human review. Code badges come from real compiles. The flasher is real but not yet hardware-tested; the Playground is still a preview.

4×4 keypad with Arduino Nano — PIN-code entry on D2–D9

Wire a 4×4 membrane keypad to an Arduino Nano on D2–D9, read keys with the Keypad library, and check a 4-digit PIN that lights the on-board LED.

Arduino C++Verified — core avr 1.8.8, Keypad 3.1.1, 3 Nov 2026Compile-only

Community draft — report a mistake

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 NanoOnly the pins used are shown · 5 V logic4×4 matrix membrane keypadD9D8D7D6D5D4D3D2R1R2R3R4C1C2C3C4
Every connection
Arduino Nano4×4 matrix membrane keypadWireNotes
D9R1orange
D8R2orange
D7R3orange
D6R4orange
D5C1blue
D4C2blue
D3C3blue
D2C4blue

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

keypad-nano.inoArduino C++Open in PlaygroundOpen in PlaygroundFlash
// 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

Serial Monitor · 115200Output
Enter 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.

↑↓ to move · Enter to open