Built-in project · Arduino Uno R3

Keypad lock on an Arduino Uno

A 4x4 keypad, a relay and an RGB LED on an Uno: type 1234 then # and the relay clicks the door lamp on. The whole build, an Arduino Uno and 8 more parts, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.

Teaching? Assign it to your class in one click.

Advanced About 40 minutes to build and run. Runs in your browser. Free, and no account needed.

The parts retail for about $36. On Mokxi they're free.

Step by step, with the wiring and the common mistakes: Arduino 4x4 Keypad Code Lock with a Relay

The circuit runs here once the page has loaded.

What you'll learn

  • Scanning a 4x4 keypad by rows and columns
  • Comparing typed digits to a stored code
  • Switching a lamp safely with a relay module
  • Mixing colors on an RGB LED with 220 ohm resistors
  • Giving feedback with LED colors
  • Difficulty: Advanced
  • Time: About 40 minutes
  • Board: Arduino Uno R3
  • Parts: 10

How it works

Type 1234 on the 4x4 keypad and press #. A right code turns the RGB LED green and switches the relay on for 3 seconds, which lights the yellow door lamp wired through the relay contacts. A wrong code flashes the LED red three times.

The LED is red while locked. Every key you press blinks it blue. The * key clears what you typed. A keypad is just a grid of switches, so the sketch scans rows and columns to find which key is down.

Parts list

10 parts, plus the jumper wires. They retail for about $36; on Mokxi they're free.

Kits that can build it

This starter kit has every part in the circuit. Each kit's page lists what else it can build.

Wiring table

Every connection, pin by pin, read from the circuit itself. Each row joins the pin on the left to the pin on the right, by a jumper wire or a breadboard strip.

Part and pinConnects to
Relay module pin GNDArduino Uno R3 pin GND
Relay module pin INArduino Uno R3 pin 13
Resistor, 220 Ω (3) pin 2Arduino Uno R3 pin 12
Resistor, 220 Ω (2) pin 2Arduino Uno R3 pin 11
Resistor, 220 Ω (1) pin 1Arduino Uno R3 pin 10
Keypad, 4x4 pin R1Arduino Uno R3 pin 9
Keypad, 4x4 pin R2Arduino Uno R3 pin 8
Keypad, 4x4 pin R3Arduino Uno R3 pin 7
Keypad, 4x4 pin R4Arduino Uno R3 pin 6
Keypad, 4x4 pin C1Arduino Uno R3 pin 5
Keypad, 4x4 pin C2Arduino Uno R3 pin 4
Keypad, 4x4 pin C3Arduino Uno R3 pin 3
Keypad, 4x4 pin C4Arduino Uno R3 pin 2
Relay module pin VCCArduino Uno R3 pin 5V
Relay module pin NOArduino Uno R3 pin 5V
RGB LED pin CArduino Uno R3 pin GND
LED, yellow pin CArduino Uno R3 pin GND
Resistor, 220 Ω (1) pin 2RGB LED pin R
Resistor, 220 Ω (2) pin 1RGB LED pin G
Resistor, 220 Ω (3) pin 1RGB LED pin B
Resistor, 220 Ω (4) pin 2Relay module pin COM
LED, yellow pin AResistor, 220 Ω (4) pin 1

The code

The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.

sketch.ino · Arduino Uno R3
// Keypad lock: type the code, the relay clicks, the door opens.
//
//   pins 9, 8, 7, 6   keypad rows R1 to R4
//   pins 5, 4, 3, 2   keypad columns C1 to C4
//   pin 10, 11, 12    the RGB LED's red, green and blue legs, 220 ohm each
//   pin 13            the relay module's IN (VCC to 5 V, GND to GND)
//
// The code is 1234 and # sends it. Get it right and the LED goes green and
// the relay pulls in for three seconds, which on a real door is the strike
// plate letting go. Get it wrong and the LED flashes red. * clears what you
// have typed, and every key you press blinks blue so you know it landed.
//
// # Scanning a keypad
//
// A keypad has no chip in it. Under each key is a contact that shorts one of
// four row wires to one of four column wires, so the sketch has to ask: drive
// one row low, read the four columns with their pull-ups on, and a column that
// reads low is a key held in that row. mokxi_keypad.h does that scan and
// hands back one character per press.
//
// # The relay
//
// The board pin cannot switch a door strike, a lamp or a motor on its own, and
// it should not try. The relay module takes a logic level on IN and closes a
// contact that has nothing to do with the board's 5 V. COM is wired to the
// supply and NO to the door lamp, so the lamp lights only while the relay is
// pulled in.

#include "mokxi_keypad.h"

const uint8_t ROWS[4] = {9, 8, 7, 6};
const uint8_t COLS[4] = {5, 4, 3, 2};

const int RED = 10;
const int GREEN = 11;
const int BLUE = 12;
const int RELAY = 13;

const char CODE[] = "1234";
const int CODE_LEN = 4;
const int OPEN_MS = 3000;

Keypad pad(ROWS, COLS);

char typed[8];
int count = 0;

static void setColor(int r, int g, int b) {
  digitalWrite(RED, r);
  digitalWrite(GREEN, g);
  digitalWrite(BLUE, b);
}

static void clearTyped() {
  count = 0;
  typed[0] = 0;
}

