
STM32F103这个片子在我手里折腾了快十年从最早的C8T6到后来的ZET6裸机、RTOS、各种外设都玩过说实话很少遇到“芯片没反应”这种问题。但最近朋友寄来一块板子说程序下载成功FreeRTOS移植也照着教程做了死活跑不起来LED不亮串口也没数据。我拿到板子第一件事不是看代码而是看芯片本身——丝印有点不对劲。这个“不对劲”让我想起来市面上的STM32F103假货确实多尤其是“打着原装旗号的打磨翻新片”和“国产兼容片”一旦进了FreeRTOS这种对时序敏感的工程问题就全冒出来了。如果你也遇到“程序下载成功芯片却毫无反应”的情况又恰好用的是STM32F103加FreeRTOS的组合先别急着怀疑自己的移植代码。芯片本身是不是正品、是不是翻新、是不是打磨片往往才是问题的根源。这篇博文我会从硬件最小系统排查、FreeRTOS移植的经典坑、假芯片识别方法到一份可以照着查的排障速查表把这类问题一次性讲透。1. 芯片没反应的排查思路先分清楚是“没电”还是“没跑”“芯片没反应”这个描述太宽泛了它可能指上电后什么动静都没有也可能指程序下载成功但运行不了还可能是指跑着跑着突然死机。不同的现象排查方向完全不同。我的习惯是先把问题分成三类。第一类是物理层完全没反应上电后电流表显示电流极小或者为零用万用表量芯片VDD引脚根本没有3.3V。这种情况基本不用怀疑芯片真假先检查电源、LDO、滤波电容、焊接有没有虚焊甚至PCB有没有短路。很多新手一上来就怀疑芯片其实是自己电源没焊好。第二类是电源正常芯片也下载了程序但程序就是跑不起来。这种情况既有可能是硬件问题也有可能是软件问题。硬件层面要查复位引脚是不是一直处于低电平、BOOT0和BOOT1的跳线是否正确、外部晶振有没有起振软件层面要查编译配置、启动文件、下载器设置以及FreeRTOS移植时SysTick和中断优先级配置是否正确。第三类是程序跑了一段时间后死机或者复位后能跑、断电再上电又不跑了。这类问题和假芯片的关联度最高因为翻新片和兼容片在供电纹波容忍度、Flash写入可靠性、内部RC振荡器精度上往往和原装正品有差距。在裸机程序里这些差距可能被容忍但FreeRTOS对时序和中断很敏感隐患就容易暴露出来。我排查这类问题的固定顺序是先量电压再查复位然后看启动模式接着换一个最简单的裸机点灯程序试跑最后才回到FreeRTOS工程本身。这个顺序能最大限度减少变量避免在不干净的条件下反复折腾代码。2. 硬件层面的第一轮排查最小系统的四个关键点2.1 供电纹波和芯片“假死”的关系STM32F103官方手册给出的供电范围是2.0V到3.6V推荐典型值是3.3V。但很多人在测量时只看了电压平均值忽略了纹波。我曾经用示波器看过一块假芯片板子的供电电压显示3.3V但纹波接近300mV低频段还有周期性跌落。这种供电质量在裸机跑个while(1)点灯没问题但FreeRTOS在任务切换时电流会突然变化供电跌落超过芯片的复位阈值就表现为周期性重启或直接卡死。排查供电问题时不要只信万用表要用示波器看VDD引脚的纹波和跌落幅度。标准做法是在每个VDD引脚旁边放一个100nF的陶瓷电容再在电源入口放一个4.7uF到10uF的钽电容或陶瓷电容。如果板子上连这些小电容都被省了芯片在FreeRTOS调度下出现偶发复位的概率会非常高。假芯片对供电质量的容忍度比原装片更低这一步不能省。2.2 复位引脚和启动模式的坑STM32F103的NRST引脚是低电平复位内部有上拉电阻正常工作时应该为高电平。如果外部接了复位按键或RC复位电路要确认电容没有漏电、按键没有短路。实际操作中我遇到过NRST被一个误解法的下拉电阻拉到低电平导致芯片上电就一直处于复位状态程序永远跑不起来。这种情况看起来就是“芯片没反应”但换一百个芯片都一样。BOOT0和BOOT1的电平状态是另一个高频坑。默认情况下BOOT0应该拉低让芯片从主Flash启动。如果BOOT0悬空芯片可能随机从系统存储区启动程序下载进去也不会运行。有些开发板上有跳线帽有些没有新手最容易漏掉这一步。使用SWD下载时即使BOOT0不是低电平也能下载成功但运行不起来这个现象极具迷惑性。我在实际项目中BOOT0直接接一个10k下拉电阻到地BOOT1直接接10k下拉电阻到地不做跳线。这样保证了芯片必然从Flash启动也减少了人为配置错误。如果是为了之后用串口ISP下载程序再把BOOT0跳高也不迟。2.3 外部晶振起振问题STM32F103内部有一个HSI RC振荡器精度典型值约1%温度变化时会漂移。如果工程里配置成使用外部HSE晶振而晶振又没有起振系统时钟源会切换失败程序可能卡在启动阶段的时钟初始化函数里。排查时用示波器量晶振两个引脚的波形应该能看到正弦波或方波。如果完全看不到波形检查晶振的负载电容是否匹配、晶振是否虚焊、引脚是否连错。需要特别留一个心眼部分翻新片在长期存放后引脚氧化严重焊接时容易出现虚焊导致晶振电路不工作。这时候你用眼睛看是看不出来的要拿万用表的通断挡挨个量或者用助焊剂重新焊接。不过FreeRTOS场景下更常见的情况恰恰是相反的——大部分教程工程默认使用内部HSI不依赖外部晶振假芯片的HSI精度又不好导致串口波特率偏移、SysTick周期不准。这种问题在硬件层不那么容易发现但会让FreeRTOS的时基异常表现为任务调度混乱甚至看起来像死机一样。3. FreeRTOS工程里最容易踩的软件坑把硬件问题排除得差不多之后再回头看FreeRTOS移植本身。这里的坑数量不少而且有几个非常具有迷惑性。我见过有人在论坛上把“假芯片”当成“FreeRTOS会挑芯片”来问其实锅多半在软件配置上。3.1 SysTick被覆盖导致系统启动后卡死FreeRTOS在xPortStartScheduler里会重新配置SysTick作为系统节拍中断源并且接管SysTick_Handler。如果你在main函数之前的某个库函数里也写了SysTick_Handler并且在FreeRTOS接管SysTick后没有保护性处理就会出现两个定义同时存在的情况链接阶段可能不报错但运行逻辑全乱。更隐蔽的情况是你的裸机代码里写了一个延时函数这个函数使用了SysTick中断而这个延时函数在FreeRTOS启动之后被某个任务调用了。当FreeRTOS接管SysTick后SysTick_Handler在port.c里已经被替换为xPortSysTickHandler你的延时函数等待的标志位永远不会置为1任务就卡死在延时循环里整个系统看起来就像没反应。我的建议是进入FreeRTOS之后不要再直接操作SysTick做延时统一用vTaskDelay或vTaskDelayUntil。如果必须在中断里处理时间相关逻辑用FreeRTOS的软件定时器或者时间片。这个教训是我在一个步进电机项目中踩到的当时排查了整整一个晚上最后才发现是旧代码里的SysTick延时函数在作怪。3.2 启动文件选错导致的中断向量问题STM32F103根据Flash容量大小分为低密度、中密度、高密度等不同型号。C8T6是中密度Flash是64KB启动文件应该用startup_stm32f10x_md.s。如果你不小心用了startup_stm32f10x_hd.s编译链接也能通过但中断向量表的位置和大小不匹配部分中断回调永远进不去。我遇到过有人把C8T6当大容量芯片用、选了hd.s启动文件结果FreeRTOS的PendSV_Handler和SVC_Handler被启动文件错误地分配到不同地址任务切换永远不触发最终表现就是创建任务成功但调度器不起作用系统像死了一样。这个问题的排查要点是打开工程设置里的启动文件选项确认和芯片型号匹配。标准外设库工程里编译器会根据全局宏比如STM32F10X_MD来选择启动文件宏定义错误也会导致同样的问题。我在VSCodeCMake的移植工程里也踩过类似的坑后来在CMakeLists里明确指定启动文件路径才彻底解决。3.3 中断优先级分组和FreeRTOS的硬性要求FreeRTOS要求使用4位抢占优先级也就是NVIC优先级分组必须设置为Group 4。如果你在不同的地方调用NVIC_PriorityGroupConfig设置了不同的分组FreeRTOS内部的临界区切换、中断嵌套保护就会失效。这个问题的典型表现是在某个中断里调用了带FromISR后缀的API但中断优先级高于FreeRTOS允许的最大值导致系统直接进入HardFault_Handler。FreeRTOS官方文档里有一条明确要求所有中断的抢占优先级必须小于等于configMAX_SYSCALL_INTERRUPT_PRIORITY移植时这个宏会被映射到具体的数值。我在调试时会把SystemCoreClock和优先级分组的配置放到main函数最前面并且只设置一次同时把configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY设为5再在中断初始化里保证所有调用FreeRTOS API的中断优先级不高于这个值。照这个规则大部分和优先级相关的问题都能绕开。3.4 堆栈溢出和任务创建失败的隐蔽表现FreeRTOS移植时很多人会把configTOTAL_HEAP_SIZE设置得比较小用heap_4.c管理内存。如果任务栈和队列、信号量占用的总量超过了堆大小prvHeapAlloc会返回NULL而xTaskCreate在创建失败时不会打印任何信息任务句柄变成NULL。如果你之后调用了vTaskDelete并传入NULL系统会崩溃。更隐蔽的是堆栈溢出检测不开启任务栈溢出会把相邻内存踩坏导致其他任务的数据被改写现象五花八门有时候是某个变量的值莫名其妙变成负数有时候是串口偶发乱码有时候是任务切换频率变慢。这些表现会让人怀疑到“假芯片”头上但其实是软件问题。我建议在FreeRTOSConfig.h里把configCHECK_FOR_STACK_OVERFLOW设为2同时实现vApplicationStackOverflowHook函数在溢出时点亮一个错误LED或进入一个死循环方便定位。还要在任务创建后检查返回值如果失败打印任务名和堆剩余量。这样一来软件问题就不会被误判为硬件或芯片问题。4. 假芯片识别实战三类“李鬼”一次看明白如果硬件最小系统没问题裸机程序也跑得动但FreeRTOS工程总是出现各种诡异现象那就要认真怀疑芯片来源了。根据我这些年的经验市面上的假芯片大致可以分为三类每一类的识别方法都不一样。4.1 翻新打磨片最容易伪装成“原装”翻新打磨片是把旧芯片拆下来打磨掉表面原来的丝印再重新印上STM32F103C8T6的字样。这类芯片外观上最容易露馅的地方在丝印本身原装ST芯片的丝印字样清晰、线条锐利、高低温环境下耐磨翻新片的丝印往往有模糊、字体风格不统一、深浅不一等问题。识别手段也很直接用放大镜或手机微距镜头观察芯片表面打磨过的区域会有细微的不均匀光泽或者有明显的抛光痕迹。另一个办法是用棉签蘸酒精擦拭丝印如果是二次印刷的印刷墨迹很可能被擦掉或者变淡。原装芯片表面一般是磨砂质感二次打磨后再印刷的芯片要么过于光滑要么有细密的砂纸纹路。翻新片在FreeRTOS场景下最大的问题是内部Flash老化擦写次数已经接近寿命上限。下载小工程可能没问题但工程稍微大一点、Flash擦写比较频繁写入后校验就会失败或者芯片运行一段时间后程序出错。如果你发现每次下载程序要看运气有时候成功有时候失败十有八九是Flash或供电出了问题而翻新片的Flash寿命衰减是最常见的原因。4.2 国产兼容片上电时序和时钟精度的差异国产兼容片以GD32F103系列为代表脚位和寄存器基本兼容ST的STM32F103很多工程不经过修改就能跑起来。但兼容不是复制GD的芯片在内部架构、上电时序、复位延迟、Flash读取等待周期上都和ST有差别。这些差别在裸机点灯程序里根本看不出来但在FreeRTOS里就容易出事了。GD芯片的内部RC振荡器精度和温度漂移特性与ST不一样如果你用了HSI做时钟源串口波特率可能偏出几个百分点UART通信偶尔出错SysTick的计数值虽然由软件配置但时钟源偏移会让FreeRTOS的时基不准任务延迟的时间要么偏快要么偏慢。识别GD芯片最快的方法是读芯片ID。用ST-Link Utility或者STM32CubeProgrammer连接目标板读Device ID和Flash Size。更直接的方法是查丝印上的生产批次编码GD的编码规律和ST不同有时候还会印上GD的Logo。另外GD的芯片在USB、ADC等外设行为上和ST也有差异如果你用到了这些外设出现的现象可能非常奇怪比如ADC采样值整体偏移、USB枚举失败等。对于一个对实时性和可靠性有要求的FreeRTOS工程我的建议是如果项目出货量大且对成本敏感可以在验证充分后使用GD但如果是做产品原型、调试学习或者客户有指定芯片品牌尽量用正规渠道的ST原装片不然排查成本会远高于省下的那点差价。4.3 低配改标片容量和温标的障眼法还有一类假芯片是用低配版本改高配版本比如把STM32F103RBT6改成C8T6引脚数一样Flash容量翻倍标称。或者把工业级的丝印打磨后重新印成军工级或车规级卖高价。这种造假方式在视觉上很难察觉因为芯片本身确实是ST的东西只是型号和实际规格不符。识别方法依然是读ID和Flash容量。STM32F103C8T6的Device ID是0x410Flash大小应该显示为64KB。如果你读到的是128KB甚至更大说明芯片本身可能是更高容量的型号只是丝印被打磨重印了。这种情况看起来是“捡了便宜”但工程上的麻烦也很大如果芯片实际是Flash较小的低配版工程代码超过实际容量下载时就能发现异常如果芯片本身是高配版改标成低配那问题在于你无法确认芯片的工作温度范围和寿命等级是否匹配项目需求。低配改标片在FreeRTOS场景下相对少见因为功能上基本能跑。但如果是把大批闪存已经接近寿命末期的芯片改标出售就会出各种Flash写入和读取问题表现和翻新片类似。我在确认芯片身份时除了看ID还会刻意做一个全Flash读写测试把每个扇区写一遍再读出来对比这样能暴露不少隐患。4.4 芯片测试小技巧上电电流和温升的旁证除了看丝印、读ID、查Flash容量平时我还会用几个辅助手段来判断芯片是不是有问题。第一个是空载上电电流。用稳定的直流电源给板子供3.3V在没连接调试器、没下载程序的情况下测整板静态电流。原装STM32F103C8T6空跑一个while(1)空循环不带任何外设静态电流通常在十几毫安到二十多毫安这个量级。如果电流明显过大或者过小都说明芯片可能有异常。但要注意这个值会受板上其他器件影响只适合作为旁证不适合当唯一判断依据。第二个是持续运行温升。让芯片反复进行Flash擦写和外设操作运行10分钟到半小时正常芯片的温升比较温和。如果芯片升温很快、烫手可能是内部电路有问题比如翻新片内部存在受损的驱动管或者打磨时破坏了封装的热导性能。把FreeRTOS工程直接跑起来持续做任务切换和通信观察芯片温度和供电电流的稳定性比跑几个小时的裸机测试更能暴露问题。第三个是串口回环测试。在FreeRTOS工程里开一个UART配置成几个常用的波特率比如9600、115200、460800发一串已知数据再收回来做CRC校验。如果高波特率下误差率很高除了检查晶振精度也要怀疑芯片内部时钟源的精度是否达标。这个测试能帮忙分辨到底是你代码里波特率计算有误还是芯片时钟源的底子不行。5. 工程排障速查表照着查不绕路为了节省后续排查时间我把“STM32F103 FreeRTOS芯片没反应”这个场景下最常见的现象、可能原因和验证手段整理成了一张速查表供大家在实际调试时参考。现象可能原因验证方法解决方向上电后完全没反应LED不亮无任何电流变化供电故障、焊接虚焊、VDD短路万用表量VDD电压和GND通断示波器看纹波修复电源电路补焊电容程序下载成功但运行不起来BOOT0悬空或电平不对量BOOT0引脚电平确认是否接地BOOT0接10k下拉到地程序下载成功但运行不起来启动文件或宏定义和芯片容量不匹配检查工程启动文件是否md.s换成匹配型号的启动文件程序下载后偶发下载失败或校验错误Flash老化翻新片概率高全Flash读写测试反复擦写更换正品芯片FreeRTOS任务不切换系统卡死SysTick_Handler被覆盖或陈旧代码占用SysTick全局搜索SysTick_Handler查是否有两个定义统一使用FreeRTOS延时API删掉旧的SysTick处理函数任务创建后系统崩溃或跑飞堆大小不足任务创建失败返回NULL打印堆剩余空间检查xTaskCreate返回值增大configTOTAL_HEAP_SIZE增加任务栈大小中断进不去或调用FromISR后硬件错误中断优先级分组错误或优先级超限确认中断优先级不超过configMAX_SYSCALL_INTERRUPT_PRIORITY统一NVIC分组为Group 4串口乱码高波特率通信错误率高HSI精度不足、晶振起振失败示波器看晶振波形串口回环测试多个波特率改用外部晶振修正时钟配置运行一段时间后死机或复位供电纹波大、假芯片内部电路质量问题示波器长时间监控复位脚和VDD纹波加强滤波电容更换正品芯片这张表不可能覆盖所有问题但能把最常见的几种“芯片没反应”收敛到一个很小的范围。我最想强调的还是那句老话先软件后硬件或者先硬件后软件都行但一定要有一个确定的顺序不要同时改一堆变量否则出了问题根本不知道是谁引起的。6. 日常防“假”的几个实操习惯最后分享几个我在项目里养成的习惯也算是对大家少走弯路的一些提醒。第一采购芯片时要看渠道资质不要只看单价。一样标着STM32F103C8T6正规代理出和路边低价散片的价差可能只有两三块钱但后者的翻新概率极高。对于要量产的项目芯片来源一定要稳定最好能拿到原厂的授权书或者代理的进货凭证。个人DIY的话选销量大、评价稳定的店铺买回来先做一次“身份认证”再投到正式工程里。第二芯片拿回来先做一批基础“体检”。我的做法是抽几颗样片焊到最小系统板上用CubeProgrammer读Device ID和Flash容量和丝印型号对比然后跑一个固定固件这个固件会做Flash全片读写、UART自测、内部RC频率测算跑完通过的才批量使用。这套流程看起来繁琐但对批量项目来说前期花十几分钟识别一批坏片比后期测试终端设备出现故障再返修要划算得多。第三新芯片首次使用不要直接上复杂工程。先跑一个裸机点灯程序确认芯片供电、复位、时钟、下载链路都通畅了再一步步把FreeRTOS和外设驱动加进来。这一步能帮助把“芯片本身问题”和“工程代码问题”彻底分开避免在两个不明确的变量之间反复横跳。第四如果项目到了测试阶段才发现个别板子跑FreeRTOS会死机不要只盯着那一块板子修建议把同一批次的芯片重新编号登记追查出问题芯片的丝印批次和采购来源。很多时候同一批板子的芯片来自同一次采购只要找到一颗有问题的其他板子的排查方向也就明确了。这个习惯帮我定位过两批来路不明的“兼容片”直接把问题消灭在量产之前。我个人在实际操作中的体会是STM32F103加FreeRTOS这个组合本身非常成熟它不会因为芯片某个型号细微的差异就崩掉只要硬件和软件都是对的跑起来很稳定。一旦出现“芯片没反应”这类问题先怀疑芯片真假、再怀疑FreeRTOS配置、最后才怀疑自己的业务代码这个顺序在大多数情况下都成立。尤其是当你发现裸机工程一切正常、FreeRTOS工程却诡异百出的时候把目光从代码移到芯片丝印上往往会有意外收获。