拓冰建站拓冰建站
首页 / 资讯中心 / 正文

STM32F103芯片没反应?从最小系统到FreeRTOS排查全指南

STM32F103 这颗芯片有多火不用我多说。也正因为它火市场上翻新片、打磨片、替代片、杂牌片多到超出你的想象。遇到“芯片没反应”的第一反应很多人会怀疑代码、怀疑 FreeRTOS 配置、怀疑焊接很少有人第一时间想到你手里这颗可能就不是一颗正经的原装芯片。我最早踩这个坑是在一个量产小项目上几十片板子焊好一半以上 ST-Link 连不上Keil 里反复提示 No target connected换上从代理商拿的样片立刻正常。从那次之后我才明白排查“没反应”的正确顺序不是先改代码而是先确认芯片本身还活着。这篇东西就围绕“STM32F103 FreeRTOS 芯片没反应”这件事展开把最小系统、芯片真伪判断、FreeRTOS 移植里最容易翻车的几个点以及碰到外设异常时该怎么定位一次都说清楚。内容面向正在用标准库 v3.5、FreeMODBUS v1.6、Keil MDK 这类老牌工具链做项目的朋友也适合刚入手 STM32F103C8T6 最小系统板的小白。1. 芯片没反应先拔掉 FreeRTOS 再谈“假芯片”1.1 最小系统首先要过的“三板斧”供电、复位、启动方式把“没反应”这个问题拆开看绝大多数情况根本不是芯片假不假而是最小系统本身没搭好。STM32F103 不是插上电源就能跑的单片机它的最小系统有几个硬性要求少一个都可能导致调试器完全识别不到芯片。供电方面3.3V 要给 VDD 引脚最好每个 VDD/VSS 对就近放一个 100nF 去耦电容再加一个 10uF 左右的钽电容或电解电容做整体储能。VDDA/VSSA 这两个模拟供电引脚也必须接好很多人漏了 VDDA结果芯片能上电但 ADC 和内部基准都不正常看起来就像“半死不活”。复位引脚 NRST 一般建议接 100nF 电容到地官方参考设计里通常还有一个上拉电阻BOOT0 要拉到 GNDBOOT1 也建议通过电阻拉低确保上电后从主闪存启动而不是误入系统存储器 ISP 模式。调试接口这里容易出问题。SWD 只需要 PA13、PA14 两根线加上 GND 和 3.3V共四根线就够了。不要图省事用又长又细的杜邦线从 20Pin JTAG 转接头上飞线线一长就容易被干扰。我见过一个朋友SWD 死活连不上最后发现是 SWDIO 和 SWCLK 接反了这种低级问题反而最容易被忽略。时钟部分F103 虽然内部有 HSI但很多工程初始化代码里一上来就把时钟切换到外部 HSE如果板上没有焊 8MHz 晶振或者晶振两个 20pF 左右负载电容没装程序会在时钟切换那里卡死。调试器能不能连上不完全取决于晶振但程序能不能跑起来非常依赖它。所以排查时先确认供电、复位、BOOT、时钟这四个东西都没问题再往下查。1.2 先确认调试器能不能“见到”芯片再谈烧录用 ST-Link Utility 或者 STM32CubeProgrammer 连接芯片时如果提示无法连接可以先切到“Connect under reset”模式。这个模式的意思是调试器先把目标芯片的复位引脚拉低在复位状态下建立连接然后再释放复位。这样做可以绕过一个非常经典的问题上一次烧录进去的程序把 SWD 引脚复用成普通 GPIO 了或者程序跑飞后恰恰让 PA13/PA14 变成了非调试功能导致调试接口被“关掉”。如果你的程序里调用了类似 GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE) 这样的代码把 SWJ 调试口重映射了那下次连接就会出现“连不上”的现象。解决办法就是按住复位键再点连接或者用 CubeProgrammer 里的 under reset 连接。如果 under reset 也连不上再把 BOOT0 拉高、BOOT1 拉低上电进入系统存储器模式这时候 CPU 跑的是芯片出厂自带的 bootloaderSWD 接口大概率能恢复正常或者用串口 ISP 擦除 Flash。这里有个判断技巧如果 under reset 或者 ISP 模式能连上说明芯片本身大概率还活着问题在固件或者配置如果所有模式都连不上甚至串口 ISP 都收不到任何应答那才轮到“芯片是不是坏了/是不是假货”这个怀疑。2. 买到假芯片的几种情况以及快速鉴别流程2.1 翻新片、打磨片与国产兼容片别混为一谈先说清楚不是所有“非原装”都是假芯片。STM32F103 的替代芯片非常多比如 GD32、APM32、CKS32 这类国产兼容芯片它们在引脚和指令集上高度兼容很多时候可以直接替换原装芯片来跑。这类芯片不是不能用但必须清楚它跟原装 F103 不是 100% 等同的东西某些外设行为、Flash 擦写时间、内部上拉阻值、ADC 噪声特性可能都不一样。真正让人头疼的是翻新片和打磨片。所谓翻新片是从废旧电路板上拆下来清洗、重新镀锡、重新打标再当新片卖打磨片则是把芯片表面的字磨掉一层重新印上 STM32F103C8T6 这种热门型号。这类芯片在第一次上电也许能工作但老化、静电损伤、内部 Flash 寿命耗尽、引脚虚焊等暗病非常突出很多“芯片没反应”的现场最后都栽在这种片子上。这里整理一个简单的对比方便你拿到芯片后快速判断风险项目原装 ST 芯片国产兼容片翻新/打磨/Remark 片丝印字体清晰工艺一致批次可查有自己的 Logo 与型号比如 GD32、APM32常有打磨痕迹字体深浅不一或位置偏移价格高中低很便宜批量报价尤其诱人SWD IDCODE能读到与型号对应多数能读到部分会模拟原厂值可能读不到或读到怪值可靠性稳定适合量产基本稳定但外设细节需验证高概率有暗病容易无故死机排查建议当基准参考不要硬套原厂库用官方 SDK直接换片不值得花时间调2.2 用 SWD 读 IDCODE、容量位、唯一 ID 做交叉验证判断一颗芯片是否正常先别拆芯片用软件读几个关键寄存器比肉眼可靠得多。打开 STM32CubeProgrammer 连接成功后在 Log 里能看到 Device ID 和 Revision ID。对 F103 来说不同型号对应不同的 Device ID具体值要翻《STM32F103中文参考手册》里的调试支持章节。如果读出来的 ID 和丝印型号完全对不上那这颗芯片的“身份”就很可疑。还有一个很实用的地址是 0x1FFFF7E0这是 Flash 容量寄存器原装芯片会返回实际出厂容量。比如 F103C8T6 是 64KB Flash如果读出来是 128KB 或者 0多半有问题。另外F103 每颗芯片都有一个 96 位唯一 ID地址在 0x1FFFF7E8原装芯片都能读到。翻新片如果是从板上拆的ID 仍然能读到所以 ID 不能直接证明“新片”但至少能确认芯片不是完全损坏。需要注意的是很多国产兼容片为了兼容原厂工具链在 IDCODE 和容量位上做了模拟所以“读出来正常”不等于“一定是原装”。这套方法适合快速筛掉明显异常或者已经读死的芯片真正要上量还是得从可靠渠道采购并且做完整的老化测试。我现在的习惯是新批次芯片到货后先随机抽几颗读 IDCODE、容量、唯一 ID再烧一个裸机点灯程序跑 24 小时没问题才允许贴片量产。2.3 只有一块板子时用裸机 LED 点灯排除芯片故障调试器都不好使的时候最简单的裸机程序反而是救命的。如果你能做一块最小系统板或者手头有空板那就先不跑 FreeRTOS不跑外设直接写一个最简单的 GPIO 翻转程序让 PA1 或者 PC13 上的 LED 以 1Hz 频率闪烁。用标准库 v3.5 写点灯程序也就十几行关键是先把 RCC 时钟打开再把 GPIO 初始化成推挽输出。如果 LED 能闪说明这颗芯片的内核、Flash、时钟、GPIO 通路基本是好的问题大概率在 FreeRTOS 移植或者更上层代码如果 LED 完全不闪哪怕换一颗确认是好芯片后能闪那原先那颗就得丢掉。有人可能会说“我没有外置晶振”没关系先把代码里的时钟源改成内部 HSI或者干脆不要切时钟用默认的 HSI 跑 GPIO 翻转。这样做的好处是把变量压缩到最少只要电源没有短路、芯片没有被锁死点灯程序几乎一定能跑。如果连这个都不跑再贵的调试器也救不了它。3. FreeRTOS 项目里最常见的“没反应”现场3.1 中断向量表、SysTick 和 PendSV这三点先对齐很多人在把 FreeRTOS 移植到 STM32F103 时明明是按照教程一步一步做的下载也提示成功但芯片就是没有任何反应。这种事我见得太多了十有八九是中断向量表的问题。FreeRTOS 在 Cortex-M3 上运行时需要接管三个异常SVC、PendSV、SysTick。在 FreeRTOS 的 port.c 里这三个异常对应 vPortSVCHandler、xPortPendSVHandler、xPortSysTickHandler。而标准库 v3.5 的启动文件 startup_stm32f10x_md.s 里默认向量表写的是 SVC_Handler、PendSV_Handler、SysTick_Handler。如果你没有把启动文件里的这三个向量改成 FreeRTOS 的名字那么 FreeRTOS 调度器第一次切换任务时PendSV 会跳进启动文件默认的那个空函数任务永远切不过去现象就是程序卡死在初始化之后串口没输出LED 不闪芯片像是死了一样。解决办法很直接打开启动文件把向量表里这三项对应改成 vPortSVCHandler、xPortPendSVHandler、xPortSysTickHandler。有的工程里还会在 stm32f10x_it.c 里重复定义了这三个弱函数记得也要删掉或者屏蔽否则链接时可能冲突。SysTick 也得注意。FreeRTOS 使用 SysTick 作为系统节拍你在 FreeRTOSConfig.h 里通常定义 configTICK_RATE_HZ 为 1000表示每秒 1000 个 tick。同时要保证 configCPU_CLOCK_HZ 和 SystemCoreClock 一致否则任务延时、超时判断会不准。还有一点FreeRTOS 对中断优先级有要求Cortex-M3 上 NVIC 分组建议使用库函数 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4)把优先级设置为 0 到 15 的抢占优先级别让某个外设中断优先级高到把内核临界区搞乱。3.2 任务建了但没跑堆栈溢出和返回值的坑FreeRTOS 里创建任务用的是 xTaskCreate但它不是一定会成功的。如果堆内存不够xTaskCreate 会返回 errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY。很多老工程不检查返回值任务没创建成功程序照样往下跑看起来就像芯片没反应。建议所有任务创建后都检查返回值至少也要在创建失败的地方点亮一个错误灯。还有一个常被忽略的点xTaskCreate 的栈大小参数单位是“字”而不是“字节”。STM32F103 是 32 位 MCU一个栈字等于 4 字节。如果你写 128实际分配的是 512 字节如果你以为 128 就是 128 字节那栈几乎是必溢出的。任务里如果有大数组比如 uint8_t buffer[256]那 128 字的栈根本不够。更稳的做法是在 FreeRTOSConfig.h 里打开堆栈溢出检测#define configCHECK_FOR_STACK_OVERFLOW 2然后实现钩子函数void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName) { // 这里不要调用 FreeRTOS API先挂住或者写一个错误标志 __disable_irq(); while (1) { } }当任务栈被写穿时FreeRTOS 会调用这个钩子程序卡在 while(1) 里总比默默跑飞好诊断。配合 Keil 生成的 map 文件把 HardFault 发生时 PC 指针的值对应到具体函数就能快速定位是哪个任务栈溢出。3.3 用 vTaskList 做“任务心电图”别靠猜FreeRTOS 跑起来之后怎么确认任务真的在调度最简单的方法是用 vTaskList 输出一张任务状态表。这个函数需要同时开两个配置#define configUSE_TRACE_FACILITY 1 #define configUSE_STATS_FORMATTING_FUNCTIONS 1然后建一个专门的调试任务把 vTaskList 的结果通过串口打出来void DebugTask(void *argument) { char buf[512]; for (;;) { vTaskList(buf); printf(%s, buf); vTaskDelay(2000); } }输出格式里每个任务会有一行状态字段是 R运行、B阻塞、S挂起、D删除。如果所有任务都是 B只有空闲任务是 R那说明业务任务要么在等一个永远不会来的事件要么任务根本没创建成功。这个时候不要怀疑芯片去查信号量、消息队列和事件标志。不过这里要提醒一句vTaskList 输出需要 printf 支持而 F103 的 printf 默认走向 fputc重定向到串口才看得到。如果你把 printf 重定向到 ITM/SWO那也完全没问题。关键是先确认串口本身能输出否则你又会陷入“芯片没反应”的幻觉。3.4 PWMDMA 在 PA1/PA3 没波形先查外设映射再怀疑芯片很多人在 F103 上用定时器 PWM 配合 DMA 输出波形典型的就是用 TIM2 的通道在 PA1、PA3 上输出。PA1 对应 TIM2_CH2PA3 对应 TIM2_CH4。如果代码看起来没问题但这两个引脚就是没有波形先不要骂芯片按顺序查这几项。第一GPIO 是否配置成了复用推挽输出。PWM 是片上外设驱动引脚必须用 GPIO_Mode_AF_PP不能是 GPIO_Mode_Out_PP。第二AFIO 时钟有没有打开。虽然 TIM2 默认没有重映射但很多标准库工程在开启复用功能时仍然要 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE)。第三DMA 通道是否选对了。DMA1 的每个通道对应的外设请求是固定的TIM2_CH2、TIM2_CH4 分别挂在哪条通道上需要查《STM32F103中文参考手册》里的 DMA 请求映射表不能凭感觉填。配置 DMA 搬数据到 CCR 寄存器时数据类型尤其容易错。CCR 是 16 位寄存器所以你的波形数据数组元素应该用 uint16_t而不是 uint32_t。如果用 32 位数组DMA 会把高低字节错位搬进去输出的 PWM 波形会完全乱掉。我见过一个项目调了一整天“芯片坏”最后发现只是 DMA 外设数据宽度设置成了 32 位改成 16 位后波形立刻恢复正常。另外有人说定时器输出 PWM 占空比到不了 100%其实这不是芯片坏了而是理解问题。ARR 设成 999、CCR 设成 999 时输出在大多数配置下不会得到一个持续的高电平因为比较事件的行为和计数器从 0 重新开始有关。如果业务上需要 100% 占空比最干脆的办法是直接把 GPIO 拉高或者用 CCR 大于等于 ARR 的方式来实现前提是你查过定时器手册里对边界条件的说明。3.5 新编译器报 include 错误先检查工程配置别给芯片定罪最近两年不少人还在用标准库 v3.5 移植 FreeRTOS但 Keil MDK 已经更新到 ARM Compiler 6 了。编译老工程时经常会出现 #include freertos/freertos.h 报错或者提示“检测到 #include 错误。请考虑更新 compile_commands.json”。这个错误跟芯片完全没有关系纯粹是工程的头文件路径没配好。FreeRTOS 源码目录非常多至少要把这几条路径加进 C/C 编译器头文件路径里FreeRTOS/Source/includeFreeRTOS/Source/portable/RVDS/ARM_CM3FreeRTOS/Source/portable/MemMang如果你用 VSCode Clangd 看代码那 compile_commands.json 里也得有这些路径。ARM Compiler 6 对代码的检查比 AC5 严格老工程会报出一堆 warning甚至把隐式声明直接当成错误处理。这时候先更新工程配置不要把时间浪费在反复烧录上。4. 结合 Modbus RTU 与标准库移植的实战排查实录4.1 FreeMODBUS v1.6 RS232串口无响应的三元排查STM32F103 标准库 v3.5 FreeMODBUS v1.6 通过 RS232 串口实现 Modbus RTU是工业类小项目里非常经典的组合。很多人在这个组合下遇到的第一个问题是主站发请求从站没有任何响应。第一先查 RS232 电平转换。F103 的 UART 引脚输出的是 TTL 电平不能直接连电脑的串口必须经过 MAX3232、SP3232 这类芯片转换。如果你用的是 USB 转 TTL 模块那只能看到乱码或者完全没反应因为电平不匹配。第二查接线RXD、TXD、GND 三根线缺一不可最容易被忽略的是 GND 不共地结果信号线上全是悬浮噪声。第三查 FreeMODBUS 的定时器端口。Modbus RTU 要求 3.5 个字符时间的帧间隔FreeMODBUS 在移植时需要提供一个定时器来产生这个时间基准。很多人只初始化了串口忘了把对应的定时器中断函数接入 FreeMODBUS 的 porttimer.c 接口结果协议栈永远不认为一帧数据接收完整自然不回帧。这个问题的排查方法很粗暴先用逻辑分析仪抓串口 TX、RX 引脚的波形如果 RX 有数据进来但 TX 一直没反应再往下查中断和定时器配置。4.2 串口助手能看到乱码但 FreeMODBUS 不回帧这个现象比完全没反应更隐蔽。串口助手能看到乱码说明硬件链路是通的数据确实进来了但字符内容不对。最常见的原因是波特率不准。F103 的 UART 波特率由 APB 时钟和 USARTDIV 决定如果你在代码里把系统时钟配置成了 72MHz但 FreeRTOS 的 configCPU_CLOCK_HZ 或者 SystemCoreClock 变量没有同步那 FreeRTOS 的 tick 时间会不对UART 如果用了基于时钟的延时或超时计算也会跟着乱。FreeMODBUS 这边还要确认从机地址是否匹配。调用 eMBInit 时第一个参数是模式 MB_RTU第二个是设备地址比如 0x01。主站轮询的地址必须和这个一致。还有一个容易踩的坑是校验位设置不一致。主站用 8E1从站初始化成 8N1字符本身能收到但 Modbus 帧的校验和计算全错从站自然不会回帧。遇到这种问题先把串口参数统一成 9600 8N1 或者项目原始的约定再去调协议栈。4.3 掉电保存、红外接收等“玄学”问题的真实原因有人把 F103 掉电保存数据的异常也算到“芯片假”头上其实 F103 内部没有 EEPROM。要想掉电保存数据一是用备份寄存器和 VBAT 供电二是用片内 Flash 模拟 EEPROM三是外挂 EEPROM。直接用 Flash 做掉电保存时如果写之前没有先擦除扇区或者没有处理写保护数据就会丢。F103 的 Flash 编程必须按字或半字写入擦除按扇区这个时序如果被 FreeRTOS 任务切换打断后果就是“上次存的数据莫名其妙没了”。红外的“玄学”问题也一样。红外接收头输出的是脉冲信号最好用定时器输入捕获来测量脉宽而不是靠 GPIO 中断加 delay 去数时间。如果你的工程里同时开了串口接收中断和红外 GPIO 中断优先级没安排好的话任何一个高频中断都可能把另一个吃掉。看到 HAL_UART_ERROR_FE 这类报错时先查串口帧错误一般是波特率偏差、接线过长或者地线不好造成的跟芯片真假关系不大。所以当项目表现“很玄”的时候我建议把模块一个个拆掉。先跑裸机串口回环再跑 FreeMODBUS 从站再挂 FreeRTOS最后加红外和掉电保存。每加一层都验证一次问题一定会暴露在某一次组合里而不是“芯片没反应”这种大锅。5. 怎么买芯片才能不被坑个人经验5.1 渠道判断一眼识别翻新引脚聊了这么多排查方法其实最省事的方法还是从源头避开假芯片。STM32F103 现在供应渠道分层很明显原厂或者授权代理商、正规目录商、国产兼容原厂、淘宝散新翻新。最忌讳的是看哪家便宜就买哪家尤其是量产项目一颗芯片便宜几毛钱但一批板子全部返工的成本足以让你怀疑人生。收到芯片后先看引脚。全新原装芯片的引脚应该是均匀、光亮、没有焊料的翻新片的引脚根部常残留有旧焊料或者整排引脚有重新镀锡后那种不自然的发亮。再看丝印。原装丝印虽然不同批次有差异但总体是清晰、锐利的打磨片的表面会有一层细微的磨痕丝印边缘发虚有的字体甚至能看出原来品牌的一点点轮廓。还有一个很土但很好用的办法用手摸芯片表面。全新原装芯片表面是平整且光滑的翻新片被磨过之后光洁度会不一样有些甚至能摸出轻微的涩感。当然这些只能做初步判断最终还是要以上电测试为准。5.2 收到货先做的三件事第一抽检读 ID。每批芯片抽 3 到 5 颗用 ST-Link 连接读取 Device ID、唯一 ID、Flash 容量确认和型号一致。第二烧写裸机点灯测试。不要一上来就烧完整的 FreeRTOS 工程先用一个简单的 GPIO 翻转程序跑几个小时看有没有偶发死机。如果裸机点灯都会死那这颗芯片再便宜也不能用。第三进行关键外设验证。如果你的产品要用 PWMDMA、FreeRTOS、Modbus RTU那就把这三项分别做成测试固件在新批次芯片上逐一验证。我自己在实际操作中的体会是绝大多数“芯片没反应”的现场最后都是工程配置、焊接、最小系统、外设初始化这些环节出的问题真正拿到假芯片的情况反而没那么高但一旦遇到了就是批量的事故。所以排查时先冷静先确认最小系统再谈 FreeRTOS最后再怀疑芯片。而买芯片这个环节宁可多花一点成本走正规渠道也不要拿整个项目的交付时间去赌省下来的那几块钱。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门