Membrane Keypad (4x4 / 3x4) · Astro Tech Blog

Membrane Keypad (4x4 / 3x4)

A membrane keypad is a matrix of push-button switches arranged in rows and columns, overlaid with a flexible membrane. By scanning each row-column intersection, a microcontroller can detect which key is pressed using far fewer I/O pins than individual buttons would require. A 4x4 keypad uses 8 pins for 16 keys, and a 3x4 keypad uses 7 pins for 12 keys. These keypads are widely used for PIN entry, menu navigation, and control interfaces.

Membrane keypad

For this interfacing you need the following components:

  • Arduino board (Uno, Nano, Mega, etc.)
  • 4x4 or 3x4 membrane keypad
  • Breadboard and jumper wires (female-to-female recommended)
  • USB cable to connect Arduino to your computer
  • (Optional) I2C LCD 16x2 to display key presses

Schematic

Connect the membrane keypad to the Arduino as follows:

4x4 Keypad            Arduino
-----------           -------
Pin 1 (R1)    -->     Digital Pin 9
Pin 2 (R2)    -->     Digital Pin 8
Pin 3 (R3)    -->     Digital Pin 7
Pin 4 (R4)    -->     Digital Pin 6
Pin 5 (C1)    -->     Digital Pin 5
Pin 6 (C2)    -->     Digital Pin 4
Pin 7 (C3)    -->     Digital Pin 3
Pin 8 (C4)    -->     Digital Pin 2

The pinout order varies by manufacturer. Most 4x4 keypads use the 8-pin single-row header with pins 1–8 arranged left to right (when the keys face you). Pins 1–4 are typically the rows and pins 5–8 the columns, but verify with your specific keypad’s datasheet or use a multimeter to confirm.

3x4 keypad wiring

A 3x4 keypad has 7 pins (4 rows + 3 columns):

Keypad PinArduino Pin
R19
R28
R37
R46
C15
C24
C33

Pin Map

4x4 keypad (8 pins)

Keypad PinLabelArduino Pin
1Row 19
2Row 28
3Row 37
4Row 46
5Column 15
6Column 24
7Column 33
8Column 42

Key layout (4x4)

[1] [2] [3] [A]
[4] [5] [6] [B]
[7] [8] [9] [C]
[*] [0] [#] [D]

Key layout (3x4)

[1] [2] [3]
[4] [5] [6]
[7] [8] [9]
[*] [0] [#]

Install necessary Library

Install the Keypad library by Mark Stanley, Alexander Brevig via the Library Manager (Tools > Manage Libraries).

Alternatively, using arduino-cli:

arduino-cli lib install "Keypad"

Code with complete explanation

This sketch reads key presses from a 4x4 membrane keypad and prints them to the Serial Monitor. It also demonstrates debouncing, key hold detection, and a simple password check.

#include <Keypad.h>

const byte ROWS = 4;
const byte COLS = 4;

// 4x4 key layout
char keys[ROWS][COLS] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};

// For 3x4 keypad, use:
// const byte ROWS = 4;
// const byte COLS = 3;
// char keys[ROWS][COLS] = {
//   {'1', '2', '3'},
//   {'4', '5', '6'},
//   {'7', '8', '9'},
//   {'*', '0', '#'}
// };

// Arduino pins connected to keypad rows and columns
byte rowPins[ROWS] = {9, 8, 7, 6};
byte colPins[COLS] = {5, 4, 3, 2};

Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);

// Password verification example
const String PASSWORD = "1234A";
String entered = "";

void setup()
{
  Serial.begin(9600);
  Serial.println("Membrane Keypad Test");
  Serial.println("Press keys to test. Enter password (1234A) to unlock.");
  Serial.println();

  // Optional: set a custom hold time (default 500 ms)
  keypad.setHoldTime(300);

  // Register event listeners
  keypad.addEventListener(keypadEvent);
}

void loop()
{
  char key = keypad.getKey();

  if (key)
  {
    Serial.print("Key pressed: ");
    Serial.println(key);

    // Accumulate for password
    entered += key;

    // Check password on # press
    if (key == '#')
    {
      if (entered.substring(0, entered.length() - 1) == PASSWORD)
      {
        Serial.println("ACCESS GRANTED");
      }
      else
      {
        Serial.println("ACCESS DENIED");
      }

      entered = "";
    }

    // Clear on * press
    if (key == '*')
    {
      entered = "";
      Serial.println("Entry cleared");
    }
  }
}

