ESP32(ESP-IDF)下如何将PN532读取的uint8_t类型UID转为字符串
问题描述
在PlatformIO基于ESP-IDF框架开发ESP32程序时,通过SPI连接PN532 RFID阅读器已成功读取UID并输出日志,但无法将uint8_t数组存储的UID转换为可用字符串。需要将UID转为字符串用于OLED显示及RESTful API数据库查询,该功能在Arduino IDE中正常,切换到ESP-IDF后受阻。
相关代码片段:
uint8_t uid[] = {0, 0, 0, 0, 0, 0, 0}; // Buffer to store the returned UID uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type) // Wait for an ISO14443A type cards (Mifare, etc.). When one is found // 'uid' will be populated with the UID, and uidLength will indicate // if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight) success = pn532_readPassiveTargetID(&nfc, PN532_MIFARE_ISO14443A, uid, &uidLength, 0); if (success) { // Display some basic information about the card ESP_LOGI(TAG, "Found an ISO14443A card"); ESP_LOGI(TAG, "UID Length: %d bytes", uidLength); ESP_LOGI(TAG, "UID Value:"); esp_log_buffer_hexdump_internal(TAG, uid, uidLength, ESP_LOG_INFO); }
解决方案
核心原理
UID是uint8_t类型的字节数组,每个字节对应两位十六进制字符(如0xAB转为"AB"),转换时需要:
- 分配足够大的字符缓冲区:长度为
uidLength * 2 + 1(额外1位用于空终止符\0,C语言字符串必须以此结尾,否则会读取内存垃圾数据) - 逐字节将十六进制值格式化为字符
具体实现代码
在success的判断块中添加转换逻辑:
if (success) { // 原有日志输出代码 ESP_LOGI(TAG, "Found an ISO14443A card"); ESP_LOGI(TAG, "UID Length: %d bytes", uidLength); ESP_LOGI(TAG, "UID Value:"); esp_log_buffer_hexdump_internal(TAG, uid, uidLength, ESP_LOG_INFO); // UID转字符串逻辑 // 固定缓冲区大小(支持最大7字节UID:7*2+1=15) char uid_str[15] = {0}; for (int i = 0; i < uidLength; i++) { // 逐字节格式化,%02X表示两位大写十六进制,小写用%02x snprintf(&uid_str[i*2], 3, "%02X", uid[i]); } // 验证转换结果 ESP_LOGI(TAG, "转换后的UID字符串:%s", uid_str); // 后续可直接使用uid_str:OLED显示、API传递等 }
关键说明
- 空终止符:代码中通过
char uid_str[15] = {0};初始化时自动填充了空终止符,也可在循环结束后手动添加uid_str[uidLength*2] = '\0';确保字符串合法。 - 缓冲区大小:因为ISO14443A卡UID最长7字节,所以固定15位缓冲区足够,避免变长数组的兼容性问题。
- ESP-IDF与Arduino差异:Arduino的
String类自动处理内存和终止符,而ESP-IDF使用标准C字符串,需手动管理缓冲区和终止符。
内容的提问来源于stack exchange,提问作者Andrew Taylor
相关产品推荐
相关产品推荐

