ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Arduino+RC522 DIY NFC门禁卡复制器:从读取到写入完整教程

2026/10/5 6:22:45 拓冰建站 浏览量
Arduino+RC522 DIY NFC门禁卡复制器:从读取到写入完整教程 1. 项目概述为什么有人要DIY一个NFC门禁卡复制器先聊点实际的。NFC门禁卡复制器这个项目我在不同平台上看到过很多次提问讨论热度一直不减。原因很简单生活中需要用到门禁卡的场景太多了——公司大楼、小区单元门、地下车库、健身房、甚至部分酒店的电梯楼层权限都是一张卡片的事。但问题在于卡片容易丢、容易忘带或者你需要在多个地方用卡但只有一张实体卡。Arduino配合RC522模块做NFC读写器是目前门槛最低、资料最全、成本最友好的方案。整套硬件成本控制在20到30元以内软件部分使用现有的MFRC522库代码量也不大哪怕你只是刚接触Arduino的小白基本也能在一个晚上搞定。这个项目解决的核心问题有三个一是把实体门禁卡的数据读取出来二是将数据写入到空白卡或UID可写的卡中三是在此基础上理解RFID低频/高频通信的基本原理。需要提前说明的是我做这个项目纯粹是为了技术学习和研究。门禁卡复制涉及安全与合规问题不同地区对门禁卡复制的法律法规不同请务必确保你的操作只用于自己的设备、自己的卡并且征得管理方的同意。本文的所有内容出发点都是帮助你理解RFID/NFC的工作原理而不是提供违法工具。适合看这篇博文的人包括刚入门Arduino的电子爱好者、工作中需要批量配置门禁卡的运维人员、对RFID原理感兴趣的软件开发者以及单纯觉得“读卡写卡”这件事很酷、想自己试试的折腾型玩家。如果你是零基础也没关系我会从选型、接线、代码到调试一步步讲清楚过程中你踩过的坑大概率我早期也都踩过。2. 硬件准备与接线2.1 RC522模块到底是个什么东西RC522是NXP恩智浦推出的一款低功耗、低成本的非接触式读写芯片工作在13.56MHz频段支持ISO/IEC 14443A协议。市面上几乎所有常见的M1卡也就是S50卡、NTAG系列标签都兼容这个协议。RC522模块的通信方式有三种SPI、I2C和UART实际使用中绝大多数人选择SPI因为速度最快、稳定而且Arduino的SPI库非常成熟。模块正面通常是一块印刷天线那圈线圈背面是RC522芯片和外围电路引脚一般引出8个SDA、SCK、MOSI、MISO、IRQ、GND、RST、VCC。很多新手容易搞混的是SDA和RSTSDA在SPI模式下是片选信号SS不是I2C的数据线而RST虽然名字和Arduino的复位引脚一样但这里不是Arduino的复位是RC522芯片的复位输入用来控制芯片的使能和复位时序。关于模块的供电RC522芯片本身工作电压是2.5V到3.3V但这不意味着你只能从Arduino的3.3V引脚取电。常见的模块上一般都带了电平转换电路所以可以直接接5V的VCC。不过这里有个容易踩坑的点不同厂家的模块电路设计略有差异有的模块确实标注支持5V供电但有的比较老的模块或者出厂质量不稳定的直接接5V可能导致芯片发烫。我个人的习惯是如果手头方便直接从Arduino的3.3V供VCC这样最稳妥尤其当你用的是Arduino Uno或Nano时3.3V输出电流足够RC522使用了。2.2 与Arduino Uno的接线对照表整张接线表其实非常固定下面是我惯用的接法照着接基本不会出错。这里以最常见的Arduino Uno为例如果你用的是Nano引脚定义也是完全相同的Nano和Uno的SPI引脚都在同一位置但要注意Nano的D11对应MOSI、D12对应MISO、D13对应SCKD10是SS。如果你用的是ESP8266、ESP32、STM32等其他板子就需要查一下对应芯片的SPI引脚定义不要盲目照搬。RC522引脚Arduino Uno/Nano引脚说明SDAD10SPI片选信号低电平有效也就是SSSCKD13SPI时钟信号MOSID11主机输出从机输入MISOD12从机输出主机输入IRQ不接中断请求脚本项目中不用GNDGND共地必须接RSTD9RC522复位引脚VCC3.3V建议从3.3V取电有几个细节值得单独说一下。IRQ引脚在绝大多数入门教程里都是悬空不接的这个没问题。如果你以后想做一个“靠近即触发”的感应门而不是轮询读卡才需要把IRQ接到Arduino的外部中断引脚上配合中断方式来节省CPU资源。但在这个项目里我们只需要循环检测有没有卡片靠近IRQ用不上悬空即可。RST引脚接D9这个是可配置的。在MFRC522库里构造函数会接收两个参数第一个是SS引脚第二个是RST引脚你完全可以把RST接到其他数字脚只要代码里对应改一下就行。我之所以默认D9是因为大家在写代码时习惯用MFRC522 mfrc522(SS_PIN, RST_PIN)而SS_PIN是10、RST_PIN是9这个组合在几乎所有示例代码里都能见到算是社区事实标准。VCC这里我再强调一次。虽然很多模块板载了稳压和电平转换但我建议优先接3.3V。RC522的天线驱动电流不大实测在3.3V供电下读卡距离大概能到3到5厘米5V供电下读卡距离也不会显著增加反而可能因为模块上的LDO发热导致性能不稳定。供电电压的稳定比电压高低更重要这一点在后面的调试部分还会再提。2.3 准备一张可写的空白卡做复制器至少需要一张空白卡作为“复制目标”。你需要仔细区分两种卡第一种是M1标准卡也就是S50卡容量1KB出厂时默认会有官方传输密钥KeyA和KeyB通常都是FFFFFFFFFFFF。这种卡绝大多数门禁系统在用。对于普通的M1卡只要密钥是默认的你就能直接读取所有扇区数据也能写入新的数据。第二种是UID可写卡也叫UID卡、CUID卡、FUID卡等。普通M1卡的UID唯一标识符也就是卡号在出厂时一次性写入之后不能修改。而UID卡允许你修改卡号这一块方便做“一卡复制多卡”之类的门禁卡复制操作。如果你只是想把A卡的数据完整复制到B卡那么B卡必须是这张UID卡否则卡号那一段写不进去。去淘宝搜“UID卡”或者“M1空白卡”一搜一大把。需要注意买卡的时候看清楚FAQ说明有些便宜的空卡是S50标准卡它的UID写不了只能写扇区数据这对于本项目的“完整复制”目标是不够的。预算充足的话CUID卡是很稳的选择——它比UID卡多了一层兼容性处理理论上可以被更多读卡器识别不容易出现那种“复制完读卡器反而不认”的情况。3. 核心原理M1卡的存储结构到底长什么样S50卡M1卡的内部存储结构很多人看了很多遍源码依然记不清楚但一旦你想做门禁卡复制器的读写操作这部分是绕不开的。M1卡的总容量是1KB分为16个扇区编号0到15每个扇区由4个块组成块0到块3每个块16字节所以总数是16乘4乘16等于1024字节正好1KB。其中每个扇区的最后一个块块3叫“尾部块”存放这个扇区的KeyA、访问控制位、KeyB。KeyA在地址0到5字节访问控制位在第6到9字节KeyB在第10到15字节。普通情况下读卡验证时只要KeyA对了就能读取这个扇区的块0到块2的数据。而访问控制位的核心功能是决定KeyA和KeyB各自能对这个扇区做什么操作。扇区0的块0是特殊区域它被叫作厂商块存放卡片的UID4字节、UID校验位、厂商数据和厂商自定义数据。即使你用的是UID卡厂商块也不是随意改的需要相对特殊的写操作一般的复制流程里我们会单独处理它。这就是为什么M1卡数据复制不能简单地“整体拷贝”而要分区处理、分块处理。真正有价值的门禁数据比如楼层权限、有效日期、工号等储存在扇区1到15的数据块里具体哪个扇区放什么完全取决于门禁厂家的自定义设计。常见的小区门禁系统使用的是扇区1的块0或块1来存储卡号具体位置没法从一个模块的封装看出只能通过读卡之后的实际数据去推测或者查阅对应门禁品牌的文档。此外门禁卡并不一定都是M1卡。很多新小区的门禁已经换成了CPU卡如FM1208、NXP Desfire EV1等这些卡是高安全性卡RC522模块通过ISO 14443A能读到的只有UID无法读取扇区数据更不可能复制。所以你在操作之前建议先把卡放在安卓手机的NFC功能下读一下很多安卓手机自带“触碰付款”里能看到卡类型或者用RC522读一下看看返回的卡片类型是MIFARE Classic 1K还是其他型号。如果说这个卡压根不是M1卡那本方案直接作废。4. 软件配置与完整代码解析4.1 安装MFRC522库代码方面首先需要一个开源库MIGUEL GOMEZ编写的MFRC522库这是目前Arduino社区最常用的RC522驱动库。在Arduino IDE的库管理器里搜索MFRC522通常第一个就是。安装最新版本即可。这里有个小坑要提醒一下另一个常见的库叫RFID作者是Miguel Balboa功能类似但API和MFRC522库不同。很多新手从网上复制一段代码然后发现自己装的库和代码对不上号编译报错一头雾水。我个人的建议是直接认准库里头的头文件名字如果你在代码里看到#include SPI.h和#include MFRC522.h那么你装的就是MFRC522库。如果看到#include RFID.h那就要换成RFID库。本文全部使用MFRC522库。4.2 完整代码读取卡片UID和扇区数据#include SPI.h #include MFRC522.h #define SS_PIN 10 #define RST_PIN 9 MFRC522 mfrc522(SS_PIN, RST_PIN); void setup() { Serial.begin(115200); SPI.begin(); mfrc522.PCD_Init(); Serial.println(F(RC522 Ready, place card near reader...)); } void loop() { if (!mfrc522.PICC_IsNewCardPresent()) { return; } if (!mfrc522.PICC_ReadCardSerial()) { return; } Serial.print(F(Card UID: )); dump_uid(mfrc522.uid.uidByte, mfrc522.uid.size); MFRC522::MIFARE_Key key; for (byte i 0; i 6; i) { key.keyByte[i] 0xFF; } dump_all_sectors(key); mfrc522.PICC_HaltA(); mfrc522.PCD_StopCrypto1(); } void dump_uid(byte *uid, byte uidSize) { for (byte i 0; i uidSize; i) { if (uid[i] 0x10) { Serial.print(F(0)); } Serial.print(uid[i], HEX); if (i uidSize - 1) { Serial.print(F( )); } } Serial.println(); } void dump_all_sectors(MFRC522::MIFARE_Key *key) { byte buffer[18]; byte block 0; byte status; for (byte sector 0; sector 16; sector) { status mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, sector * 4, key, (mfrc522.uid)); if (status ! MFRC522::STATUS_OK) { Serial.print(F(Auth failed at sector )); Serial.println(sector); continue; } for (byte blockOffset 0; blockOffset 3; blockOffset) { block sector * 4 blockOffset; byte size 18; status mfrc522.MIFARE_Read(block, buffer, size); if (status MFRC522::STATUS_OK) { Serial.print(F(Sector )); Serial.print(sector); Serial.print(F( Block )); Serial.print(block); Serial.print(F(: )); for (byte i 0; i 16; i) { if (buffer[i] 0x10) { Serial.print(F(0)); } Serial.print(buffer[i], HEX); Serial.print(F( )); } Serial.println(); } else { Serial.print(F(Read failed at block )); Serial.println(block); } } Serial.println(F(---)); } }这段代码分成几个功能块下面逐个拆解。首先setup()里初始化串口和SPI总线然后通过mfrc522.PCD_Init()初始化RC522模块。如果你在串口监视器里看不到“Ready”提示基本就是SPI接线有问题或者RC522的RST引脚接触不良。其次loop()里最重要的函数是PICC_IsNewCardPresent()这个函数检测有没有新的卡片靠近天线区域注意它是“新卡”检测如果你把卡一直贴着读卡器它可能只触发一次因为检测逻辑是捕捉从无到有的变化。常见的坑是卡放上去没反应你可以把卡拿开再放一次。PICC_ReadCardSerial()用于读取卡片的UID并完成防碰撞处理之后mfrc522.uid结构体里就有卡片UID数据。dump_uid()是把UID按十六进制格式化输出。比如一张卡的UID如果是0x04 0x12 0x34 0x56 0x78就会打印成04 12 34 56 78。这里有个小技巧字节小于0x10时补一个前导零否则输出会乱尤其是UID里包含0A、0B之类的字节时。dump_all_sectors()是核心读取逻辑。循环变量sector从0到15对每个扇区先通过PCD_Authenticate做密钥认证这里用的密钥是6个0xFF字节也就是MFare Classic卡出厂默认的KeyA。如果门禁系统没有修改过密钥这个认证就会成功。认证通过后再读这个扇区的块0到块2每个读操作16字节保存在buffer中打印出来。扇区的块3尾部块我没有打印因为里面是密钥和访问位属于安全敏感数据而且对普通复制操作而言块3的数据在写入时通常也要重新计算不是简单照抄即可。4.3 完整代码写入扇区数据到空白卡读取之后是写入。写卡代码的骨架和读卡非常相似核心差异是把MIFARE_Read换成MIFARE_Write。下面这段代码会把data数组中的16个字节写入到指定的块中。#include SPI.h #include MFRC522.h #define SS_PIN 10 #define RST_PIN 9 MFRC522 mfrc522(SS_PIN, RST_PIN); void setup() { Serial.begin(115200); SPI.begin(); mfrc522.PCD_Init(); Serial.println(F(RC522 Writer ready.)); } void loop() { if (!mfrc522.PICC_IsNewCardPresent()) { return; } if (!mfrc522.PICC_ReadCardSerial()) { return; } MFRC522::MIFARE_Key key; for (byte i 0; i 6; i) { key.keyByte[i] 0xFF; } // 把下面的16字节数据修改成你从读卡步骤中获取到的数据 byte data[16] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10 }; byte targetBlock 4; // 举例扇区1的块0实际根据门禁系统而定 byte status mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, targetBlock, key, (mfrc522.uid)); if (status ! MFRC522::STATUS_OK) { Serial.print(F(Auth failed: )); Serial.println(status); } else { status mfrc522.MIFARE_Write(targetBlock, data, 16); if (status MFRC522::STATUS_OK) { Serial.println(F(Write OK)); } else { Serial.print(F(Write failed: )); Serial.println(status); } } mfrc522.PICC_HaltA(); mfrc522.PCD_StopCrypto1(); }这段代码里最需要注意的是MIFARE_Write要求目标块是数据块不是尾部块而且块地址必须和认证时使用的扇区对应。我上面默认写入到扇区1的块0也就是块地址4这只是一个示例。现实情况中你大概率需要将从原卡读出来的所有扇区数据逐一搬到新卡中所以我建议把写入逻辑写成循环遍历扇区类似于读卡时的遍历方式只不过把打印换成写入。写入区块有一点是非常容易踩坑的如果你写入的数据块在原卡里存储的数据本身带有CRC校验那么你把扇区数据写过去了但对应的校验字节却没有跟着更新门禁系统读卡时会认为数据无效表现为“能读到卡号但打不开门”。所以如果你在做完整复制最稳妥的方式是除了UID需要单独处理之外把扇区1到15的每个数据块原样搬过去同时把尾部块的访问控制位和密钥也按照原卡计算后写进去。不过访问控制位的计算不是简单的16进制拷贝需要做位运算和权限推导这部分在技术上相对复杂KJD的话如果你只是复制家门门禁卡很多系统认的就是UID加一两个数据块不用把所有扇区都搬过去。你可以先只复制UID和数据块如果门禁不认再进一步做扇区级的完整镜像。4.4 关于UID写入的特殊处理如果你买的是UID卡支持修改UID的M1卡你还需要写厂商块。厂商块的块地址是0里面前4字节是UID第5字节是UID校验位第6到第10字节是厂商数据后面还跟着其他设定。直接用普通的MIFARE_Write写块0是无效的RC522会拒绝这一操作因为厂商块有特殊保护机制。处理思路有几种。第一种是用MFRC522库中专门针对UID写入的私有命令比如MIFARE_UL Write、PICC_CMD_HLTA等但MFRC522库本身对厂商块的写入支持不太友好很多人在这个环节会卡住。第二种是换一个库使用MFRC522Extended或者直接调用RC522的命令寄存器做底层访问实现过程较为复杂。第三种是使用UID卡自带的后门指令市场上很多CUID卡带有出厂后门比如说特定指令允许你随意改写厂商块但这依赖卡厂的实现不一定所有卡都支持。如果你只做入门实验我建议先放弃写UID这一步重点放在扇区数据的读写上。因为很多门禁系统验证的是扇区里的数据比如工号、日期不一定是UID而且M1卡在默认密钥下的扇区数据读写已经能让你跑通整个项目流程。等后面你确实有需求要改UID再去研究对应卡型的数据手册方向不至于跑偏。5. 实操过程从读取到复制一份可用的门禁卡5.1 操作流程总览整个项目的实操流程我的建议是先跑通“读取”再跑“写入”最后才做“完整复制”。很多人一上来就想着把卡复制出来结果连串口都没调通无从下手。正确顺序是接线上传读取程序打开串口监视器确认能打印出卡片的UID。用原卡做一次扇区数据扫描记录数据内容。用空白卡做一次写入测试确认能写入任意数据并重新读出来。对照原卡的数据逐扇区写入到空白卡中。在门禁机或手机NFC上测试复制卡是否正常使用。接下来我把每个步骤讲细一些。第一步接线说实话没什么技术含量但最容易出问题。Arduino Uno的SPI引脚和RC522的引脚对应关系我已经在表格里列出来了。有一个很容易被忽略的坑部分RC522模块的引脚丝印是反的我之前买过一版模块SDA和SCK印反了接上去怎么都读不到卡折腾了半天排查发现是丝印错误。所以如果你严格按照表格接线却读不到卡先用万用表测一下引脚通断或者干脆换一块模块试试。第二步读卡。上传完代码打开串口监视器波特率选115200。将原卡靠近天线串口窗口会打印“Card UID: xx xx xx xx”紧接着打印各个扇区的内容。如果卡使用了非默认密钥PCD_Authenticate会返回16进制错误码扇区会显示Auth failed这时你就需要知道原卡的密钥或者放弃读取该扇区。很多门禁卡的密钥不是默认0xFF这种情况门禁卡的数据读取就非常困难了除了暴力破解理论上可以离线破解M1卡但这属于另一个大话题之外没有什么简单办法。第三步写测试数据。把空白卡放到读卡器上运行写卡程序确认串口打印Write OK然后立刻用读卡程序重新读一下这块空白卡看看刚写入的16字节是否能在对应块中被正确读出来。这块操作主要验证模块的写功能是否正常以及空白卡是真正的可写卡。如果你写入后重新读取发现数据是乱的或者读出失败大概率是卡质量问题建议换一张不同品牌的卡试试。第四步执行完整复制。这一步需要你先把原卡所有扇区的块0到块2数据记录下来用4.2节代码的打印结果然后修改4.3代码中的data数组逐块写入到空白卡。我这里建议把原卡的数据整理到一个结构体或二维数组里然后在循环里批量写入而不是手工一个个改这样效率高还不容易出错。写完后最好再用读卡程序扫描一遍写入结果和原卡数据逐字节比对确保没有因为写入中途断电或者接触不良造成数据丢失。最后一步拿到门禁上测试。把复制卡靠近门禁读卡器观察门禁的反应。如果门禁里有“滴滴”声或者亮绿灯说明卡通过了认证如果完全没反应可能的原因有很多UID没写进去、访问控制位不对、扇区密钥不对甚至门禁系统启用了防复制机制。这部分排查我会在下一节详细说明。5.2 实操中的记录一次典型的复制过程演示为了让你有更直观的感觉我这里模拟一次实际操作的输出。假设原卡是一张M1卡UID为04 A2 15 6B 33 80通过读卡程序得到扇区1的数据如下这里只列出前几个关键字节Sector 1 Block 4: 01 23 45 67 89 AB CD EF 00 00 00 00 00 00 00 00 Sector 1 Block 5: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Sector 1 Block 6: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Sector 2 Block 8: 12 34 56 78 90 12 34 56 78 90 12 34 56 78 90 12从扇区1的块0块地址4开头是01 23 45 67这一段来看这很可能不是卡号因为卡号就是UID本身。这块的89 AB CD EF有可能是一个日期或自定义编号具体含义要靠门禁厂家的数据格式才能确定。扇区2的块0块地址8数据看起来像是重复的卡号或数据密钥也在常理之中。对应的写入步骤中我会把一个空的UID卡先不修改UID然后把扇区1的块0写入01 23 45 67 89 AB CD EF 00 00 00 00 00 00 00 00扇区2的块0写入12 34 56 78 90 12 34 56 78 90 12 34 56 78 90 12其他块根据原卡逐一写入。这样一次典型的复制如果使用的是默认密钥整个项目在20分钟内就能从零跑到测试。如果门禁系统只认UID不认其他扇区数据那么这种情况下你还得想办法把UID复制过去才能达到完整复制的效果。6. 常见问题与排查技巧实录6.1 读不到卡先别怀疑模块坏了读不到卡是最常见的现象新手第一时间都会怀疑模块坏了、卡坏了。实际上最大的嫌疑是接线其次是供电。这里列一个典型排查顺序确认SPI的4根线SCK、MOSI、MISO、SDA连线无误。MISO和MOSI接反是高频错误。确认RST接的是D9并且代码里的RST_PIN定义是9。如果你把RST接到了8代码里还写着9那模块就一直处于复位状态怎么读都是失败。确认VCC供电。优先接3.3V。如果你接的是5V可以先用万用表量一下模块3.3V引脚是不是真的有3.3V输出。很多模块自带LDO如果模块没有LDO直接接5V会烧芯片。用示波器或逻辑分析仪看SPI总线上有没有数据波形。如果没有示波器可以在初始化之后打印mfrc522.PCD_ReadRegister(mfrc522.VersionReg)的返回值。正常情况下返回值是0x92或0x12如果读到0x00或0xFF说明SPI通信异常模块没有被Arduino识别。卡片类型必须是ISO 14443A的M1卡。如果你拿一张电梯里的CPU卡或者银行卡来测试RC522只能读出UID后面的扇区读取会失败但至少UID能打印出来。如果连UID都不出就说明卡片太近、太远、或被金属外壳屏蔽了。6.2 读卡距离太短RC522的有效读卡距离本来就不大标称5厘米实际在3厘米左右都很正常。如果你发现距离不足2厘米可能的原因有供电不足、天线线圈周围有金属干扰、模块天线设计和卡不匹配。改善距离的办法有几个确保模块背面不要直接贴在金属桌面上最好垫一层塑料片或者悬空安装检查供电不要和舵机、继电器这种大电流设备共用电源给天线区留足空间不要在模块正上方放置螺丝钉等金属物体。另一个容易被忽视的是如果你的Arduino通过USB供电而USB线质量很差、电阻大电流供应不够也会导致读卡距离缩水。6.3 写入数据后重新读出来是乱的这一般是写入数据时发生的问题或者卡本身有问题。先用读卡程序确认目标块在写前是否全为零。有些卡出厂不是全零而是带有测试数据如果你没擦除就直接写入新数据会覆盖旧数据理论上不会乱但有些卡的内部状态机在区块没有正确擦除时会写入失败返回状态码不是OK。然后检查你是不是在写尾部块块3。尾部块需要特殊处理如果把密钥和访问控制位写错了这个扇区会直接废掉后续认证都过不了。我建议新手先避开块3只操作块0到块2。另外写入速度也有影响。MIFARE_Write写入一个块需要几十毫秒如果在写入过程中卡片被移走了就会写入失败或写入部分数据。所以写卡时卡片要放稳不要动它。6.4 复制出来的卡在门禁上没反应这种情况比较多见逐一分析原因。第一原卡不是M1卡而是CPU卡或Desfire卡。RC522只能读出UID复制出的卡在门禁系统看来是一张“陌生卡”自然没反应。你可以用读卡程序看一下PICC_GetType返回的卡片类型如果显示的是PICC_TYPE_MIFARE_DESFIRE或其他类型说明这卡根本不适合本方案。第二门禁系统认的是UID。如果你没有把UID复制过去只是复制了扇区数据门禁不认很正常。解决方式是买UID可写卡然后研究厂商块的写入方法。第三门禁系统有“离线白名单”校验。很多门禁系统在发卡时会往卡内写入一个唯一的随机数或者加密证书门禁控制器在认证时不仅检查UID和扇区数据还要校验加密签名。这种复制出来的卡即使数据一模一样在门禁上也会被拒绝。这是目前门禁防复制的常见手段之一没有什么简单方案能绕过我也不建议为了绕过去而采取任何行动——合规使用才是底线。第四门禁的频率不匹配。极少数门禁系统使用的是125kHz的低频ID卡也叫EM4100卡而不是13.56MHz的M1卡。RC522无论如何都读不了125kHz的卡。如果你的门禁卡是一张很薄的卡放到手机上检测时手机没有任何NFC响应那它很可能就是低频ID卡这种情况你应该去搜索“ID卡复制”而不是“NFC复制”。6.5 串口打印乱码串口打印乱码基本上都是波特率不匹配。确认代码里Serial.begin设置的波特率和你电脑上串口监视器右下角的波特率选择一致。本文代码统一用的是115200如果你用的示例代码是9600那串口监视器也要同步改成9600。乱码之后你什么都看不清这会让你误以为程序出了问题。6.6 模块发热严重RC522模块发热严重一般有两个原因。一个是VCC接了5V但板载LDO质量不好发热大另一个是SPI速率太高导致芯片内部耗电上升。解决方法是VCC改接3.3V同时在SPI.begin后面手动降低SPI时钟频率。可以用SPI.setClockDivider(SPI_CLOCK_DIV16)把SPI频率降到1MHz左右RC522在这个频率下工作完全够用而且稳定很多。7. 一些经验心得与安全建议做完这个项目之后我最大的感受是Arduino加RC522这个组合很适合作为RFID入门的第一块跳板。它低成本、低门槛、资料多而且从硬件的角度来看你接触到的SPI通信、M1卡存储结构、密钥认证机制这些都是通用知识换到其他平台一样适用。比如你以后想做一个基于ESP32的NFC配网工具或者想给树莓派的项目加一个NFC感应模块思路和代码逻辑基本可以平移过去只需要调整硬件引脚和库的适配。还有一点个人体会MFRC522这个库虽然简单但它把很多底层细节封装得太好了反而容易让人忽略真正重要的部分。比如你知道MIFARE_Read该怎么调用但如果不了解块地址和扇区地址之间的关系你根本不知道为什么要传4这个参数、为什么扇区1对应块地址4到7。建议你花点时间把M1卡的存储结构读透这比代码本身有价值得多。写代码的时候我建议你习惯性地在读写前后添加日志输出方便排查问题。在你读写卡的过程中很多问题并不是逻辑问题而是模块和卡之间的物理交互问题日志里多打印状态码和读回的数据能让你很快定位问题出在哪一步。最后安全方面的提醒必须再次强调NFC/RFID技术本身是中性的但复制他人门禁卡、未经授权读取他人卡片信息明显涉及个人隐私和公共安全问题有可能违反当地法律法规。我在“项目概述”里就说了这是一个学习项目请把它用于你自己的卡、自己的门禁或者在有明确授权的环境中使用。我更建议大家把这个项目当成一个理解RFID协议的切入点在此基础上探索门禁系统安全性、数据加密防护从防护者的角度思考问题而不要越界做违规的事。另外这个项目后续还能怎么扩展我给你几个方向。第一加入OLED显示屏和键盘做成一个离线写卡器不用每步都依赖电脑串口。第二换用ESP32加一个Web服务器通过手机浏览器远程控制读卡写卡。第三加一个蜂鸣器和LED做成一个优雅的“滴一声就完成”的流程而不是每次看串口输出。第四尝试用树莓派加PN532模块来处理UID厂商块的写入功能更全也更能深入理解RFID底层协议。每个方向都有大量的学习空间祝你折腾得开心也折腾得安全。