用STM32F103和RC522模块DIY一个门禁卡复制器?手把手教你读写M1卡(附完整代码) STM32与RC522模块实战深入理解M1卡读写机制与安全实践1. RFID技术基础与M1卡结构解析在物联网和嵌入式系统领域RFID射频识别技术已经成为不可或缺的重要组成部分。Mifare Classic 1K卡片简称M1卡作为13.56MHz高频RFID的典型代表广泛应用于门禁系统、公交卡和小额支付等场景。M1卡的核心特性1KB EEPROM存储空间分为16个扇区每个扇区包含4个块Block每块16字节每个扇区的块3为控制块存储两个密钥Key A和Key B及访问控制位采用ISO/IEC 14443 Type A通信协议典型读写距离2-10cm取决于天线设计M1卡的存储结构可以用以下表格清晰表示扇区号块0块1块2块3控制块0厂商信息只读数据块数据块密钥A控制位密钥B1-15数据块数据块数据块密钥A控制位密钥B重要提示扇区0的块0存储厂商信息出厂时已固化不可修改这保证了每张卡片的唯一性标识。2. 硬件搭建与开发环境配置2.1 所需硬件组件实现M1卡读写功能需要以下硬件组件STM32F103开发板如正点原子精英版RFID-RC522读写模块M1卡片钥匙扣卡或标准卡片杜邦线若干USB转TTL串口模块用于调试输出RC522模块引脚定义SDA - 片选信号SCK - SPI时钟MOSI - 主机输出从机输入MISO - 主机输入从机输出IRQ - 中断信号本项目中未使用GND - 地线RST - 复位信号VCC - 3.3V电源2.2 硬件连接指南将RC522模块与STM32F103连接时需按照以下对应关系接线RC522引脚STM32引脚功能说明SDAPA4SPI片选SCKPA5SPI时钟MOSIPA7主出从入MISOPA6主入从出RSTPB0复位信号GNDGND共地VCC3.3V电源输入注意RC522模块工作电压为3.3V切勿接入5V电源否则可能损坏模块。2.3 开发环境准备软件工具链Keil MDK-ARM开发环境建议V5.25STM32CubeMX用于外设初始化串口调试工具如Putty或SecureCRT工程配置关键步骤// SPI初始化配置示例STM32CubeMX生成 void MX_SPI1_Init(void) { hspi1.Instance SPI1; hspi1.Init.Mode SPI_MODE_MASTER; hspi1.Init.Direction SPI_DIRECTION_2LINES; hspi1.Init.DataSize SPI_DATASIZE_8BIT; hspi1.Init.CLKPolarity SPI_POLARITY_HIGH; // RC522要求 hspi1.Init.CLKPhase SPI_PHASE_2EDGE; // 数据在第二个边沿采样 hspi1.Init.NSS SPI_NSS_SOFT; hspi1.Init.BaudRatePrescaler SPI_BAUDRATEPRESCALER_256; // ~140kHz hspi1.Init.FirstBit SPI_FIRSTBIT_MSB; hspi1.Init.TIMode SPI_TIMODE_DISABLE; hspi1.Init.CRCCalculation SPI_CRCCALCULATION_DISABLE; if (HAL_SPI_Init(hspi1) ! HAL_OK) { Error_Handler(); } }库函数准备标准外设库或HAL库RC522驱动程序需实现SPI底层读写函数3. M1卡读写操作深度解析3.1 卡片操作基本流程对M1卡进行读写操作需要遵循严格的通信协议流程寻卡Request探测射频场内的卡片防冲撞Anticollision获取卡片唯一标识UID选卡Select选定特定UID的卡片密钥验证Authentication验证扇区访问权限数据操作Read/Write执行实际的读写操作休眠Halt结束通信可选// 典型操作流程代码示例 void M1Card_Operate(uint8_t sector, uint8_t block, uint8_t* key, uint8_t* data) { uint8_t uid[4]; uint8_t status; // 1. 寻卡 status PcdRequest(PICC_REQALL, NULL); if(status ! MI_OK) return; // 2. 防冲撞获取UID status PcdAnticoll(uid); if(status ! MI_OK) return; // 3. 选卡 status PcdSelect(uid); if(status ! MI_OK) return; // 4. 密钥验证以Key A为例 uint8_t blockAddr sector * 4 3; // 计算控制块地址 status PcdAuthState(PICC_AUTHENT1A, blockAddr, key, uid); if(status ! MI_OK) return; // 5. 数据读写 uint8_t dataBlockAddr sector * 4 block; status PcdRead(dataBlockAddr, data); // 或PcdWrite // 6. 休眠可选 PcdHalt(); }3.2 密钥验证机制详解M1卡的安全性建立在密钥验证基础上每个扇区都有独立的两个密钥Key A和Key B和访问控制位。验证过程采用三重认证机制验证类型0x60表示验证Key A0x61表示验证Key B块地址只需指定目标扇区的任意块地址通常是控制块密钥6字节密钥默认通常为0xFF 0xFF 0xFF 0xFF 0xFF 0xFF卡片UID4字节唯一标识验证成功后才能对该扇区进行读写操作。访问控制位决定了密钥的具体权限典型配置如下控制位值Key A权限Key B权限0xFF078069不可读全权限可读无权限0xAABBCCDD自定义权限自定义权限安全建议实际应用中应修改默认密钥并合理设置访问控制位以提高安全性。4. 完整项目实现与代码分析4.1 系统初始化完整的RC522初始化包括硬件复位、SPI接口配置和工作模式设置void RC522_Init(void) { // 1. 硬件复位 RC522_Reset_Disable(); delay_us(1); RC522_Reset_Enable(); delay_us(1); RC522_Reset_Disable(); delay_us(1); // 2. 配置寄存器 WriteRawRC(CommandReg, PCD_RESETPHASE); WriteRawRC(ModeReg, 0x3D); // 定义发送和接收常用模式 WriteRawRC(TReloadRegL, 30); // 定时器低位 WriteRawRC(TReloadRegH, 0); // 定时器高位 WriteRawRC(TModeReg, 0x8D); // 定时器模式 WriteRawRC(TPrescalerReg, 0x3E); // 定时器分频 // 3. 设置ISO14443 Type A模式 M500PcdConfigISOType(A); // 4. 开启天线 PcdAntennaOn(); }4.2 核心功能实现数据读取功能uint8_t M1_ReadBlock(uint8_t sector, uint8_t block, uint8_t* data) { uint8_t status, uid[4]; uint8_t blockAddr sector * 4 block; // 1. 寻卡 status PcdRequest(PICC_REQALL, NULL); if(status ! MI_OK) return status; // 2. 获取UID status PcdAnticoll(uid); if(status ! MI_OK) return status; // 3. 选卡 status PcdSelect(uid); if(status ! MI_OK) return status; // 4. 密钥验证假设使用Key A uint8_t authBlock sector * 4 3; // 控制块地址 status PcdAuthState(PICC_AUTHENT1A, authBlock, DefaultKey, uid); if(status ! MI_OK) return status; // 5. 读取数据 status PcdRead(blockAddr, data); // 6. 休眠卡片 PcdHalt(); return status; }数据写入功能uint8_t M1_WriteBlock(uint8_t sector, uint8_t block, uint8_t* data) { uint8_t status, uid[4]; uint8_t blockAddr sector * 4 block; // 验证流程与读取相同... // 写入数据 status PcdWrite(blockAddr, data); // 验证写入结果 uint8_t readBack[16]; status PcdRead(blockAddr, readBack); if(memcmp(data, readBack, 16) ! 0) { return MI_ERR; } return MI_OK; }4.3 串口调试与数据可视化为了方便调试可以通过串口输出操作过程和结果void ShowCardInfo(uint8_t* uid, uint8_t* data) { printf(Card UID: ); for(int i0; i4; i) { printf(%02X , uid[i]); } printf(\r\n); printf(Data: ); for(int i0; i16; i) { printf(%02X , data[i]); if(i7) printf( ); // 8字节分隔 } printf(\r\n); }5. 安全实践与项目扩展5.1 合法使用与安全边界在开发RFID相关项目时必须注意以下法律和道德规范仅对自有卡片进行操作未经授权不得访问他人卡片不得复制具有版权保护或安全认证的卡片商业应用需获得相应资质和授权尊重隐私权不得非法收集或使用个人信息技术防护措施定期更换密钥不使用默认密钥合理设置访问控制位对敏感操作增加二次确认记录操作日志以备审计5.2 项目扩展方向基于本项目的核心功能可以进一步开发以下实用应用门禁系统原型实现UID白名单验证增加继电器控制电路添加管理界面电子钱包模拟实现余额存储和扣款加入简单加密算法设计充值功能智能储物柜卡片与储物柜绑定超时提醒功能远程管理接口考勤系统记录刷卡时间和UID数据统计分析报表生成功能// 简单门禁验证示例 uint8_t CheckAccess(uint8_t* uid) { // 定义合法UID列表 uint8_t validUIDs[][4] { {0x12, 0x34, 0x56, 0x78}, {0x9A, 0xBC, 0xDE, 0xF0} }; // 检查UID是否在合法列表中 for(int i0; isizeof(validUIDs)/4; i) { if(memcmp(uid, validUIDs[i], 4) 0) { return 1; // 验证通过 } } return 0; // 验证失败 }5.3 性能优化技巧在实际应用中可以考虑以下优化措施天线调谐调整匹配电路中的电容值优化天线形状和尺寸测试不同工作频率下的性能通信优化合理设置SPI时钟频率采用DMA传输减少CPU占用优化协议处理流程功耗管理动态调整发射功率实现轮询间隔可调低功耗模式设计错误处理增加重试机制完善状态检测异常情况恢复通过本项目的实践不仅可以掌握STM32与RC522的硬件接口开发更能深入理解RFID技术的工作原理和安全机制。这种基础技术的掌握为后续开发更复杂的物联网应用奠定了坚实基础。