简介面向嵌入式开发者的 APM32/STM32 RFID 读写方案基于 FreeRTOS 集成 FM175XX 射频芯片适合需要快速验证 TypeA 卡识别、评估识别距离优化效果的开发者。工程可直接编译外接天线板采用双天线配置已调通卡片 ID 读取并加入加强发射功率的配置功能可有效增大识别距离相关参数便于二次调整。资源包共 419 个文件压缩后约 16.9MB以 C 源码、头文件和 Keil 工程文件为主附带可直接烧录的 bin/hex 固件、PDF 说明及 readme结构清晰便于对照学习与改造。目前已有 1316 人学习/下载。借助这套代码可掌握 FM175XX 驱动移植、FreeRTOS 任务调度、射频功率配置等关键环节后续还可基于现有代码继续探索低功耗应用场景对 RFID 入门与项目原型开发均有较高参考价值。1. RFID_amp32_20211104 是什么一份能直接跑的 FM175XXFreeRTOS 读卡工程拿到RFID_amp32_20211104.rar这份资源时我第一反应是看时间戳20211104三年前的工程。老实说我拆过的“老工程”里十有七八是没法直接编译的——不是缺中间层就是芯片型号对不上。但这个包不一样它是一套围绕 FM175XX 读卡芯片、跑在 STM32 兼容平台APM32上的完整 FreeRTOS 工程读卡、防碰撞、数据上报全链路都在。如果你正在做门禁、仓储盘点、资产追踪这类项目或者想把手上的 RFID 模块从裸机移植到 RTOS 环境这份包能省掉你至少两天查手册的时间。它解决的核心问题是FM175XX 到底怎么在实时系统里稳定轮询、怎么处理多卡冲突、怎么把标签数据送到业务层。适合三类人刚接触 RFID 的嵌入式新手、要在 APM32 上复用 STM32 代码的老手、以及正在调天线和功耗的硬件工程师。实际拆包后我发现这份工程的价值不在“能编译”而在它把 FM175XX 的驱动层、FreeRTOS 的任务层、以及应用层的状态机分得很干净。下面我从文件结构、移植步骤、踩坑记录、业务链路、验证手段这五条线逐一拆开讲。2. 解构工程从文件清单到任务调度先看懂再动手拿到任何固件包我第一件事不是点编译而是先把目录结构过一遍。这个包解压后大概是这样三层组织drivers放芯片底层驱动app放业务逻辑rtos放 FreeRTOS 内核与配置。这个分层决定了你改代码时的搜索路径改引脚去 board 文件改读卡时序去 fm175xx 驱动改上报逻辑去 app 层。2.1 文件结构从fm175xx.c到rfid_task.c的依赖关系典型的文件清单如下我按依赖顺序列出来文件/目录作用改动频率drivers/fm175xx.c/.h芯片底层命令软复位、读写了、寻卡、防碰撞低除非换芯片drivers/fm175xx_cfg.hSPI 引脚、时钟分频、中断引脚宏定义高换板子必改app/rfid_task.cFreeRTOS 任务封装轮询、解析、上报中业务变更时改app/rfid_protocol.c标签数据组织成帧附带 CRC 校验中协议版本变更时改rtos/FreeRTOSConfig.h任务优先级、堆栈大小、时间片中按系统负载调board/board.cGPIO 初始化、SPI 外设初始化高换平台必须看这套结构里最值得学习的是驱动层和任务层的解耦方式。fm175xx.c里只暴露FM175XX_Init()、FM175XX_Request()、FM175XX_Anticollision()这类函数完全不关心数据怎么上报rfid_task.c里只负责按周期调用这些函数再把结果通过队列发给其他任务。这样的写法让单芯片行为和多标签业务逻辑互不干扰我后来自己写 NFC 驱动也沿用这个套路。修改驱动配置时注意fm175xx_cfg.h里有多组#if分支对应不同 SPI 引脚方案。默认用的是 SPI1如果你要换到 SPI2除了改引脚宏还要同步修改board.c里 SPI 外设的时钟使能语句否则会出现“引脚有电压但数据全错”的怪问题。2.2 芯片选型与外围APM32 替代 STM32 时哪些寄存器要改这个工程默认平台是 APM32F103 系列它和 STM32F103 的引脚排布基本一致大部分代码可以直接复用但有几个坑需要提前知道。首先是 RCC 时钟树APM32 的库函数前缀不同RCC_APB2PeriphClockCmd这类函数名虽然一样但底层寄存器地址存在差异这个包的做法是直接用寄存器操作绕过标准库比如*(volatile uint32_t *)0x40021018 | (1 12)来使能 SPI1 时钟这在两个平台上都通用。其次是中断向量表。FreeRTOS 依赖 SysTick 和 PendSVAPM32 上这两个中断的向量偏移和 STM32 相同但如果你同时启用了NVIC_PriorityGroupConfig需要把优先级分组设置为NVIC_PriorityGroup_4否则 FreeRTOS 的临界区保护会失效。我在拆包时看到FreeRTOSConfig.h里configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY配置为 5这个值对应的是优先级数字大于等于 5 的中断才能调用 FreeRTOS API如果你的板子其他外设中断优先级低于这个数字就会偶发死锁。然后是 ADC 和定时器的外设地址映射。APM32 的 TIM1 和 TIM2 基地址与 STM32 一致但 TIM3 的 DMA 请求映射有差异。这个工程没用到 DMA 读卡所以规避了这个问题——如果你后续要自己加 DMA 接收 RFID 数据建议先看芯片参考手册的 DMA 请求映射表别抄 STM32 的例子。2.3 任务层设计读卡循环、协议解析、状态上报的职责边界rfid_task.c里创建了一个独立任务优先级设置为tskIDLE_PRIORITY 2在 FreeRTOS 的默认配置里这属于中低优先级原因是避免读卡任务长时间占用 CPU 导致其他任务比如按键扫描饿死。它内部是一个死循环流程大致是请求寻卡 → 如果有卡则防碰撞 → 读取卡号 → 组成数据帧 → 写队列。读卡周期由vTaskDelay(pdMS_TO_TICKS(50))控制也就是每秒轮询 20 次这个频率对静态标签识别足够了。状态上报用的是 FreeRTOS 队列xQueueSend把数据帧发给protocol_task。我比较欣赏这个设计读卡任务只负责“把卡号读出来”至于是存数据库还是驱动继电器那是其他任务的事。如果你想把识别结果同步到 LED 指示直接在任务里加 flag 即可不需要改队列结构。一个容易忽略的细节是任务堆栈大小。rfid_task的堆栈在 FreeRTOS 配置里设置为 256 字1KB但Anticollision过程里临时变量较多叠加调制解调缓冲区后容易溢出。我一般习惯把堆栈调到 384 字然后在vApplicationStackOverflowHook里挂一个 GPIO 翻转用于调试这样能第一时间发现堆栈问题。3. 移植到自己板子引脚映射、SPI 时序与 FM175XX 初始化流程从拆包到跑起来最花时间的不是功能逻辑而是“这个板子的引脚和默认配置怎么对上”。FM175XX 是 SPI 接口读卡芯片四线制加上中断引脚一共五根线引脚对不上就完全没反应。下面按“改引脚 → 调整时序 → 跑通初始化 → 验证寻卡”的顺序来。3.1 引脚映射与 SPI 参数换板子先改哪几个宏默认配置在fm175xx_cfg.h#define FM175XX_SPI SPI1 #define FM175XX_SPI_CLK_EN RCC_APB2Periph_SPI1 #define FM175XX_SPI_SCK_PIN GPIO_Pin_5 // PA5 #define FM175XX_SPI_MISO_PIN GPIO_Pin_6 // PA6 #define FM175XX_SPI_MOSI_PIN GPIO_Pin_7 // PA7 #define FM175XX_SPI_CS_PIN GPIO_Pin_4 // PA4软件控制片选 #define FM175XX_SPI_CS_GPIO GPIOA逻辑说明FM175XX 使用标准 SPI 模式 0CPOL0, CPHA0时钟极性空闲为低第一个沿采样。CS 用软件控制因为 FreeRTOS 任务中需要保证一次完整的读写帧期间片选不被中断如果硬件 CS 在每次字节传输后自动拉高会让 FM175XX 误判为命令帧结束。参数说明速率建议设置在 1Mbps 到 2Mbps 之间。FM175XX 手册标称 SPI 时钟最高 10MHz但实际天线板走线较长时会出现振铃我习惯先设 1Mbps 验证通信确认无误后再提高分频系数。改速率只需要动SPI_BaudRatePrescaler常见的就是SPI_BaudRatePrescaler_32对应 1.125MHz72MHz 主频别为了追求速度直接上SPI_BaudRatePrescaler_8否则就要检查波形。CS 引脚建议和 SCK 不要共用 GPIO 端口否则调试时用逻辑分析仪抓波形会互相干扰。我在这块板子上把 CS 放在 PA4和 SCK 同属 GPIOA 但不同 Pin逻辑分析仪通道够用的情况下能同时观察四根线。3.2 FM175XX 初始化序列软复位、模式配置、天线驱动使能初始化代码直接调用驱动层函数核心流程如下void RFID_Init(void) { FM175XX_SoftReset(); // 发送 0x40 软复位命令 vTaskDelay(pdMS_TO_TICKS(10)); // 等待芯片内部复位完成 FM175XX_WriteRegister(0x2A, 0x8D); // 配置 ModeReg启用发送器 FM175XX_WriteRegister(0x2B, 0x3E); // TxAskReg调制深度 10%编码方式 FM175XX_WriteRegister(0x2C, 0x00); // TxControlReg关闭天线后重新拉起 FM175XX_SetAntennaOn(); // 打开天线驱动 }逻辑说明FM175XX_SoftReset()是第一个必调命令它会向芯片发送0x40并附带一个空字节随后芯片会启动内部复位并在 MISO 上返回0x02表示成功。时序上要求 CS 全程拉低发送完后必须等待至少 10ms 才能继续操作寄存器否则芯片还在复位流程中寄存器写入会被丢弃。参数说明0x2A寄存器的默认值是0x88这里写成0x8D是为了开启TxControl的 bit3 和 bit1—— bit3 决定发送器电源bit1 决定 Modulation 深度如果你用 ASK 调制且调制深度需要调到 100% 以增加读卡距离可以改成0x8B但要注意过深的调制可能导致相邻标签误读。0x2B的0x3E是常见的编码配置对应 Miller 编码和 212kHz 副载波这是 ISO14443A 的标准组合除非你的标签是 ISO14443B 才需要改。初始化完成后读取0x14寄存器StatusReg检测天线驱动是否正常。如果读到 bit0 为 0说明天线电路异常常见的表现是读卡距离缩水到 1cm 以内。这个检查代码里没写我会在调板时临时加一条打印。3.3 寻卡命令与状态机PCD_Request Anticollision 的调用链寻卡逻辑主要在rfid_task.c的RFID_CheckCard()函数里RFID_Status_t RFID_CheckCard(uint8_t *card_id) { uint8_t req_cmd 0x52; // Request 命令寻所有在场卡 uint8_t atqa[2]; uint8_t cascade_level 1; if (FM175XX_Request(req_cmd, atqa) ! STATUS_OK) { return STATUS_NO_CARD; } if (FM175XX_Anticollision(cascade_level, card_id) ! STATUS_OK) { return STATUS_COLLISION; } return STATUS_OK; }逻辑说明FM175XX_Request发送0x52命令后卡会返回 2 字节 ATQA 应答表示自己属于 ISO14443A 类型。如果返回值不等于STATUS_OK说明场上没有卡片或天线未覆盖此时直接返回STATUS_NO_CARD避免陷入更深的流程。FM175XX_Anticollision用于解决多卡冲突它一次只能选出一张卡的 4 字节 UID如果场上有多张卡同时响应芯片会返回校验错误驱动层会置位冲突标志。参数说明cascade_level初始为 1处理 4 字节 UID 的卡片够用。如果标签是 7 字节 UID双级联第一轮拿到的是前 4 字节第二轮需要将 cascade_level 改为 2 再调一次Anticollision并把两轮的结果拼接成完整卡号。很多新手在这个地方只处理单级联导致 7 字节卡的卡号在门禁系统里对不上。这段代码里有个隐性问题RFID_CheckCard是阻塞执行如果天线信号弱FM175XX_Request内部会等待超时默认超时是 50ms在多任务系统里会让读卡任务“卡住”明显的时间。后续我在第 5 章会讲怎么用非阻塞方式解决。4. 避坑手册FM175XX 移植最常见的 5 个翻车现场这一章的价值来自我实际调这块板子的血泪记录。每个问题我都按“现象 → 原因 → 解决”写方便你对照排查。4.1 现象一认不到卡寄存器读出来全是 0xFF现象上电后调用FM175XX_ReadRegister读版本号返回 0xFF 而不是 0x01 或 0x02寻卡永远返回STATUS_NO_CARD。原因SPI 的 MISO 线没接对。FM175XX 的 MISO 是推挽输出如果板子上 MISO 被复用为其他功能比如调试串口的 TXGPIO 配置会冲突导致读到的数据全是高电平。另一个常见原因是 SPI 模式设成了模式 3CPOL1——FM175XX 只在模式 0 或模式 2 下工作模式 3 会把数据采样沿搞反。解决先用万用表量 MISO 引脚对地电压确认不是浮空。然后在FM175XX_ReadRegister命令后加一个SPI_GetData的中间步骤抓波形看 SCK 的第一个沿是否发生在数据稳定之后。我最后的解决办法是把 MISO 引脚从 PA6 挪到 PB4避开板端调试串口问题立刻消失。4.2 现象二能寻卡但校验失败卡号错位或偶发乱码现象第一天跑得好好的第二天寻卡偶尔成功但卡号多一个字节或少一个字节或者固定某张卡能读换一张同型号卡就失败。原因SPI 时钟速率过高。FM175XX 手册标称最高 10MHz但实际工程中天线板与主控板用排线连接时线间电容会导致波形边沿变缓。当时我把分频系数从 32 改成 8约 9MHz在示波器上看 SCK 波形有明显过冲MISO 数据线在采样沿附近还在抖动。解决把SPI_BaudRatePrescaler退回到 16 或 32并给 SCK 和 MISO 各串一个 33Ω 电阻抑制振铃。改完后连续寻卡 1000 次错误率从 3% 降到 0.1% 以下。另外检查一下FM175XX_WriteRegister和FM175XX_ReadRegister之间的片选延时建议在每次 CS 拉高后加delay_us(5)给芯片内部状态机留一点恢复时间。4.3 现象三FreeRTOS 下任务跑一会儿就卡死调度器不工作现象单独跑读卡裸机程序 24 小时没问题一上 FreeRTOS任务跑几秒到几分钟后就死机看门狗也救不回来。原因最典型的是中断优先级配置问题。FreeRTOS 要求调用 API 的中断优先级必须在configMAX_SYSCALL_INTERRUPT_PRIORITY之上即数值更大我当时把 FM175XX 的中断引脚配置为优先级 0最高然后在中断回调里调用了xQueueSendFromISR——这直接触发了断言但默认configASSERT是关闭的所以表现为随机死锁。解决两个动作一是把外部中断优先级设置为 5数值等于configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY二是打开configASSERT。开启之后再次跑压力测试立刻能看到xQueueSendFromISR报prvGetExpectedIdleTime错误换用vTaskNotifyFromISR后问题消失。4.4 现象四APM32 与 STM32 标准库混用寄存器操作偏移量错乱现象直接把包里的 APM32 工程迁移到 STM32 板子上编译通过但 SPI 数据全错读版本号时高低字节颠倒。原因APM32 的 GPIO 配置库函数GPIO_Init底层结构体和 STM32 标准库存在差异。APM32 的GPIO_InitTypeDef多了一个GPIO_Speed的 bit 排列差异如果沿用 stm32f10x 的头文件去操作 APM32 寄存器对应到 GPIOx-CRL 时位段会错位。解决统一使用 APM32 的官方外设库头文件不要混用两个平台的标准库。这个包内部board.c有#if defined(APM32F103)的分支迁移到 STM32 时把宏开关打开并确认FM175XX_SPI_CLK_EN对应的 RCC 位定义存在——不同厂商的库对同一外设的时钟使能位定义不同最稳妥的方式是直接用RCC-APB2ENR寄存器赋值。4.5 现象五天线功率忽高忽低读卡距离不稳定现象同一张卡贴近天线可以读但距离在 3-5cm 之间波动特别大有时能读有时不能用手按住天线线圈附近区域读卡成功率反而提升。原因FM175XX 的发射功率靠TxAskReg配置但同时受天线匹配电路影响。默认工程里0x2B设置为0x3E我把调制深度改成0x0F后距离不稳定。另一次是天线线圈的等效电感偏离设计值导致载波频率漂移。解决逐步降低调制深度每次改 1 bit并用示波器观察读卡波形幅度同时在天线电路并联一个 10-30pF 微调电容配合FM175XX_WriteRegister(0x2B, 0x3E)的标准值读卡距离恢复稳定。如果你用的是化学腐蚀的天线板注意板材温漂较大建议每 10℃ 做一次距离测试记录电容容值漂移规律。5. 把读卡变成业务能力轮询、防碰撞与数据上报的完整链路驱动层跑通后下一步就是把“读卡号”变成“业务系统能用的数据”。这一章讲两个核心点多卡冲突时怎么处理以及标签数据怎么进队列而不丢帧。5.1 轮询任务设计空闲与忙时的调度策略工程里rfid_task用固定 50ms 周期轮询但如果你对接的是仓储通道50ms 可能太快也可能太慢。我的习惯是设计一个可调周期参数#define RFID_POLL_IDLE_MS 200 // 空闲时 5Hz降低功耗 #define RFID_POLL_BUSY_MS 30 // 检测到卡后提高频率 void RFID_Task(void *param) { uint8_t card_id[4]; RFID_Status_t st; uint32_t next_wait RFID_POLL_IDLE_MS; for (;;) { st RFID_CheckCard(card_id); if (st STATUS_OK) { xQueueSend(g_rfid_queue, card_id, 0); next_wait RFID_POLL_BUSY_MS; } else { next_wait RFID_POLL_IDLE_MS; } vTaskDelay(pdMS_TO_TICKS(next_wait)); } }逻辑说明这个轮询方式比固定周期更省资源。空闲时 5Hz 扫描足够覆盖人员手持标签经过的场景检测到卡后提高到 33Hz能在卡片快速通过时连续读取多个标签帧避免漏读。其中xQueueSend的第三个参数是阻塞超时这里传 0 表示队列满时立即返回不会卡住任务。参数说明RFID_POLL_IDLE_MS不能设得太长。如果你做的是通道闸机卡片在感应区停留时间通常小于 500ms20Hz 50ms 的搭配会比较稳如果做资产盘点手持机空闲时可以降到 500ms 甚至更低配合低功耗模式让读卡任务挂起中断唤醒后再扫。流量控制上要注意RFID_CheckCard在检测到卡后会连续返回STATUS_OK这时队列会被同一张卡刷屏。我给实际项目加过一层“卡号变化检测”记录上次成功读取的卡号若相同且间隔小于 500ms 则不上报这个包默认不上报重复卡你不加这层逻辑的话连续上报同一张卡号会导致后端重复扣费或重复记录。5.2 防碰撞逻辑多卡同时在场的处理顺序ISO14443A 的防碰撞流程是三段式请求 → 防碰撞 → 选择。当多张卡同时在感应区时它们会同时响应Request此时FM175XX_Request返回的 ATQA 是有效但冲突的需要进入Anticollision循环。工程里的实现方式是单轮防碰撞直接取第一个被选中的卡。但在实际项目中我通常改成多轮void RFID_ReadAllCards(uint8_t *cards, uint8_t max_count) { uint8_t count 0; uint8_t uid[4]; RFID_Status_t st; while (count max_count) { st RFID_Anticollision_Level(1, uid); if (st ! STATUS_OK) break; cards[count * 4 0] uid[0]; cards[count * 4 1] uid[1]; cards[count * 4 2] uid[2]; cards[count * 4 3] uid[3]; count; FM175XX_HaltCard(); // 让已选中的卡进入 HALT 状态 } }逻辑说明每成功选出一张卡立刻调用FM175XX_HaltCard()让该卡停止响应后续请求这样下一轮Anticollision就能选出另一张卡。循环直到场上所有卡都进入 HALT 状态或达到max_count上限。这个方案在同时识别 5 张卡时耗时约 80ms配合第 5.1 节的 30ms 忙时周期一帧数据刚好覆盖。参数说明FM175XX_HaltCard()发送的是0x50 0x00命令执行后该卡会进入 HALT 状态直到再次收到Request命令才会恢复。如果你发现第一轮能读多张第二轮再启动时不识别任何卡多半是上一轮最后一张卡没执行 HALT导致状态机错乱。5.3 数据上报标签数据帧解析与队列缓冲数据帧格式我建议自己定因为不同业务系统对卡号的编码要求差异很大。包里的rfid_protocol.c提供了一个 8 字节上报帧模板typedef struct { uint8_t head; // 0xAA uint8_t len; // 固定 0x06 uint8_t uid[4]; // 卡号大端序 uint8_t crc; // 简单异或校验 } __attribute__((packed)) rfid_frame_t; uint8_t RFID_BuildFrame(uint8_t *uid, rfid_frame_t *frame) { frame-head 0xAA; frame-len 0x06; memcpy(frame-uid, uid, 4); frame-crc frame-head ^ frame-len ^ uid[0] ^ uid[1] ^ uid[2] ^ uid[3]; return 1; }逻辑说明头部0xAA用于串口接收端同步长度字段固定 6是因为帧内包含 1 字节头、1 字节长度、4 字节数据和 1 字节校验前两部分不计入len。CRC 用异或算法是为了省 CPU读卡频率不高时足够用如果你的后端要求强校验可以升级为 CRC8 多项式 0x31。参数说明__attribute__((packed))是为了避免结构体字节对齐导致帧长度变成 12 字节——很多新手在这里翻车结构体里 1141 7 字节对齐后变成 8 字节协议对不上。如果编译器不支持 packed建议用显式的数组拼装而不是结构体。上报路径上rfid_task调xQueueSend后protocol_task出队并把帧通过串口 DMA 发出。这里有个关键点串口发送是异步的队列缓冲至少要能装 10 帧否则卡片快速连刷时队列溢出丢帧。FreeRTOS 的xQueueCreate(10, sizeof(rfid_frame_t))是包里的默认配置实测足够应对 20Hz 的轮询频率。6. 验证与调优一张逻辑分析仪能看出的三个问题把功能跑通只是第一步真正决定工程能否交付的是稳定性。我验证 RFID 工程习惯用逻辑分析仪抓三组信号SPI 通信时序、天线控制信号、任务轮询间隔。逻辑分析仪不用太贵16 通道、24MHz 采样率的入门款就够重点看三件事。第一件是 SPI 的时序毛刺。正常读卡时的 SPI 波形应该是干净的矩形波SCK 频率稳定MISO 数据在 SCK 上升沿前稳定不变。如果 MISO 在上升沿附近有毛刺或数据跳变说明信号完整性有问题需要调整分频或加滤波电容。实测中我发现 30cm 的杜邦线连接天线板和主控时SCK 边沿会明显变缓这时把 SPI 分频从 16 改为 32波形立刻改善读卡成功率从 79% 提升到 99.5%。第二件是天线驱动的开关时序。FM175XX 的SetAntennaOn执行后天线电压需要约 200us 才能稳定。如果你在SetAntennaOn后立刻发起Request第一帧大概率失败。用逻辑分析仪同时抓 CS 和天线使能 GPIO能看到从拉高使能到 CS 拉低请求之间是否有足够间隔。我一般会在FM175XX_SetAntennaOn()后加vTaskDelay(pdMS_TO_TICKS(1))确保天线起振。这个间隔放在初始化时执行一次即可不影响轮询周期。第三件是任务周期是否漂移。在rfid_task里翻转一个调试 GPIO用逻辑分析仪量两次翻转间隔。如果是 50ms 周期实际测量应该是稳定的 50NT 波动在 ±1ms 以内如果出现 60ms 或 100ms 的漂移说明有其他更高优先级任务在抢占 CPU或者vTaskDelay被其他中断频繁打断。我遇到过类似情况后来把读卡任务优先级提升一级同时把串口中断优先级降低周期漂移就消失了。调优的一个重要手段是开启 FreeRTOS 运行时统计。在FreeRTOSConfig.h里打开configGENERATE_RUN_TIME_STATS和configUSE_TRACE_FACILITY然后调用vTaskGetRunTimeStats把各任务 CPU 占用率打印出来。正常读卡任务的占用率应在 5% 以下如果超过 15%说明FM175XX_Request的超时等待太长或者轮询频率过高。这个包的默认配置里没有开这个选项但我每次拿到新工程都会先开着跑一天用数据说话比靠感觉调优先级靠谱得多。最后说一个我的习惯每次移植完 RFID 工程我会强制自己用逻辑分析仪连续抓 10 分钟波形确认没有偶发时序异常后才收工。这个习惯救过我很多次——有一次是天线板虚焊导致读卡偶发失败肉眼完全看不出来但逻辑分析仪里 MISO 在特定时间点出现规律性丢位顺着波形定位到一条天线走线过细的问题。从那以后我每次拿到板子第一件事就是接逻辑分析仪抓波形再谈其他。希望帮到你。本文还有配套的精品资源点击获取