资讯详情

Arduino RC522门禁卡复制器:UID读写原理与完整实现教程

📅 2026/10/5 2:51:54 | 华诺云谱 👁 阅读
Arduino RC522门禁卡复制器:UID读写原理与完整实现教程
周末折腾了一下用一块 Arduino UNO 加上一个 RC522 模块我做出了一个能复制 NFC 门禁卡的小工具。把卡往上一放串口里看到 UID按一下指令目标卡的 UID 就被覆盖成源卡的 UID整个过程不到 10 秒。这个项目不需要高深的高频电路知识也不需要昂贵的设备Arduino 加 RC522 的整套成本大概就三四十块钱却能让你把 RFID 卡片的存储结构、SPI 通信、密钥认证这些概念一次搞明白。先说清楚这个 DIY 项目只能用于你本人有权限操作的卡片备份、门禁测试、校园卡研究之类场景。复制别人的门禁卡、绕过物业门禁管制既不合规也有法律风险。技术本身是中性的用在哪儿完全取决于你自己。下面进入正题我从原理开始讲最后会把能直接编译的完整代码给出来。1. RC522 能复制什么门禁卡技术和卡片类型先分清很多人在做这个项目之前有个误解以为 RC522 是万能读卡器什么卡放上去都能读。不是这样的。RC522 工作在 13.56MHz 频段支持 ISO/IEC 14443A 协议核心兼容的是 Mifare Classic 系列也就是我们常见的 S501K 容量和 S704K 容量这类卡。对应到日常见到的东西就是小区门禁卡、电梯卡、部分校园卡、停车卡。如果你的门禁卡是那种很厚的 ID 卡或者工作频率是 125kHz 的低频卡RC522 直接读不了。低频卡通常用 EM4100 之类的芯片需要配专用的 125kHz 读卡模块比如 RDM6300、RDM630 之类。所以拿到卡片先别急着接线第一步是确认你的卡是不是 13.56MHz 的 Mifare 卡。判断方法很简单把卡放在手机闪光灯下面照能看到内部线圈和芯片形状一般 Mifare 卡是圆形线圈加一个方形芯片也可以先烧录一个最简单的读 UID 程序如果串口有反应就说明卡在 RC522 的工作范围内。1.1 RC522 到底是什么模块RC522 模块本质上是 NXP 公司出品的 RC522 射频读写芯片加上天线线圈、匹配电路和外围元件做成的成品小板。它通过 SPI 接口和单片机通信Arduino 负责发指令、收数据RC522 负责把数字信号变成射频场然后和卡片进行无线数据交换。芯片本身支持读写 Mifare Classic 卡的扇区数据也支持对卡片进行密钥认证、减值、增值等操作。这里要注意一个关键点RC522 是一个读写器不是一个卡模拟器。它只能发指令读写卡片不能把自己伪装成一张卡让门禁读卡器来读。后面有人问能不能用 RC522 直接模拟门禁卡答案是不能那需要 PN532 或者支持卡模拟功能的 NFC 芯片。这个项目说的复制是把源卡的数据写入另一张目标卡而不是让 Arduino 变成一张卡。1.2 主流门禁卡的存储结构我们常用的 Mifare S50 卡容量是 1KB也就是 1024 字节分成 16 个扇区Sector 0 到 Sector 15每个扇区有 4 个块Block每个块 16 字节。块 0 比较特殊它存放的是厂商信息其中前 4 个字节就是卡的 UID唯一标识符第 5 个字节是 UID 的校验位BCC后面还有 SAK、ATQA 等编码信息。原厂出厂的普通卡块 0 是只读的用户不能改。这也是为什么普通白卡不能改 UID——因为 UID 被写死在芯片里了。如果想复制一张只校验 UID 的门禁卡就必须用专门的可写 UID 卡也就是我们常说的UID 卡或UID 可写卡。这种卡的块 0 没有被锁死可以通过特定的命令改写。除了块 0每个扇区的块 3 也特殊它存的是密钥 A、访问控制位、密钥 B。要读写某个扇区里的数据块首先得通过这个扇区的密钥认证。默认出厂的 Mifare 卡密钥 A 和密钥 B 都是六个字节的 0xFF也就是 FFFFFFFFFFFF。很多门禁系统发行卡的时候并不改密钥所以用默认密钥就能把卡片数据读出来。如果物业改过密钥你又不知道那这套代码也救不了你别想着穷举破解那不是这个项目该做的事。1.3 你的门禁到底校验的是 UID 还是数据这是整个项目里最核心的一个判断因为它决定了你能不能复制成功。一种门禁系统只读取卡的 UID在数据库里存一串卡号记录只要你刷的卡 UID 在列表里门就开。这种门禁最简单也最好复制。你只需要把源卡的 UID 写到一张可写 UID 卡上目标卡的 UID 变成和源卡一样门禁就认了。绝大部分自制门禁、小型物业门禁都是这种工作模式。另一种门禁系统会读取卡内特定扇区的加密数据比如楼层权限、有效期、用户 ID 等。这种卡就算 UID 一样数据不对也开不了门。复制这种卡光改 UID 不够得把源卡的扇区数据完整导出来再写进目标卡。第三种更麻烦门禁系统和卡之间有动态互认证每次刷卡后数据会变这种卡复制出来基本没用也就是所谓的滚动码防复制。RC522 能做的只是读写卡遇到这种卡直接放弃。所以做这个项目之前先搞清楚你手头卡属于哪种。我的建议是先读出 UID如果门禁只认 UID直接走改 UID 方案如果门禁还需要数据再研究全卡复制。2. 材料清单和接线照着接90% 的人第一次都没问题硬件部分相当简单本质上就是一个 Arduino 板加一个 RC522 模块。如果你手头已经有 Arduino UNO、Nano 或者 ESP8266省下主控的钱直接买模块就行。如果没有一套 Arduino UNO 兼容板加 RC522 模块价格也在 30 块上下。2.1 要准备哪些东西我实际测试用的配置如下Arduino UNO 兼容板一块RC522 模块一个通常会送一张 IC 卡和一个钥匙扣卡目标卡建议买 Mifare Classic 1K UID 可写卡也就是能改写 UID 的卡按UID 可写卡搜索就能找到杜邦线公对母的 7 根左右面包板可不用但方便把模块固定如果是给 RC522 模块供电感觉不稳可以准备一个 3.3V 的外部稳压模块但大多数 UNO 的 3.3V 输出能带动这个模块不需要额外供电。模块的天线区域最好悬空不要在下面垫金属板否则识别距离会明显缩短。2.2 引脚对应关系表RC522 模块左侧一排引脚分别是 SDA、SCK、MOSI、MISO、IRQ、GND、RST、3.3V。和 Arduino UNO 的接线如下RC522 引脚Arduino UNO 引脚SDASSD10SCKD13MOSID11MISOD12IRQ不接悬空GNDGNDRSTD93.3V3.3V这里三个 SPI 引脚是固定的D13 是时钟D11 是主机输出D12 是主机输入。D10 是片选引脚理论上可以改到其他数字引脚但需要同步修改代码里的SS_PIN定义。RST 引脚也可以换只要在代码里改RST_PIN就行。我建议一开始完全按表接跑通了再改。如果你是 Arduino Nano接线和 UNO 是一样的Nano 的 D13、D12、D11、D10 也在相同位置。如果是 ESP8266 或其他开发板引脚要重新查这里先不展开。2.3 一个经常被忽略的问题RC522 必须用 3.3V我看到过不少新手直接把 RC522 接到 Arduino 的 5V 引脚上然后模块一股焦味芯片直接报废。RC522 的 VCC 标的是 3.3V它内部电路是按 3.3V 设计的。Arduino UNO 的 3.3V 引脚可以提供约 50mA 电流RC522 读卡时电流峰值大概在 30mA 左右从 3.3V 引脚取电是可行的。但是要注意有些 Arduino 兼容板的 3.3V 是从 USB 转串口芯片或者 AMS1117 稳压出来的电流余量不大。如果你的读卡距离特别近、偶尔读不到卡可以先怀疑供电。排查方法是拿万用表量 RC522 模块 3.3V 引脚和 GND 之间的电压刷卡瞬间如果电压跌落超过 0.2V就是供电不足可以换一个电流更大的 3.3V 电源并把电源地和 Arduino 的 GND 连在一起。另外RC522 模块的 SPI 信号线是 3.3V 电平Arduino UNO 的 D10~D13 输出是 5V 电平。市面上常见的 RC522 模块板载了电平转换电路所以直连没问题。但如果你的模块上没有分压电阻稳妥起见可以在 SPI 数据线上串一个 1kΩ 电阻或者用逻辑电平转换模块。我试过的模块基本都是可以直接接的但你要留心一下板子上有没有 R1、R2 这类电阻没有的话就先串电阻再上电。3. 开发环境和库别为版本折腾一下午软件环境这步卡住的人最多但其实是最好解决的。你不需要会写复杂的寄存器操作MFRC522 库已经把这些事封装好了。3.1 用 Arduino IDE 加 MFRC522 库去 Arduino 官网下载 Arduino IDE安装完成后打开在工具 - 开发板里选择你的板子比如 Arduino Uno。然后打开项目 - 加载库 - 库管理器在搜索框里输入 MFRC522找到由 Miguel Balboa 维护的那个库直接安装。这个库是目前 Arduino 社区最常用的 RC522 驱动库支持扇区认证、读写、UID 修改等操作。库安装好以后我第一次测试时直接用示例里的 DumpInfo 程序编译烧录后把卡片放在读卡天线上串口就能打印出卡片的 UID、SAK、类型以及所有扇区的数据。这一步可以作为确认硬件没问题的验证过程。3.2 库版本和 Arduino AVR 架构的常见坑在库管理器里安装的 MFRC522 库通常是较新的版本一般没问题。但有几种情况会翻车你之前装过老版本的库里面没有MIFARE_SetUid方法编译我们后面写的复制器代码会报错。解决方法是在库管理器里把 MFRC522 升级到 1.4.10 以上。Arduino IDE 同时加载了其他库也存在 SPI 引脚冲突的可能。比如某些TFT库会占掉 D10~D13导致编译出问题。代码里如果只需要 RC522记得把其他没用的库注释掉。如果你用的是 ESP32、ESP8266 等非 AVR 平台MFRC522 库也可以用但片选引脚的定义方式和初始化逻辑会和 UNO 略有不同。这个项目我先按 UNO 讲其他平台的读者需要自行调整。编译环境搭好以后先把基础读 UID 代码烧进去测试确认硬件没问题再继续做复制功能。4. 完整代码先读卡再复制 UID标题说了附完整代码这里我分三段给第一段是最基础的读 UID 代码适合验证硬件第二段是完整可用的 UID 复制器代码能把你想要复制的源卡 UID 写到目标可写 UID 卡上第三段讲全卡数据复制的思路和关键函数不贴超长代码但思路是清晰的。4.1 一段最基础的读 UID 代码这段代码只做一件事放卡上去串口打印卡片的 UID 和类型。它也是所有后续功能的地基。#include SPI.h #include MFRC522.h #define RST_PIN 9 #define SS_PIN 10 MFRC522 mfrc522(SS_PIN, RST_PIN); void setup() { Serial.begin(115200); SPI.begin(); mfrc522.PCD_Init(); Serial.println(F(Place a card near the antenna...)); } void loop() { if (!mfrc522.PICC_IsNewCardPresent()) { return; } if (!mfrc522.PICC_ReadCardSerial()) { return; } Serial.print(F(Card detected, UID )); for (byte i 0; i mfrc522.uid.size; i) { if (mfrc522.uid.uidByte[i] 0x10) { Serial.print(0); } Serial.print(mfrc522.uid.uidByte[i], HEX); } Serial.println(); MFRC522::PICC_Type piccType mfrc522.PICC_GetType(mfrc522.uid.sak); Serial.print(F(Card type: )); Serial.println(mfrc522.PICC_GetTypeName(piccType)); mfrc522.PICC_HaltA(); mfrc522.PCD_StopCrypto1(); }把这段代码烧进板子打开串口监视器波特率选 115200卡放上去你会看到类似Card detected, UID 04A1B2C3的输出。如果串口完全没反应先看硬件接线和供电别急着往下走。4.2 带串口指令的 RC522 UID 复制器读 UID 只是开胃菜。完整的复制器逻辑是这样先放源卡发送r程序读取并保存源卡 UID然后换上目标可写 UID 卡发送w程序用MIFARE_SetUid把源卡 UID 写入目标卡。#include SPI.h #include MFRC522.h #define RST_PIN 9 #define SS_PIN 10 MFRC522 mfrc522(SS_PIN, RST_PIN); byte sourceUid[10]; byte sourceUidSize 0; bool hasSource false; void printUid(const char* label, byte* uid, byte len) { Serial.print(label); Serial.print(F( )); for (byte i 0; i len; i) { if (uid[i] 0x10) { Serial.print(0); } Serial.print(uid[i], HEX); } Serial.println(); } bool readCurrentCard() { if (!mfrc522.PICC_IsNewCardPresent()) { return false; } if (!mfrc522.PICC_ReadCardSerial()) { return false; } printUid(Current card, mfrc522.uid.uidByte, mfrc522.uid.size); return true; } void setup() { Serial.begin(115200); while (!Serial); SPI.begin(); mfrc522.PCD_Init(); Serial.println(F(RC522 UID Copier)); Serial.println(F(Commands:)); Serial.println(F( r : read the card on the reader as source)); Serial.println(F( w : write the source UID to the card on the reader)); } void loop() { if (!Serial.available()) { return; } char cmd Serial.read(); while (Serial.available()) { Serial.read(); } if (cmd r) { if (!readCurrentCard()) { Serial.println(F(No card found. Put one on the reader.)); return; } if (mfrc522.uid.size ! 4) { Serial.println(F(This example supports 4-byte UID cards only.)); hasSource false; return; } sourceUidSize mfrc522.uid.size; memcpy(sourceUid, mfrc522.uid.uidByte, sourceUidSize); hasSource true; printUid(Saved source, sourceUid, sourceUidSize); Serial.println(F(Now remove source card, place target UID-writable card, send w.)); } else if (cmd w) { if (!hasSource) { Serial.println(F(No source UID yet. Send r first.)); return; } if (!readCurrentCard()) { Serial.println(F(No card found on the reader.)); return; } Serial.println(F(Trying to overwrite UID...)); MFRC522::StatusCode status mfrc522.MIFARE_SetUid(sourceUid, sourceUidSize, true); if (status MFRC522::STATUS_OK) { Serial.println(F(SetUid OK. Put the card away and re-send r to verify.)); } else { Serial.print(F(SetUid failed, status 0x)); Serial.println(status, HEX); Serial.println(F(Most likely this card has a locked factory UID.)); } hasSource false; } }代码里MIFARE_SetUid是 MFRC522 库封装好的方法专门用于给 UID 可写卡修改块 0 里的 UID 数据。注意普通原厂 Mifare 卡块 0 被硬件保护写入会失败只有 UID 可写卡才支持这种操作。实际操作时串口监视器要在发送区域选择新行Newline输入r后回车。程序读取源卡 UID 后会有提示之后再换目标卡、输入w。写完后为了确认目标卡 UID 确实变了可以把目标卡重新放上去发送r看打印出的 UID 是否和源卡一致。4.3 如果想复制整个 M1 卡的数据UID 复制只解决了最简单的一类门禁。如果门禁系统校验的是卡内扇区数据你需要的是全卡数据复制。思路是先用默认密钥通常为 FFFFFFFFFFFF把源卡 16 个扇区的数据全部读出来再写入目标卡对应扇区。MFRC522 库自带的 DumpInfo 示例可以打印完整数据但你要自己写一个边读边写的代码。核心流程分三步对每个扇区执行一次密钥认证调用mfrc522.PCD_Authenticate用mfrc522.MIFARE_Read读取该扇区 4 个块的数据到缓冲区对目标卡同样也执行密钥认证然后用mfrc522.MIFARE_Write把缓冲区数据写入对应块。MIFARE_Write的关键用法是MFRC522::StatusCode status mfrc522.PCD_Authenticate( MFRC522::PICC_CMD_MF_AUTH_KEY_A, blockAddr, key, (mfrc522.uid)); status mfrc522.MIFARE_Write(blockAddr, buffer, 16);这里 buffer 是一个 16 字节的数组存着要写入的数据。写的时候要注意目标卡的块 0 一般不能随便写除非你用的还是 UID 可写卡每个扇区的块 3 是密钥和控制位写入后可能把扇区锁死操作前最好把源卡的块 3 数据完整保存下来并且确保目标卡该扇区可写。全卡复制比 UID 复制复杂因为不同卡片的访问控制位不一样。有些目标卡某个扇区只允许用 B 密钥写你拿着 A 密钥也认证不过去。所以如果你还不熟悉 Mifare 卡的访问位我建议先拿 UID 复制练手熟悉后再做全卡复制。5. 实测过程和几个容易翻车的地方代码写好后我第一次实测还算顺利但中间也踩了几个坑。下面是我的实际测试流程以及后来复盘时发现的问题。5.1 实际操作步骤先把复制器代码编译烧录到 Arduino。打开串口监视器波特率 115200发送区选新行。我把源卡一张小区门禁 IC 卡放到 RC522 天线上面串口输入r输出Current card 04A1B2C3 Saved source 04A1B2C3然后把源卡拿走放上一张新的 UID 可写卡输入w输出Current card 12345678 Trying to overwrite UID... SetUid OK.最后把这张刚写完的卡再放上去输入r确认 UID 已经变成04A1B2C3。之后拿去门禁上一刷指示灯正常亮起开门成功。整个流程不到一分钟。整套流程中我发现一个有价值的细节MIFARE_SetUid 写入成功后目标卡虽然 UID 变了但如果你马上再去读有时候会读到旧值这是因为 RC522 在完成写 UID 后需要重新上电或再发一次 REQA 唤醒卡片。稳妥做法是写完后把卡移开再放上去重新读一次确认。上面的代码里也提示了re-send r to verify。5.2 识读距离短、读不到卡RC522 模块的读卡距离理论上在 3~5 厘米实际使用中经常不到 2 厘米。我第一次测试时卡要贴到天线上才有反应这是因为我把模块放在了一块金属桌面上天线磁场被金属吸收了一部分。把模块悬空或者下面垫一张泡沫板距离明显恢复。还有一个原因是供电不足。我一开始用一根过长的杜邦线从 Arduino Nano 的 3.3V 引出来刷卡时模块电压掉到 3.1V 以下偶发读卡失败。换了粗短的杜邦线或者从外部 3.3V 电源供电问题消失。5.3 写 UID 失败的排查写 UID 这一步最容易出现SetUid failed, status 0x...。可能的情况有这么几种目标卡是普通白卡不是 UID 可写卡。普通 Mifare 卡块 0 出厂锁死不可能改写。买卡的时候认准UID 可写卡或UID 卡别买成普通 S50。UID 可写卡被重复写入太多次部分卡在特定条件下会把块 0 重新锁死。我遇到过一张卡写成功一次后再写第二张就失败后来换了一张新卡就正常。这类卡本来就是消耗品别指望无限次写。源卡 UID 不是 4 字节。Mifare Classic 的 UID 常见是 4 字节但也有 7 字节的。MIFARE_SetUid对 4 字节支持最好7 字节的卡不建议用这个方案。供电电压瞬间跌落导致写卡命令不完整。排查方法和读卡距离短一样先看 3.3V 电压是否稳定。5.4 复制完门禁还是打不开如果 UID 确实写成了但门禁不认大概率是门禁还校验了卡内数据。这种场景下你要么做全卡数据复制要么检查门禁是否还有滚动码、防复制机制。RC522 只是一个读卡器它做不了动态密钥的破解和模拟不要在这上面浪费时间。遇到这种卡直接承认复制不了才是正常的工程思维。6. 做完之后还能往哪个方向扩展这个项目做完你会发现 Arduino 和 RC522 的组合其实能玩出不少花样门禁卡复制只是其中一个应用。一个简单扩展是把读卡结果显示到 OLED 屏上。你可以在原来代码基础上加一块 0.96 寸 OLED用 I2C 接口刷到卡时屏幕直接显示 UID 和卡类型不需要一直开着电脑看串口。这样它就变成一个口袋里的取卡器出差去外地忘了门禁卡掏出来对一下卡号方便排查。另一个扩展是做成一个多 UID 切换器。准备一个 UID 可写卡通过两个按键存储不同门禁的 UID需要刷哪个门禁就先把对应 UID 写入这张卡。搭配锂电池和一个小外壳就是一个便携卡工具。这个做起来比复制器多不了几行代码但实用性提升明显。还有更进阶的玩法在 Arduino 上接一个继电器模块把 RC522 读到的 UID 和白名单里的值比较匹配就吸合继电器模拟一个简单的门禁控制器。这个项目能让你把自己学的 RFID 知识和实际场景打通后面想接电动门锁、智能快递柜模型思路都是一个路子。如果你想把门禁卡放到手机里模拟RC522 就不太合适了。手机 NFC 模拟卡需要手机端和门禁读卡器都支持相关协议和 Arduino 侧关系不大。RC522 的价值在于它是个开放的读写平台让你能直观看到卡片内部的逻辑而不是像手机那样把一切都封装在黑盒里。我个人玩这个项目的最大收获是把之前书上看来的扇区密钥认证块 0 不可写这些概念通过串口输出一个个验证了一遍。技术这东西光看资料总觉得抽象真正跑起来踩几个坑很多问题就通了。希望这篇分享能帮你少走一点弯路也提醒一句做出来之后先拿自己手上的废弃卡和合法门禁试别去打别人卡的主意。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