STM32+PN532实战:手把手教你用UART读取NFC卡UID(附完整代码)

张开发
2026/4/16 11:53:41 15 分钟阅读

分享文章

STM32+PN532实战:手把手教你用UART读取NFC卡UID(附完整代码)
STM32与PN532的UART通信实战从零构建NFC卡识别系统最近在开发一个智能门禁原型时我遇到了一个有趣的问题如何用最简硬件实现NFC卡片的快速识别经过多次尝试发现STM32配合PN532模块的方案既稳定又高效。本文将分享整个开发过程中的关键步骤和踩坑经验特别适合刚接触NFC开发的硬件爱好者。1. 硬件准备与连接1.1 所需材料清单在开始前请确保准备好以下硬件STM32F103C8T6最小系统板俗称蓝 pillPN532NFC模块UART版本USB转TTL模块用于调试杜邦线若干NFC卡片Mifare Classic 1K测试卡提示购买PN532模块时务必确认是UART版本市面上还有I2C和SPI版本引脚定义不同。1.2 硬件连接示意图正确的接线是成功的第一步参考以下连接方式STM32引脚PN532模块引脚功能说明PA9RXDSTM32发送PA10TXDSTM32接收3.3VVCC电源输入GNDGND共地// 在CubeMX中的USART1配置示例 huart1.Instance USART1; huart1.Init.BaudRate 115200; huart1.Init.WordLength UART_WORDLENGTH_8B; huart1.Init.StopBits UART_STOPBITS_1; huart1.Init.Parity UART_PARITY_NONE;2. PN532通信协议解析2.1 指令帧结构剖析PN532的UART通信采用特殊帧格式每个指令包含以下部分前导码0x00 0x00 0xFF数据长度LEN (实际字节数)长度校验LCS (0x100 - LEN)数据域TFI PD0...PDn数据校验DCS (0x100 - SUM)// 典型唤醒指令示例 uint8_t wakeup_cmd[] { 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, 0xFD, 0xD4, 0x14, 0x01, 0x17, 0x00 };2.2 关键指令集开发过程中最常用的几个指令指令功能命令代码典型响应唤醒模块0x14 0x010x15 0x16寻卡0x4A 0x010x4B UID读块数据0x40 0x010x41 数据3. STM32软件实现3.1 初始化配置使用STM32CubeMX生成基础代码后需要添加PN532专用驱动// pn532.h 头文件关键定义 #define PN532_PREAMBLE 0x00 #define PN532_STARTCODE 0x00FF #define PN532_POSTAMBLE 0x00 typedef struct { uint8_t command; uint8_t data[64]; uint8_t length; } PN532_Command;3.2 核心功能实现完整的UID读取流程包含三个关键函数唤醒模块HAL_StatusTypeDef PN532_Wakeup(UART_HandleTypeDef *huart) { uint8_t wakeup_seq[24] {...}; uint8_t response[15]; HAL_UART_Transmit(huart, wakeup_seq, 24, 100); HAL_UART_Receive(huart, response, 15, 100); return (response[12] 0x15) ? HAL_OK : HAL_ERROR; }寻卡操作uint8_t PN532_ReadUID(UART_HandleTypeDef *huart, uint8_t *uid) { uint8_t cmd[11] {0x00, 0x00, 0xFF, 0x04, 0xFC, 0xD4, 0x4A, 0x01, 0x00, 0xE1, 0x00}; uint8_t resp[25]; HAL_UART_Transmit(huart, cmd, 11, 100); HAL_UART_Receive(huart, resp, 25, 200); if(resp[12] 0x4B) { memcpy(uid, resp[19], 4); return 1; } return 0; }UID验证uint8_t stored_uid[4] {0xC2, 0x99, 0x4A, 0x1B}; int verify_uid(uint8_t *read_uid) { return memcmp(read_uid, stored_uid, 4) 0; }4. 实战调试技巧4.1 常见问题排查在开发过程中我遇到了几个典型问题无响应检查接线是否正确特别是TX/RX是否交叉连接数据错误确保波特率设置为115200STM32和PN532配置一致校验失败检查DCS校验和计算是否正确4.2 性能优化建议添加超时机制防止死等实现数据校验重传机制使用DMA方式提高传输效率// 带超时的改进版接收函数 HAL_StatusTypeDef UART_Receive_Timeout(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout) { uint32_t tickstart HAL_GetTick(); while(HAL_UART_Receive(huart, pData, Size, 10) ! HAL_OK) { if((HAL_GetTick() - tickstart) Timeout) { return HAL_TIMEOUT; } } return HAL_OK; }5. 扩展应用场景5.1 门禁系统实现基于此方案可以构建基础门禁功能卡片识别成功后触发继电器记录刷卡日志到EEPROM通过蓝牙/WiFi上传数据5.2 数据读写进阶除了读取UIDPN532还支持读取卡片特定扇区修改块数据实现数值增减操作// 读块数据指令示例 uint8_t read_block_cmd[] { 0x00, 0x00, 0xFF, 0x05, 0xFB, 0xD4, 0x40, 0x01, 0x30, 0x06, 0x00 // 读取块6 };6. 替代方案对比当成本成为主要考量时可以考虑芯片型号接口类型典型价格特点PN532UART/I2C/SPI¥15-20功能全面RC522SPI¥5-8性价比高FM175xxSPI/I2C¥6-10国产替代在实际项目中我发现PN532的稳定性确实更好特别是在多卡同时出现的场景下。但对于简单的门禁应用RC522可能更经济实惠。

更多文章