DIY ELECTRONICSTR

← All projects

RFID Card Door Lock

Intermediate60 min

A door lock that opens with a card or key fob you have introduced: the RC522 reader reads the card's number, and if it is known the green LED lights up, a short beep sounds and the servo turns the latch and opens the door for 5 seconds; an unknown card lights the red LED and sounds a long beep. The first card you scan becomes the master card: scanning it opens adding mode for 10 seconds, and a new card scanned meanwhile is added, a known one removed. The cards are kept in the Arduino's EEPROM memory, so they are not forgotten when the power goes. It teaches talking to a module over SPI, comparing card numbers, keeping a small list in EEPROM, and letting a mode close by itself. Install "MFRC522" from the Library Manager; Servo and EEPROM come with the Arduino IDE. This is a learning project; do not use it as a real door's only lock.

Build it step by step in the app

What you need

Wiring steps

  1. 1

    Connect the power rails (5V and GND)

    Connect the power rails (5V and GND)

    Plug a red male-male jumper wire into the 5V pin on the Arduino's power header and connect its other end to the breadboard's top red (+) rail. Plug a black wire into one of the GND pins on the same header and connect its other end to the top blue (−) rail. The servo, the buzzer and the LEDs are powered from these rails. The RC522 is not: it runs on 3.3V.

    • Arduino 5V → the top red (+) rail (red wire)
    • Arduino GND → the top blue (−) rail (black wire)
  2. 2

    Connect the RC522 reader

    Connect the RC522 reader

    Most kits ship the reader's 8-pin header loose; you may have to solder it to the board first. Push the female ends of male-female wires onto the pins and connect them all straight to the Arduino: SDA to 10, SCK to 13, MOSI to 11, MISO to 12, RST to 9, GND to the GND pin on the digital header (next to 13), and 3.3V to the 3.3V pin on the power header. IRQ stays empty. CAREFUL: do not connect the RC522 to 5V, it can break the reader; use the 3.3V pin. Pins 13, 12 and 11 are the Uno's SPI pins and cannot be changed.

    • Arduino pin 10 → RC522 SDA (yellow wire)
    • Arduino pin 13 → RC522 SCK (green wire)
    • Arduino pin 11 → RC522 MOSI (blue wire)
    • Arduino pin 12 → RC522 MISO (purple wire)
    • Arduino pin 9 → RC522 RST (white wire)
    • Arduino GND → RC522 GND (black wire)
    • Arduino 3.3V → RC522 3.3V (red wire)
  3. 3

    Connect the servo

    Connect the servo

    Push three male-male wires into the three-hole plug at the end of the SG90's cable. Connect the one facing the brown (GND) wire to the top (−) rail, the one facing the red (5V) wire to the top (+) rail, and the one facing the orange (signal) wire straight to the Arduino's pin 6 (SERVO_PIN 6). Fit the servo's single arm after the code has turned the servo to 0° at start-up: at 0° the arm should hold the latch shut, at 90° it should free it.

    • servo brown wire (GND) → the top blue (−) rail (black wire)
    • servo red wire (5V) → the top red (+) rail (red wire)
    • Arduino pin 6 → servo orange wire (signal) (orange wire)
  4. 4

    Add and wire the buzzer

    Add and wire the buzzer

    Plug the passive buzzer's + leg into column 15 in the top half and its other leg into column 16; the + leg is usually the longer one and the body has a + mark. Connect the Arduino's pin 8 to column 15 with an orange wire (BUZZER_PIN 8). Connect column 16 to the top (−) rail with a short black wire.

    • buzzer + leg → column 15, top half
    • buzzer − leg → column 16, top half
    • Arduino pin 8 → column 15, top half (orange wire)
    • column 16, top half → the top blue (−) rail (black wire)
  5. 5

    Add the green and red LEDs with their resistors

    Add the green and red LEDs with their resistors

    Plug the green LED's long leg (+) into column 34 in the top half and its short leg (−) into column 35; put a 220 Ω resistor from column 35 to the top (−) rail. Connect the Arduino's pin 5 to column 34 with a green wire (GREEN_LED 5). Plug in the red LED the same way: long leg in column 40, short leg in column 41, and the second 220 Ω resistor from column 41 to the (−) rail. Connect the Arduino's pin 4 to column 40 with a blue wire (RED_LED 4).

    • green LED long leg (+) → column 34, top half
    • green LED short leg (−) → column 35, top half
    • red LED long leg (+) → column 40, top half
    • red LED short leg (−) → column 41, top half
    • green LED's resistor (leg 1) → column 35, top half
    • green LED's resistor (leg 2) → the top blue (−) rail
    • red LED's resistor (leg 1) → column 41, top half
    • red LED's resistor (leg 2) → the top blue (−) rail
    • Arduino pin 5 → column 34, top half (green wire)
    • Arduino pin 4 → column 40, top half (blue wire)

