Community project

RFID Access Control System

leang

Published July 28, 2026

Arduino5 components5 assembly steps
Remix this project
Photo of RFID Access Control System

This RFID access control system uses an Arduino Uno to read RFID cards and control a servo-driven lock mechanism. When an authorized card is scanned, the system unlocks the door for a set duration, displays status messages on an LCD screen, and provides audio feedback via a buzzer. The guide includes a complete wiring diagram, parts list, and step-by-step assembly instructions to get the system operational.

Builders will learn how to integrate SPI communication with the MFRC522 RFID reader, I2C control of the LCD display, and servo actuation for the lock mechanism. The provided Arduino firmware handles card detection, authorization logic, and timed lock/unlock sequences, making this an excellent foundation for understanding access control systems and multi-component Arduino projects.

Wiring diagram

Interactive · read-only
Wiring diagram for RFID Access Control System

Pan and zoom to explore the wiring. Remix the project to edit it in your own workspace.

Parts list

Bill of materials
ComponentQtyNotes
MFRC522 RFID ModuleRC522 13.56 MHz113.56 MHz RFID reader/writer module based on the NXP MFRC522 IC. Communicates over SPI and is commonly sold as an RC522 breakout with an onboard antenna.
LCD 16x2 I2C16x2, I2C address 0x27116x2 character LCD display with I2C backpack
Buzzer5 V piezo1Piezo buzzer for sound output
SG90 ServoSG90 9 g1Micro servo motor (SG90)
USB-C 5V Adapter5 V, 2 A minimum1USB-C wall adapter delivering regulated 5 V to the board's USB or VBUS rail. Default wired power source for desktop / stationary projects.

Assembly

5 steps
  1. Arrange the dark circuit layout

    Place the Arduino Uno centrally on a dark gray breadboard or mounting panel. Position the RC522 reader to its left, the LCD above it, the SG90 at the right, and the piezo buzzer at the lower right. Keep the RFID antenna clear of metal and large wire bundles.

    • Tip: Use short, neatly routed jumper wires so the diagram-like layout stays easy to trace.
    • Tip: Keep the RC522 antenna face exposed for reliable card scans.
    • Do not place the RC522 directly on a metal plate or against the Uno USB connector.
  2. Wire the RC522 RFID reader

    Connect RC522 VCC to the Uno 3.3 V rail and GND to common ground. Connect SCK to D13, MOSI to D11, MISO to D12, SDA/SS to D10, and RST to D9. For a physical 5 V Uno, insert 5 V-to-3.3 V resistor dividers or a proper high-speed level shifter on the Uno outputs D13, D11, D10, and D9 before they reach the RC522 inputs.

    • Tip: The RC522 pin labelled SDA is SPI chip select, not I2C SDA.
    • Tip: Use 1 kΩ from each Uno output to the RC522 input node and 2 kΩ from that node to GND for each divider.
    • Never connect RC522 VCC to 5 V.
    • Do not omit the level reduction on D13, D11, D10, and D9; RC522 logic is 3.3 V.
  3. Wire the I2C LCD

    Connect LCD VCC to 5 V and GND to common ground. Connect LCD SDA to Uno A4 and LCD SCL to Uno A5.

    • Tip: Most 16x2 I2C backpacks use address 0x27; the supplied firmware uses that address.
    • Tip: Adjust the small contrast trimmer on the LCD backpack if characters are not visible.
    • Keep A4 and A5 exclusively for the I2C LCD bus in this project.
  4. Wire the buzzer and servo

    Connect buzzer SIGNAL to D3 and buzzer GND to common ground. Connect the SG90 signal wire (orange/yellow) to D6, its red wire to regulated 5 V, and its brown/black wire to common ground.

    • Tip: Set the servo horn mechanically after the firmware first moves it to the locked position.
    • Tip: Add a 470–1000 µF electrolytic capacitor across the 5 V and GND rails close to the servo if you see resets or LCD flicker.
    • Do not rely on the Uno 5 V pin alone to power a mechanically loaded servo.
    • The servo supply ground and Uno ground must be connected together.
  5. Connect regulated power and inspect

    Use the regulated 5 V, 2 A minimum USB power adapter to feed the project 5 V and GND rails. Confirm that the Uno receives power through its normal USB input or a safe regulated 5 V distribution, and verify every module shares the same ground before powering on.

    • Tip: Route red wires as 5 V, black wires as ground, and use distinct colors for SPI, I2C, and servo signal wires to create a realistic easy-to-read diagram.
    • Tip: After powering, scan any 13.56 MHz card or fob: its UID appears on the LCD, the buzzer chirps, and the servo unlocks briefly.
    • Do not connect two independent 5 V sources to the Uno 5 V rail at the same time.
    • Double-check RC522 power polarity before turning on the supply.

