门禁卡贴上去"滴"一声就开门,这套东西拆开看其实非常简单:一张 13.56MHz 的卡,一个读卡芯片,一片主控。Arduino 玩家里最常见的读卡方案就是 MFRC522 模块,十几块钱的套件里几乎必带一张白色 MIFARE 卡和一个蓝色钥匙扣。这篇把它接到 Arduino UNO 上,读出卡片 UID,再做一个最小门禁判断:匹配的卡放行,不匹配的拒绝。
先交代器件底细。MFRC522 是 NXP 做的读写芯片,工作在 13.56MHz,走 ISO/IEC 14443A 协议,也就是 MIFARE 那一族。模块供电必须是 3.3V,这点要刻在脑子里——接 5V 会把模块烧掉。通信走 SPI,模块上八个引脚里 IRQ 大多数例程都空着不接。套件里那张白卡是 MIFARE Classic 1K,容量 1KB,分成 16 个扇区、每扇区 4 个块。
接线:六根杜邦线的事
模块引脚虽然标着 SDA,实际是 SPI 的片选(SS),不是 I2C 的数据线,这点最容易让新手犯迷糊。对 UNO 的接线如下:
- SDA 接 D10(SPI 片选)
- SCK 接 D13,MOSI 接 D11,MISO 接 D12(SPI 总线)
- RST 接 D9
- VCC 接 3.3V,GND 接 GND,IRQ 悬空

再强调一次:VCC 千万别接 5V 引脚。UNO 的 SPI 引脚是 5V 电平,大量玩家直接这么接也没出事,但稳妥的做法是给 SCK、MOSI、SS、RST 这几条线加分压电阻,唯独 MISO 不用管。第一次搭,先按直连来,能跑通再说。
装库:认准 GithubCommunity 那个 MFRC522
打开 Arduino IDE,左侧库管理器图标点进去,搜 MFRC522,选 by GithubCommunity 的那个(GitHub 上 miguelbalboa 维护的仓库),点安装。装完重启 IDE,文件菜单的示例里就会出现 MFRC522 一族,里面有 DumpInfo 这个经典例程——把卡贴上去,能把卡里所有扇区的内容整个倒出来看。
接线图对照:RFID-RC522 各引脚到 UNO 的对应关系,SCK 13、MISO 12、SDA 10、RST 9、MOSI 11,VCC 走 3.3V

读 UID:串口监视器看卡号
先跑 DumpInfo,打开串口监视器(9600 波特率),把白卡贴到天线上,屏幕会刷出一整屏数据:卡片类型、UID、16 个扇区每个块的内容都在里面。UID 是出厂写死、只读的那 4 个字节,白色 MIFARE 卡基本都是 4 字节 UID。

把自己卡的 UID 记下来,下面门禁判断要用。门禁的原理朴素得很:每张卡 UID 唯一,读到的 UID 和白名单对得上就放行,对不上就拒绝。
门禁小实验:完整代码
下面这份例程改自 Random Nerd Tutorials 的门禁示例,逻辑是逐字节拼出 UID 字符串,和预设卡号比对:
/*
*
* All the resources for this project: http://randomnerdtutorials.com/
* Modified by Rui Santos
*
* Created by FILIPEFLOP
*
*/
#include "SPI.h"
#include "MFRC522.h"
#define SS_PIN 10
#define RST_PIN 9
MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance.
void setup()
{
Serial.begin(9600); // Initiate a serial communication
SPI.begin(); // Initiate SPI bus
mfrc522.PCD_Init(); // Initiate MFRC522
Serial.println("Approximate your card to the reader...");
Serial.println();
}
void loop()
{
// Look for new cards
if ( ! mfrc522.PICC_IsNewCardPresent())
{
return;
}
// Select one of the cards
if ( ! mfrc522.PICC_ReadCardSerial())
{
return;
}
//Show UID on serial monitor
Serial.print("UID tag :");
String content= "";
byte letter;
for (byte i = 0; i < mfrc522.uid.size; i++)
{
Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
Serial.print(mfrc522.uid.uidByte[i], HEX);
content.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "));
content.concat(String(mfrc522.uid.uidByte[i], HEX));
}
Serial.println();
Serial.print("Message : ");
content.toUpperCase();
if (content.substring(1) == "BD 31 15 2B") //change here the UID of the card/cards that you want to give access
{
Serial.println("Authorized access");
Serial.println();
delay(3000);
}
else {
Serial.println(" Access denied");
delay(3000);
}
} 尖括号头文件写成了双引号形式,两者在 Arduino 工具链下编译等价,直接粘贴可用。上传后把代码里 BD 31 15 2B 换成你刚才记下的卡号,开串口监视器:授权的卡贴上去显示 Authorized access,拿钥匙扣或者别的卡试,就是 Access denied。门禁的判断环节,到这一步就闭环了。
读不出来?先查这几处
例程启动时会打印固件版本号,这一行就是接线自检:打出版本号说明 SPI 通了,打印 0x00 或 0xFF 就是通信失败——回头检查 MISO 有没有插对、3.3V 有没有接实。RC522 发射瞬间电流能到 130mA 左右,杜邦线接触电阻偏大时 3.3V 会被拉低,模块中途复位,表现为时灵时不灵,把线焊死或者换粗线能解决。
另一个坑是金属:天线贴着金属外壳放,涡流会把 13.56MHz 的谐振拖偏,读卡距离骤降甚至读不到,垫高 1 厘米以上或者加铁氧体隔磁片。
想把小实验往真门禁推进,下一步无非是加继电器驱动电磁锁、加 LED 指示、把白名单做成多卡表。逻辑还是这一套:读 UID、查表、执行。能把这个最小系统跑稳,剩下的都是加法。











上周刚在海鲜市场淘了个RC522套件,卡在固件版本号打印0xFF那一步,看完才知道是MISO没插对。文章里130mA拉低3.3V那段说得太对了,我用的杜邦线就是时灵时不灵,换了短粗线才稳定。提醒一句,模块千万别接5V,我朋友烧过一块,在线的兄弟们引脚核对三遍再上电。
SDA其实是SPI片选这个点讲得好,第一次接的时候我也懵了半天。
门禁这块能不能再加个继电器开锁的续篇?想抄作业。