Arduino sketch

// Install from the Library Manager:
// "MFRC522" (GithubCommunity)
#include <SPI.h>
#include <MFRC522.h>
#include <Servo.h>
#include <EEPROM.h>

// The RC522's SDA and RST pins; on an Uno
// SCK, MOSI, MISO are 13, 11, 12
const int SS_PIN = 10;
const int RST_PIN = 9;
const int SERVO_PIN = 6;
const int GREEN_LED = 5;
const int RED_LED = 4;
const int BUZZER_PIN = 8;

// The servo's locked and open angles
const int LOCKED_ANGLE = 0;
const int OPEN_ANGLE = 90;
// How long the door stays open (ms)
const unsigned long OPEN_TIME = 5000;
// How long adding cards lasts (ms)
const unsigned long ADD_TIME = 10000;

// EEPROM: byte 0 a mark, byte 1 the card
// count, then 4 bytes per card number.
// The first card is the master card.
const byte MAX_CARDS = 10;
// Change this number and upload to erase
// every card
const byte EEPROM_MARK = 77;

MFRC522 rfid(SS_PIN, RST_PIN);
Servo lock;

byte cardCount = 0;
bool addMode = false;
unsigned long addStart = 0;

void beep(int ms) {
  tone(BUZZER_PIN, 2000);
  delay(ms);
  noTone(BUZZER_PIN);
}

// Writes a card's number to uid if read
bool readCard(byte uid[4]) {
  if (!rfid.PICC_IsNewCardPresent()) return false;
  if (!rfid.PICC_ReadCardSerial()) return false;
  for (byte i = 0; i < 4; i++) {
    uid[i] = rfid.uid.uidByte[i];
  }
  rfid.PICC_HaltA();
  return true;
}

void printCard(byte uid[4]) {
  Serial.print("Card:");
  for (byte i = 0; i < 4; i++) {
    Serial.print(uid[i] < 0x10 ? " 0" : " ");
    Serial.print(uid[i], HEX);
  }
  Serial.println();
}

// Its place if known (0: master), else -1
int findCard(byte uid[4]) {
  for (byte k = 0; k < cardCount; k++) {
    bool same = true;
    for (byte i = 0; i < 4; i++) {
      if (EEPROM.read(2 + k * 4 + i) != uid[i]) same = false;
    }
    if (same) return k;
  }
  return -1;
}

void addCard(byte uid[4]) {
  for (byte i = 0; i < 4; i++) {
    EEPROM.update(2 + cardCount * 4 + i, uid[i]);
  }
  cardCount++;
  EEPROM.update(0, EEPROM_MARK);
  EEPROM.update(1, cardCount);
}

// Move the last card into the gap
void removeCard(int k) {
  cardCount--;
  for (byte i = 0; i < 4; i++) {
    EEPROM.update(2 + k * 4 + i, EEPROM.read(2 + cardCount * 4 + i));
  }
  EEPROM.update(1, cardCount);
}

void openDoor() {
  digitalWrite(GREEN_LED, HIGH);
  beep(100);
  lock.write(OPEN_ANGLE);
  delay(OPEN_TIME);
  lock.write(LOCKED_ANGLE);
  digitalWrite(GREEN_LED, LOW);
  Serial.println("Door locked.");
}