Pin assignments

Board wiring reference
PinConnectionType
5Vpower_adapter +5Vpower
GNDpower_adapter GNDground
3V3rfid_reader VCCpower
GNDrfid_reader GNDground
GPIO 13rfid_reader SCKspi
GPIO 11rfid_reader MOSIspi
GPIO 12rfid_reader MISOspi
GPIO 10rfid_reader SDAspi
GPIO 9rfid_reader RSTdigital
5Vlcd_display VCCpower
GNDlcd_display GNDground
GPIO 18lcd_display SDAi2c
GPIO 19lcd_display SCLi2c
GNDpiezo_buzzer GNDground
GPIO 3piezo_buzzer SIGNALdigital
5Vservo_motor VCCpower
GNDservo_motor GNDground
GPIO 6servo_motor SIGNALpwm

Firmware

Arduino
main.cppDeploy to device
#include <Arduino.h>
#include <SPI.h>
#include <MFRC522.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Servo.h>


// Forward declarations
void showStatus(const String &line1, const String &line2);
String cardUid();
void lockDoor();
void unlockDoor(const String &uid);

const byte RFID_SS_PIN = 10;
const byte RFID_RST_PIN = 9;
const byte BUZZER_PIN = 3;
const byte SERVO_PIN = 6;
const byte SERVO_LOCKED_ANGLE = 10;
const byte SERVO_UNLOCKED_ANGLE = 95;
const unsigned long UNLOCK_TIME_MS = 3000UL;

MFRC522 rfid(RFID_SS_PIN, RFID_RST_PIN);
LiquidCrystal_I2C lcd(0x27, 16, 2);
Servo lockServo;
bool doorUnlocked = false;
unsigned long unlockStartedAt = 0;
String shownLine1;
String shownLine2;

void showStatus(const String &line1, const String &line2) {
  if (line1 == shownLine1 && line2 == shownLine2) return;
  lcd.setCursor(0, 0); lcd.print("                ");
  lcd.setCursor(0, 0); lcd.print(line1.substring(0, 16));
  lcd.setCursor(0, 1); lcd.print("                ");
  lcd.setCursor(0, 1); lcd.print(line2.substring(0, 16));
  shownLine1 = line1;
  shownLine2 = line2;
}

String cardUid() {
  String uid;
  for (byte i = 0; i < rfid.uid.size; ++i) {
    if (rfid.uid.uidByte[i] < 0x10) uid += '0';
    uid += String(rfid.uid.uidByte[i], HEX);
    if (i + 1 < rfid.uid.size) uid += ':';
  }
  uid.toUpperCase();
  return uid;
}

void lockDoor() {
  lockServo.write(SERVO_LOCKED_ANGLE);
  doorUnlocked = false;
  showStatus("Scan RFID card", "Door locked");
}

void unlockDoor(const String &uid) {
  lockServo.write(SERVO_UNLOCKED_ANGLE);
  doorUnlocked = true;
  unlockStartedAt = millis();
  showStatus("Access granted", uid);
  tone(BUZZER_PIN, 1600, 110);
  delay(140);
  tone(BUZZER_PIN, 2200, 140);
}

void setup() {
  pinMode(BUZZER_PIN, OUTPUT);
  Wire.begin();
  lcd.init();
  lcd.backlight();
  lockServo.attach(SERVO_PIN);
  SPI.begin();
  rfid.PCD_Init();
  delay(50);
  lockDoor();
}

void loop() {
  if (doorUnlocked && millis() - unlockStartedAt >= UNLOCK_TIME_MS) lockDoor();
  if (!rfid.PICC_IsNewCardPresent() || !rfid.PICC_ReadCardSerial()) return;
  String uid = cardUid();
  unlockDoor(cardUid());
  rfid.PICC_HaltA();
  rfid.PCD_StopCrypto1();
}

“Deploy to device” opens this project in Schematik, where you can flash it to your board over USB.

Remix this project

Make it yours in one click

Open a full copy of this project in your own Schematik workspace — diagram, code, parts, and assembly steps included. Swap the sensor, add features, or redesign the whole thing with AI. The author's original stays untouched.

Open in Schematik