static bool matches() {
  if (count != CODE_LEN) return false;
  for (int i = 0; i < CODE_LEN; i++) {
    if (typed[i] != CODE[i]) return false;
  }
  return true;
}

static void open() {
  Serial.println("code accepted: door open");
  setColor(LOW, HIGH, LOW);
  digitalWrite(RELAY, HIGH);
  delay(OPEN_MS);
  digitalWrite(RELAY, LOW);
  setColor(HIGH, LOW, LOW);
  Serial.println("locked again");
}

static void refuse() {
  Serial.println("wrong code");
  for (int i = 0; i < 3; i++) {
    setColor(LOW, LOW, LOW);
    delay(120);
    setColor(HIGH, LOW, LOW);
    delay(120);
  }
}

void setup() {
  pinMode(RELAY, OUTPUT);
  pinMode(RED, OUTPUT);
  pinMode(GREEN, OUTPUT);
  pinMode(BLUE, OUTPUT);
  digitalWrite(RELAY, LOW);
  setColor(HIGH, LOW, LOW);
  pad.begin();
  Serial.begin(115200);
  Serial.println("Mokxi Uno: keypad lock. Type 1234 then #.");
  clearTyped();
}

void loop() {
  char c = pad.pressed();
  if (c == 0) {
    delay(5);
    return;
  }

  // A blue wink on every key, so a press that lands is a press you can see.
  setColor(LOW, LOW, HIGH);
  delay(60);
  setColor(HIGH, LOW, LOW);

  if (c == '#') {
    if (matches()) {
      open();
    } else {
      refuse();
    }
    clearTyped();
    return;
  }
  if (c == '*') {
    Serial.println("cleared");
    clearTyped();
    return;
  }
  if (count < 7) {
    typed[count++] = c;
    typed[count] = 0;
  }
  Serial.print("typed ");
  Serial.println(typed);
}

Code walkthrough

The key functions of the sketch, and what each one does.

matches sketch.ino

Checks the typed digits against CODE. It first requires exactly CODE_LEN digits, then compares them one by one. Any difference returns false.

static bool matches() {
  if (count != CODE_LEN) return false;
  for (int i = 0; i < CODE_LEN; i++) {
    if (typed[i] != CODE[i]) return false;
  }
  return true;
}

open sketch.ino

Prints a message, turns the LED green, and sets the relay pin high for OPEN_MS (3000 ms). Then it releases the relay and turns the LED red again. The code is blocking, so keys are not read while the door is open.

static void open() {
  Serial.println("code accepted: door open");
  setColor(LOW, HIGH, LOW);
  digitalWrite(RELAY, HIGH);
  delay(OPEN_MS);
  digitalWrite(RELAY, LOW);
  setColor(HIGH, LOW, LOW);
  Serial.println("locked again");
}

loop sketch.ino

Asks the keypad for a press. Each key blinks the LED blue. A # checks the code and calls open or refuse, then clears the entry. A * clears it right away. Other keys are saved, up to 7 characters.

void loop() {
  char c = pad.pressed();
  if (c == 0) {
    delay(5);
    return;
  }

  // A blue wink on every key, so a press that lands is a press you can see.
  setColor(LOW, LOW, HIGH);
  delay(60);
  setColor(HIGH, LOW, LOW);

  if (c == '#') {
    if (matches()) {
      open();
    } else {
      refuse();
    }
    clearTyped();
    return;
  }
  if (c == '*') {
    Serial.println("cleared");
    clearTyped();
    return;
  }
  if (count < 7) {
    typed[count++] = c;
  // ... 5 more lines in the editor

Troubleshooting

The usual mistakes with this circuit, and the fix for each.

  • Keys type the wrong digits or nothing happens This project
    Rows R1 to R4 go to pins 9, 8, 7, 6 and columns C1 to C4 go to pins 5, 4, 3, 2. A swapped pair gives the wrong key.
  • The relay clicks but the lamp stays off This project
    The lamp circuit needs 5 V on the relay's NO terminal and the lamp wired from COM through its resistor to ground.
  • Pressing one key reports several keys, or the wrong key. Keypad
    Match the keymap and the row and column pin order to your keypad's pinout. Without diodes, pressing three keys at once can ghost a fourth.
  • No keys are detected. Keypad
    Rows need pull-ups, or use INPUT_PULLUP, while one column is driven low at a time. The Keypad library does this for you if you pass the pins in the right order.
  • The colors are wrong or one color never lights. RGB LED
    Check whether your LED is common cathode (shared leg to ground) or common anode (shared leg to 5 V). Common anode works backwards: LOW turns a color on.
  • One color is much brighter than the others, or the LED runs too hot. RGB LED
    Use one resistor per color leg, never one for the shared leg. Typical values are 220 ohm for red and 100 to 150 ohm for green and blue on 5 V.
  • The LED is dim, burns out, or the pin reads wrong because the resistor value is off. Resistor
    Read the color bands again. A 220 ohm to 330 ohm resistor suits a typical LED on 5 V. 10k is a common pull-up or pull-down value. Check with a multimeter if unsure.
  • A pull-up or pull-down resistor is missing, so the input floats and reads random values. Resistor
    Tie the input to 5 V or ground through about 10k. Or use INPUT_PULLUP and wire the switch to ground.

Change it and keep it

Open it in the editor, change the circuit or the code, and keep your version in a free account.