void deny() {
  digitalWrite(RED_LED, HIGH);
  beep(600);
  delay(400);
  digitalWrite(RED_LED, LOW);
}

void setup() {
  Serial.begin(9600);
  pinMode(GREEN_LED, OUTPUT);
  pinMode(RED_LED, OUTPUT);
  pinMode(BUZZER_PIN, OUTPUT);
  lock.attach(SERVO_PIN);
  lock.write(LOCKED_ANGLE);
  SPI.begin();
  rfid.PCD_Init();

  // A silent reader reads as version 0x00
  // or 0xFF
  byte version = rfid.PCD_ReadRegister(MFRC522::VersionReg);
  if (version == 0x00 || version == 0xFF) {
    Serial.println("RC522 not found, check the wires.");
    while (true) {
      digitalWrite(RED_LED, !digitalRead(RED_LED));
      delay(300);
    }
  }

  if (EEPROM.read(0) == EEPROM_MARK) {
    cardCount = min(EEPROM.read(1), MAX_CARDS);
  }
  if (cardCount == 0) {
    Serial.println("Scan the master card.");
  } else {
    Serial.print("Lock ready, cards known: ");
    Serial.println(cardCount);
  }
}

void loop() {
  // Adding mode closes by itself
  if (addMode && millis() - addStart >= ADD_TIME) {
    addMode = false;
    digitalWrite(GREEN_LED, LOW);
    Serial.println("Adding mode closed.");
  }

  byte uid[4];
  if (!readCard(uid)) return;
  printCard(uid);

  if (cardCount == 0) {
    addCard(uid);
    Serial.println("Master card saved.");
    beep(100);
    delay(100);
    beep(100);
    return;
  }

  int k = findCard(uid);
  if (k == 0) {
    // The master card opens adding mode
    addMode = true;
    addStart = millis();
    digitalWrite(GREEN_LED, HIGH);
    beep(100);
    Serial.println("Adding mode: scan a card to add or remove.");
  } else if (addMode) {
    addMode = false;
    digitalWrite(GREEN_LED, LOW);
    if (k > 0) {
      removeCard(k);
      Serial.println("Card removed.");
    } else if (cardCount >= MAX_CARDS) {
      Serial.println("The card list is full.");
    } else {
      addCard(uid);
      Serial.println("Card added.");
    }
    beep(100);
  } else if (k > 0) {
    Serial.println("Access granted: door opening.");
    openDoor();
  } else {
    Serial.println("This card is not known.");
    deny();
  }
}

What the Serial Monitor shows

SERIAL MONITOR · 9600 BAUD
Scan the master card.
Card: DE AD BE EF
Master card saved.
Card: 04 7B 2E 05
This card is not known.
Card: DE AD BE EF
Adding mode: scan a card to add or remove.
Card: 3A F2 11 9C
Card added.
Card: 3A F2 11 9C
Access granted: door opening.
Door locked.

If a wire is loose

SERIAL MONITOR · 9600 BAUD
RC522 not found, check the wires.

What you will see

Open the Serial Monitor at 9600 baud. At the first start it says "Scan the master card.": hold the kit's white card or blue key fob 1-2 cm over the reader; you hear two short beeps and this card is now the master card. Scanning an unknown card lights the red LED and sounds a long beep. To add a card, scan the master card: the green LED lights up and adding mode opens for 10 seconds; scan the new card meanwhile and it says "Card added.". Scanning a known card lights the green LED, sounds a short beep, and the servo turns to 90° and opens the door for 5 seconds, then locks it again. To remove a known card, scan the master card first and then the card to remove. The cards stay in EEPROM; they are recognised even after you unplug the Arduino. Every card's number is printed in the Serial Monitor. If it says "RC522 not found" and the red LED blinks, check the reader's wires, especially SDA (10), SCK (13), MOSI (11), MISO (12) and 3.3V; if the pin header is not soldered or is loose, the reader does not answer. If a card is never read, hold it over the middle of the reader and closer. To erase every card, change the EEPROM_MARK number in the code and upload it again.

In the app, tick off every wire, match the parts to your inventory and pick up where you left off.

Build it step by step in the app