Two builds and a check · 10 of 11

A PIN code lock

Type four digits and press #: right, and a pin goes HIGH for three seconds; wrong three times, and the keypad ignores everything for ten. The same four wires as the first keypress, and forty more lines of sketch.

How it behaves

Try it here first. The code is 2580 — straight down the middle column.

A four-digit code lock
code 2580
Type the code, then #
Digits typed
0
Tries left
3
State
typing
Type 2580, then #. Try a wrong code 3 times too to see the lockout. * clears a mistake before you check it.

Four states, and the sketch below is those four states:

  • Typing. A digit is added, up to eight. A to D are ignored.
  • Cleared. * throws away what has been typed.
  • Checking. # compares the entry with the code. Right opens; wrong costs a try and starts the entry again.
  • Locked out. After three wrong codes in a row, every key is ignored for ten seconds.

The lockout is what makes a four-digit code worth having. Without it, ten thousand codes is only a long day of typing. With three tries every ten seconds, the waiting alone adds more than nine hours.

Wiring

The same four wires as the first keypress. The output is OPEN_PIN, which is the board's own LED to begin with.

What the sketch does not do

It keeps no count across a reset, so unplugging the board clears a lockout. It stores the code in plain text. Both are fine for a drawer or a puzzle box, and both are reasons not to put it on a door.

The code

pin_lock.ino

Digits are collected up to eight, * clears, # checks. The code, the number of tries, the lockout and the time the pin stays open are the four #defines at the top. Serial prints a * per digit, so the code never appears on screen.

// A four-digit code lock: type the code, press #, and a pin goes HIGH.
//
// Wiring, adapter to board (as in "The first keypress"):
//   Adapter GND -> board GND
//   Adapter VCC -> board 5V on an Uno, 3V3 on an ESP32 or ESP32-S3
//   Adapter SDA -> Uno A4, ESP32 GPIO 21, ESP32-S3 GPIO 8
//   Adapter SCL -> Uno A5, ESP32 GPIO 22, ESP32-S3 GPIO 9
//   OPEN_PIN    -> the board's LED, or an LED and 220 ohm resistor to GND
//
// Arduino IDE: install "I2CKeyPad" by Rob Tillaart from the Library
// Manager. No special Tools settings. Serial Monitor at 115200.

#include <Wire.h>
#include "I2CKeyPad.h"

#define CODE        "2580"
#define TRIES       3
#define LOCKOUT_MS  10000UL
#define OPEN_MS     3000UL

const int OPEN_PIN = LED_BUILTIN;

char keymap[19] = "DCBA#9630852*741NF";      // soft keypad
// char keymap[19] = "D#0*C987B654A321NF";   // heavy-duty keypad

I2CKeyPad keyPad(0x20);
char last = 'N';
String entry;
int triesLeft = TRIES;

void setup() {
  Serial.begin(115200);
  pinMode(OPEN_PIN, OUTPUT);
  digitalWrite(OPEN_PIN, LOW);
  Wire.begin();
  Wire.setClock(100000);
  if (!keyPad.begin()) {
    Serial.println("No keypad at 0x20 - check GND, VCC, SDA and SCL.");
    while (true) delay(1000);
  }
  keyPad.loadKeyMap(keymap);
  Serial.println("Locked. Type the code, then #.");
}

void check() {
  if (entry == CODE) {
    Serial.println("OPEN");
    digitalWrite(OPEN_PIN, HIGH);
    delay(OPEN_MS);                  // keys are ignored while open
    digitalWrite(OPEN_PIN, LOW);
    triesLeft = TRIES;
    Serial.println("Locked.");
  } else if (--triesLeft > 0) {
    Serial.print("Wrong. Tries left: ");
    Serial.println(triesLeft);
  } else {
    Serial.println("Too many tries. Locked out.");
    delay(LOCKOUT_MS);               // and while locked out
    triesLeft = TRIES;
    Serial.println("Try again.");
  }
  entry = "";
}

void loop() {
  char c = keyPad.getChar();
  if (c != last) {
    last = c;
    if (c >= '0' && c <= '9' && entry.length() < 8) {
      entry += c;
      Serial.print('*');
    } else if (c == '*') {
      entry = "";
      Serial.println(" cleared");
    } else if (c == '#') {
      Serial.println();
      check();
    }
  }
  delay(20);
}

OPEN_PIN is LED_BUILTIN, which is pin 13 on an Uno. If your board has no plain LED there, wire an LED and a 220 Ω resistor from any free pin to GND and put that pin number in instead. Never drive a lock or a relay coil straight from a pin — see the troubleshooting below.

When it does not work

The right code says Wrong

Check which characters the keypad is really sending: with the other keypad's keymap loaded, 2, 5, 8 and 0 arrive as 4, 5, 6 and B. Run the first-keypress sketch, press 2, 5, 8 and 0, and confirm each prints as itself.

Can this pin drive a door lock or a relay?

Not directly. A pin gives a few milliamps; a solenoid lock or a relay coil needs far more, and its coil kicks back when switched off. Drive it through a transistor or a relay module with its own supply, and put a diode across any coil.

After a lockout, the next key is ignored

The sketch remembers the last thing it saw so a held key does not repeat. If a key was still down when the lockout ended, release it and press again.

Is this secure?

It is a lock for a project box, not a front door. The code is in the sketch in plain text, and anyone with the board and a USB cable can read or replace it.

Where this goes next

The three checks, in order, and a sketch that works out the keymap for any keypad.

When a key is wrong

Edit this page — content/books/matrix-keypad/a-pin-code-lock.mdx

Community

Questions about this product

See what other owners have asked, and read their solutions.

This page covers several products. Choose yours to see the right discussions.

Discuss this article

Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.

Browse Modules and blocks on the forum