// Event listener for key press, release, and hold
void keypadEvent(KeypadEvent key)
{
  switch (keypad.getState())
  {
    case PRESSED:
      Serial.print("Event: ");
      Serial.print(key);
      Serial.println(" PRESSED");
      break;

    case HOLD:
      Serial.print("Event: ");
      Serial.print(key);
      Serial.println(" HELD");
      break;

    case RELEASED:
      Serial.print("Event: ");
      Serial.print(key);
      Serial.println(" RELEASED");
      break;
  }
}

Code breakdown

  • #include <Keypad.h> — includes the Keypad library for matrix scanning and debouncing.
  • makeKeymap(keys) — converts the 2D char array into a format the library can scan.
  • Keypad keypad(map, rowPins, colPins, rows, cols) — creates a Keypad object with the key layout, row pins, column pins, and dimensions.
  • keypad.getKey() — returns the character of the key currently pressed, or NO_KEY (null character) if no key is pressed. This is non-blocking.
  • keypad.addEventListener(function) — registers a callback that fires on PRESSED, HOLD, and RELEASED events.
  • keypad.getState() — returns the current event state (PRESSED, HOLD, RELEASED) when called inside an event listener.
  • keypad.setHoldTime(ms) — sets how long a key must be held before a HOLD event fires (default 500 ms).

Reading multiple simultaneous keys

The Keypad library supports two-key rollover but not full n-key rollover. For most membrane keypads, pressing more than two keys simultaneously causes ghosting. Use the library’s built-in ghosting detection:

keypad.setDebounceTime(50); // Set debounce time in ms

Interfacing with an I2C LCD

To display key presses on a 16x2 LCD:

#include <Keypad.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);

// ... keypad setup as above ...

void setup()
{
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("Enter PIN:");
}

void loop()
{
  char key = keypad.getKey();

  if (key)
  {
    lcd.setCursor(0, 1);
    lcd.print("Key: ");
    lcd.print(key);
  }
}

Steps to perform this interfacing

  1. Identify the pinout of your keypad. For a 4x4 keypad with an 8-pin header, pins are typically numbered left to right when looking at the keypad with keys facing you.
  2. Connect the keypad pins to the Arduino digital pins as defined in the code.
  3. Install the Keypad library via the Library Manager.
  4. Copy the code into the Arduino IDE.
  5. If using a 3x4 keypad, uncomment the 3x4 key layout and change COLS to 3 and colPins accordingly.
  6. Select the correct board and port (Tools > Board and Tools > Port).
  7. Upload the sketch to the Arduino.
  8. Open the Serial Monitor (Tools > Serial Monitor, set baud rate to 9600).
  9. Press keys on the keypad — observe the key character and event type printed.
  10. Test the password feature: enter 1234A then # — you should see “ACCESS GRANTED”.

Determining the pinout

If you are unsure of your keypad’s pinout, use a multimeter in continuity mode:

  1. Press and hold the first key (top-left).
  2. Touch one probe to pin 1 of the header.
  3. Touch the other probe to each remaining pin in sequence.
  4. When the multimeter beeps, you have identified the row and column pins for that key.
  5. Repeat for other keys to map the full matrix.

Caution

  • Pinout varies by manufacturer: There is no universal standard for membrane keypad pinouts. Pins 1–8 may map to rows then columns, columns then rows, or an interleaved pattern. Always verify with a multimeter or the datasheet before concluding your wiring is correct.
  • Ghosting: When three or more keys are pressed simultaneously in a certain pattern, the matrix can report a false key press (ghosting). The Keypad library includes basic ghost detection — if you encounter ghosting, use keypad.setDebounceTime() and add series diodes on each row or column for hardware-based n-key rollover.
  • Debouncing: Mechanical switches in membrane keypads bounce for 5–20 ms after contact. The Keypad library handles debouncing internally with a default debounce time of 10 ms. Increase it with keypad.setDebounceTime(ms) if you see double-triggers.
  • Pull-up resistors: The Keypad library uses INPUT_PULLUP internally on column pins by default, so no external pull-up resistors are needed. If you wire the keypad with columns as outputs and rows as inputs, configure the library accordingly.
  • Moisture and dust: Membrane keypads are not sealed against liquids. Spills can cause short circuits between layers. If used outdoors or in a kitchen, place the keypad behind a protective acrylic or polycarbonate panel.
  • Ribbon cable strain: The thin ribbon cable is fragile. Avoid bending it sharply at the header junction — repeated flexing will break the traces. Use a right-angle header or strain relief if the keypad is frequently disconnected.