RC522 RFID 门禁系统教程:用 Arduino Uno 刷卡开锁

Blue RC522 RFID reader with white card and blue keyfob wired to a blue Arduino Uno and a red two-channel relay module driving an electric strike

把 RC522 接到 Arduino Uno 的 SPI pin,读出卡片的 UID,和 sketch 里的名单比对,再触发 relay 模块去开关 12V 电控锁(electric strike)。RC522 是 3.3V 器件——VCC 必须接 Uno 的 3.3V pin,绝对不能接 5V。一个 library、一个 sketch,大约十条线。

RC522 套装里有什么?它到底能读什么卡?

我们卖的 RC522 是完整一套:蓝色读卡器 PCB(铜层上蚀刻着一大圈螺旋天线线圈)、一张白色 RFID 卡、一个蓝色水滴形钥匙扣(keyfob),还有两排散装排针——一排直的、一排 90 度弯的。排针没有预先焊好——我们的排针焊接教程会带你按外壳需要装上合适的那一种。

这个读卡器工作在 13.56 MHz,走 ISO/IEC 14443A 标准——也就是 MIFARE 家族,涵盖盒子里的卡和钥匙扣,以及很多办公室和公寓的门禁卡;但旧式的 125 kHz 卡它完全读不到。

RC522 和 relay 怎么接到 Arduino Uno?

RC522 用 SPI 通讯,所以要接在 Uno 固定的硬件 SPI pin 上,MFRC522 library 也正是按这个布局写的。IRQ 留空不接。

模块 pin Arduino Uno 备注
RC522 SDA (SS) D10 Chip select;这块板上印的是 SDA
RC522 SCK D13 SPI 时钟
RC522 MOSI D11 SPI 数据输出
RC522 MISO D12 SPI 数据输入
RC522 RST D9 复位
RC522 VCC 3.3V 绝对不能接 5V——接了模块直接烧掉
RC522 GND GND 共地
Relay IN1 D7 任何空闲的数字 pin 都可以
Relay DC+ 5V 线圈与 optocoupler 的供电
Relay DC− GND 共地

那条 3.3V 线是唯一没有商量余地的规矩:这颗芯片所有电源 pin 的绝对最大值是 4.0V,VCC 接 5V 就直接烧掉——这也是大家弄坏这款读卡器最常见的方式。逻辑 pin 同样不是官方认可 5V 容忍的——datasheet 把上限定在比电源电压高 0.5V,也就是 3.8V 左右——虽然这些模块在实际使用中通常扛得住 Uno 的 5V SPI 信号,但按规矩来的做法是加 level shifter 或简单的串联电阻。

门锁那边保持独立的低压回路:12V 电源正极进 relay 的 COM 端子,NO 出来接电锁,电锁再回到 12V 负极。第二路 relay 通道留空备用。

卡通接线图:七条跳线从蓝色 Arduino Uno 接到蓝色 RC522 读卡器,另有三条接到驱动 12V 电控锁的红色 relay 模块
七条线到读卡器,三条到 relay,另加一条独立的三线 12V 回路——Arduino 完全不碰那一路。

为什么这个项目用 relay 模块,而不是裸 relay?

Songle SRD-05VDC-SL-C relay 就是那块红板上的蓝色方块,我们也有单卖裸件,给自带驱动级的设计用——但任何裸 relay,不管是我们的还是别家的,都不能直接用 Arduino pin 驱动。它的 5V 线圈阻值 70 Ω,工作时要抽大约 71 mA,而 Uno 单个 I/O pin 的额定电流只有 20 mA;而且线圈断电瞬间的反冲尖峰,迟早会把那个 pin 打坏。

所以裸 relay 必须围着它搭一级驱动三极管加 flyback 二极管才能用。2 路 relay 模块两样都带齐,每路输入还各配一颗 optocoupler——这正是本项目选它的原因。你的 pin 只负责点亮 opto 的 LED,几个 mA 而已;线圈交给模块自己处理。

Arduino 复位时,怎么防止门锁自己咔一声开了?

2 路 relay 模块在输入端子旁有一小块 jumper,标着高电平/低电平触发(high/low level trigger),它决定哪个逻辑电平会吸合 relay。用在门锁上这点非常关键:Uno 上电和复位期间,pin 会以输入状态浮空,浮空的输入可能被读成 LOW;如果设成低电平触发,每次有人给板子断电重启,门锁就会咔一声开一次。

