Bài viết
Khóa cửa RFID với Arduino và RC522: chỉ mở khi đúng thẻ
🔐
Khóa cửa bằng thẻ RFID là dự án nhập môn bảo mật phần cứng lý tưởng: rẻ, dễ hiểu nguyên lý, và tạo cảm giác “thành phẩm thật” rất nhanh — chỉ sau một buổi tối là bạn có thể quẹt thẻ để mở cửa tủ, hộp đồ, hoặc cửa phòng nhỏ.
Nguyên lý hoạt động
- Module RC522 phát sóng RFID tần số 13.56MHz, đọc UID (mã định danh duy nhất) của thẻ hoặc móc khóa đưa lại gần.
- Arduino nhận UID qua giao tiếp SPI, so sánh với danh sách UID được phép lưu sẵn trong code.
- Nếu khớp, Arduino quay servo để mở chốt khóa trong vài giây rồi tự đóng lại; đồng thời bật đèn xanh/còi báo “chấp nhận”.
- Nếu không khớp, đèn đỏ nhấp nháy báo “từ chối”.
Linh kiện
- Arduino Uno (hoặc Nano)
- Module đọc thẻ RFID RC522 (giao tiếp SPI)
- Thẻ/móc khóa RFID 13.56MHz (Mifare Classic là loại phổ biến nhất)
- Servo SG90 gắn với chốt khóa cơ khí (hoặc dùng khóa solenoid 12V + module relay nếu cần lực giữ lớn hơn)
- 2 LED (xanh, đỏ) + buzzer nhỏ báo hiệu
- Thư viện
MFRC522(cài qua Library Manager trong Arduino IDE)
Code mẫu
Bước 1: đọc UID của thẻ để biết cần thêm giá trị gì vào danh sách cho phép.
#include <SPI.h>
#include <MFRC522.h>
#define SS_PIN 10
#define RST_PIN 9
MFRC522 rfid(SS_PIN, RST_PIN);
void setup() {
Serial.begin(9600);
SPI.begin();
rfid.PCD_Init();
Serial.println("Dua the lai gan de doc UID...");
}
void loop() {
if (!rfid.PICC_IsNewCardPresent() || !rfid.PICC_ReadCardSerial()) return;
Serial.print("UID: ");
for (byte i = 0; i < rfid.uid.size; i++) {
Serial.print(rfid.uid.uidByte[i] < 0x10 ? " 0" : " ");
Serial.print(rfid.uid.uidByte[i], HEX);
}
Serial.println();
rfid.PICC_HaltA();
}
Bước 2: khóa cửa thực tế với danh sách UID được phép.
#include <SPI.h>
#include <MFRC522.h>
#include <Servo.h>
#define SS_PIN 10
#define RST_PIN 9
#define LED_XANH 6
#define LED_DO 5
#define BUZZER 4
#define SERVO_PIN 3
MFRC522 rfid(SS_PIN, RST_PIN);
Servo lockServo;
// Danh sách UID được phép (viết hoa, không dấu cách)
String danhSachChoPhep[] = {
"A1B2C3D4",
"1A2B3C4D"
};
const int SO_LUONG_THE = 2;
void moKhoa() {
digitalWrite(LED_XANH, HIGH);
tone(BUZZER, 1000, 200);
lockServo.write(90); // vi tri mo
delay(4000);
lockServo.write(0); // vi tri khoa
digitalWrite(LED_XANH, LOW);
}
void tuChoi() {
for (int i = 0; i < 3; i++) {
digitalWrite(LED_DO, HIGH);
tone(BUZZER, 300, 100);
delay(150);
digitalWrite(LED_DO, LOW);
delay(150);
}
}
void setup() {
Serial.begin(9600);
SPI.begin();
rfid.PCD_Init();
lockServo.attach(SERVO_PIN);
lockServo.write(0);
pinMode(LED_XANH, OUTPUT);
pinMode(LED_DO, OUTPUT);
pinMode(BUZZER, OUTPUT);
}
void loop() {
if (!rfid.PICC_IsNewCardPresent() || !rfid.PICC_ReadCardSerial()) return;
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);
}
uid.toUpperCase();
bool duocPhep = false;
for (int i = 0; i < SO_LUONG_THE; i++) {
if (uid == danhSachChoPhep[i]) { duocPhep = true; break; }
}
if (duocPhep) {
Serial.println("The hop le -> Mo khoa");
moKhoa();
} else {
Serial.println("The khong hop le -> Tu choi");
tuChoi();
}
rfid.PICC_HaltA();
rfid.PCD_StopCrypto1();
}
Những lỗi thường gặp
- Cấp nhầm 5V cho RC522: module chỉ chịu được mức logic 3.3V, cấp 5V vào VCC có thể làm cháy chip trong vài giây.
- Servo giật/không đủ lực giữ chốt: SG90 khá yếu, nếu chốt cửa nặng nên đổi sang khóa solenoid 12V điều khiển qua relay thay vì kéo trực tiếp bằng servo.
- So sánh UID sai định dạng: UID đọc ra có thể có hoặc không có số 0 ở đầu byte — cần chuẩn hóa nhất quán (ví dụ luôn thêm “0” khi byte < 0x10) giữa lúc ghi danh sách và lúc so sánh, nếu không thẻ hợp lệ vẫn bị từ chối.
- Không có cơ chế chống dò UID bằng brute-force: vì đây là dự án DIY quy mô nhỏ nên chấp nhận được, nhưng đừng dùng cách này cho cửa thực sự quan trọng — RFID UID có thể bị sao chép bằng thiết bị chuyên dụng.
Mở rộng
Lưu danh sách UID vào EEPROM để thêm/xóa thẻ mà không cần nạp lại code, hoặc ghi log thời gian mở khóa lên thẻ SD/Google Sheets qua ESP8266 để biết ai mở cửa lúc nào.
Thẻ:#arduino#rfid#security
Bình luận