两个习惯就能解决:一是有意识地选触发方向——高电平触发能让浮空的 pin 保持无害;二是在 setup() 里第一件事就定好 pin 的待机状态,而且要在 pinMode() 之前先写入待机电平。我们的 relay 模块安全指南对这颗 jumper 有深入讲解。门锁一律用自带电源的低压 DC——市电切换不属于这个项目的范围。

卡通对比图:蓝色 RC522 读卡器正确接在 Arduino 3.3V pin 供电,旁边同一个读卡器因接了 5V 而冒烟
RC522 的 VCC 只属于 3.3V pin。插错一格就是一个报废的读卡器——这是大家弄坏它的头号方式。

怎么找出你卡片的 UID 并跑起这个 sketch?

要装的是 GithubCommunity 出的 MFRC522 library:打开 Arduino IDE 的 Library Manager,搜 MFRC522,选那一条。把下面的 sketch 原封不动上传,打开 Serial Monitor 设 9600 baud,拍一下卡——不管在不在名单里,它都会把见到的每张卡的 UID 打印出来。把那几个 byte 抄进 allowedUids,重新上传,那张卡就能开锁了。

#include <SPI.h>
#include <MFRC522.h>

#define SS_PIN     10   // RC522 SDA/SS
#define RST_PIN     9   // RC522 RST
#define RELAY_PIN   7   // Relay 模块 IN1

// 按你的触发 jumper 来设:低电平触发用 LOW/HIGH,
// 高电平触发用 HIGH/LOW。
#define RELAY_ACTIVE  HIGH
#define RELAY_IDLE    LOW
#define UNLOCK_MS   3000

MFRC522 mfrc522(SS_PIN, RST_PIN);

// 允许开锁的卡,4 byte UID。换成这个 sketch 打印出来的 UID。
byte allowedUids[][4] = {
  {0xDE, 0xAD, 0xBE, 0xEF},
  {0x12, 0x34, 0x56, 0x78}
};
const byte allowedCount = sizeof(allowedUids) / sizeof(allowedUids[0]);

// 只有拍卡的 UID 与名单中某一整行完全吻合才返回 true。
bool isAllowed(byte *uid, byte size) {
  if (size != 4) return false;          // 这个名单只收 4 byte 的 UID
  for (byte c = 0; c < allowedCount; c++) {
    byte matched = 0;
    for (byte i = 0; i < 4; i++) {
      if (uid[i] == allowedUids[c][i]) matched++;
    }
    if (matched == 4) return true;
  }
  return false;
}

void setup() {
  // 在 pin 变成输出之前,先把 relay 停在待机电平,
  // 板子启动过程中它就绝不会瞬间跳到触发电平。
  digitalWrite(RELAY_PIN, RELAY_IDLE);
  pinMode(RELAY_PIN, OUTPUT);
  digitalWrite(RELAY_PIN, RELAY_IDLE);

  Serial.begin(9600);
  SPI.begin();
  mfrc522.PCD_Init();
  delay(50);
  mfrc522.PCD_DumpVersionToSerial();  // 打印 0x00 或 0xFF 表示接线或供电有问题
  Serial.println(F("Ready. Tap a card."));
}

void loop() {
  if (!mfrc522.PICC_IsNewCardPresent()) return;
  if (!mfrc522.PICC_ReadCardSerial()) return;

  // 打印每张卡的 UID,方便你收集自己的卡号。
  Serial.print(F("UID:"));
  for (byte i = 0; i < mfrc522.uid.size; i++) {
    if (mfrc522.uid.uidByte[i] < 0x10) Serial.print(F(" 0"));
    else Serial.print(F(" "));
    Serial.print(mfrc522.uid.uidByte[i], HEX);
  }
  Serial.println();

  if (isAllowed(mfrc522.uid.uidByte, mfrc522.uid.size)) {
    Serial.println(F("Granted - unlocking"));
    digitalWrite(RELAY_PIN, RELAY_ACTIVE);
    delay(UNLOCK_MS);
    digitalWrite(RELAY_PIN, RELAY_IDLE);
  } else {
    Serial.println(F("Denied"));
  }

  mfrc522.PICC_HaltA();
  mfrc522.PCD_StopCrypto1();
}

老实说,RC522 门禁到底有多安全?

这个 RC522 sketch 用来比对的 UID 并不是秘密。任何读卡器一问,卡片在任何认证发生之前就会把 UID 广播出去,而 UID 区块可以改写的空白卡,市面上几令吉就能公开买到。MFRC522 library 自己的文档说得很直白:UID 不能当作安全相关项目的唯一身份凭证

改成读受保护的 sector 也救不回来。MIFARE Classic 的 Crypto1 加密从 2008 年起就被公开破解,后来研究人员又演示了仅凭密文就能在几分钟内从加固版卡片恢复密钥的攻击。2024 年 Quarkslab 更发现一整个 MIFARE Classic 兼容芯片家族共用的硬件后门密钥。Crypto1 不是弱,而是已经玩完了。

所以老实的结论是——但这绝不是叫你别做。它是非常好的 RBT 或 final-year project,适合做考勤或出入记录、抽屉、locker、工作室柜子、“谁在工作台”的显示板,或是保留实体钥匙做后备的闸门。它不适合当你家大门、保险箱,或任何丢了会心痛的东西的锁。

当威胁是真实的,凭证也必须是真的。像 MIFARE DESFire 这类卡用的是 AES-128 双向认证,而不是广播一个序列号——商用门禁系统跑的就是这一套。至于住家大门,一把好的机械锁加一个摄像头,永远胜过 UID 比对。

卡通对比图:RC522 读卡器正确用在工作室柜子上,旁边错误地装在住家大门上
柜子、locker、抽屉、考勤记录:可以。你家大门:不行——UID 比对是方便,不是安全。

为什么读卡器完全没反应,或读到了却永远不匹配?

RC522 的故障模式不多,而且每一种都有特征——这也是 sketch 每次开机都打印 firmware 版本的原因。

症状 可能原因 解决方法
Firmware 版本打印 0x00 或 0xFF SPI 接线错误,或 VCC 接了 5V 重查 D9–D13,把 VCC 移到 3.3V;已经喂过 5V 的模块可能已经报废
版本正常,却永远检测不到卡 排针没焊或虚焊(冷焊点) 把八个焊点重新焊一遍;用手扭一扭线证明不了什么
能读几次,之后就没反应 3.3V 供电不足或跳线太长 线缩短到 20 cm 以内,给 Uno 用像样的电源,别靠笔记本的 USB hub
UID 打印出来,但永远被拒绝 名单里的 byte 或长度不符 一字不差照抄打印出来的 byte;7 byte UID 的卡要把长度检查放宽

我们从真实客户身上看到的常见错误

最烧钱的模式,是顺手把 RC522 接上 5V——因为其他模块个个都吃 5V。之后的症状就是一小时前还好好的板子,firmware 版本变成 0x00——接着一整个下午都在怀疑其实完全没问题的代码。

最烧时间的模式,是电锁和设计想的不一样:桌面测试时 relay 咔咔响得很开心,装上门才发现买的是断电上锁(fail-secure)的锁,而方案假设的是断电开锁(fail-safe)。买电锁之前,先决定停电时门应该是什么状态。

FAQ

我能用 RC522 复制办公室门禁卡或 Touch ‘n Go 吗?

RC522 通常能读出任何 13.56 MHz 卡片的 UID,Touch ‘n Go 也属于同一个 MIFARE 家族——但我们不会发布任何复制卡片的步骤。复制不属于你的凭证,是发卡方才有权决定的事;储值余额存在加密 sector 里,那不是你能碰的东西。

RC522 能隔着门或墙读卡吗?

它能穿透几毫米厚的非金属材料——木板、亚克力或 3D 打印面板——所以你可以把读卡器藏进外壳里。金属才是杀手:金属门或金属背板会让天线失谐,读卡距离直接崩掉。

RC522 实际的读卡距离是多少?

纸面上最远 50 mm,用套装里的白卡实际是 2–4 cm。蓝色钥匙扣的天线更小,距离更短;供电不稳时距离还会再掉。

我可以用 ESP32 代替 Arduino Uno 吗?

可以,而且从电气上讲更匹配,因为 ESP32 和 RC522 一样是 3.3V 板子。用默认 SPI pin——MOSI 23、MISO 19、SCK 18、SS 5——RST 接任何空闲的 GPIO。我们的 ESP32、ESP8266 与 Uno 对比讲了各自的取舍。

允许名单里可以存多少张卡?

远超你的需要。每个 4 byte UID 只占 ATmega328P 那 2 KB RAM 中的四个 byte,数组里放几百张都没问题。当你希望名单断电不丢、加卡不必重新上传时,把名单搬进芯片的 1 KB EEPROM——大约能放 250 个 UID。

最后更新:2026年8月。有问题?WhatsApp 联系我们

Leave a Reply

Your email address will not be published. Required fields are marked *