
STM32烧录后不运行这类问题在嵌入式新手求助榜里绝对能排进前三。前两天我帮一个朋友调一块STM32F103C8T6的最小系统板他用的是ST-Link V2配对最新版Keil MDK 5.39烧录过程中没有任何报错进度条走完校验也显示通过最后还提示Application running……可板子上的LED就是死活不亮。换了一根杜邦线、换了一块板子、甚至改用STM32 ST-LINK Utility去烧录问题依旧。折腾了快两个小时最后发现根子不在硬件上也不在程序逻辑而是Keil新版本里一个极其隐蔽的配置项被悄悄重置了。这篇文章就围绕“STM32烧录后不运行”这个现象来做一次完整的排查复盘把最常见但也最容易忽略的几个坑挨个拆开。不管你是刚接触STM32还是在旧工程升级MDK之后莫名其妙遇到板子不跑这套排查思路和解决步骤都能直接抄作业。1. 烧录成功却不运行先分清“没烧进去”和“没跑起来”很多人遇到板子没反应第一反应就是“烧录失败”然后开始怀疑芯片坏了。其实对于STM32来说下载成功和运行成功是两码事。先把这两件事分开后面排查才有方向。1.1 典型现象描述下载成功、校验通过板子就是不动以最常见的工程为例STM32F103C8T6蓝板ST-Link V2四线SWD连接MDK 5.39 STM32F1xx_DFP 2.4.0芯片包工程是一个最简单的LED闪烁程序。点击DownloadBuild Output窗口按顺序打印出编译信息、下载地址范围、Flash编程进度最后是Verify OK。整个过程看起来一切正常没有任何红色错误。但此时板子上的LED不闪串口没有任何输出按一下板子上的复位键也没反应。如果点Debug进入调试模式程序又能跑起来单步、全速都正常。退出调试、重新上电又回到“死板”状态。这种现象非常典型它的潜台词是Flash里确实写入了正确的程序CPU也确实具备运行条件但上电后没有走到那条“让程序跑起来”的路径上。关键问题在于复位与启动动作而不是程序本身。1.2 从复位启动流程看“运行”需要满足的三个条件STM32上电后要真正运行用户程序需要同时满足三个条件。第一条BOOT0引脚必须处于低电平也就是从主Flash启动而不是从系统存储器或SRAM启动。第二条Flash的0x08000000地址处必须存放正确的初始堆栈指针0x08000004处必须存放正确的复位向量这两个值如果不对CPU上电后连第一条指令都取不到。第三条复位信号必须有效释放让CPU从复位状态解脱正常读取向量表并跳转。上面说的第三条就是最容易出问题的地方。程序烧进了Flash但它需要一次“复位事件”才会被CPU取指执行。如果你烧完程序后CPU一直停在复位状态、或者是停在调试暂停状态那它自然不会去执行Flash里的代码。什么时候会停在复位状态比如调试器在下载完成后没有做“控制复位”这一动作或者根本没有连接复位引脚无法把CPU从复位里拉出来。1.3 插着ST-Link能跑拔掉就不跑这个信号很关键还有一种更常见的描述下载完程序后插着ST-Link板子能运行但只要一拔掉调试器重新上电板子就没反应。这种现象其实是1.2节里第三个条件的一个变种。如果你在Keil里下载完成后点过Debug或RunCPU是在调试器的控制下运行起来的这时候它并不依赖一个完整的掉电复位过程。当你拔掉ST-Link电源断开重来CPU要依靠自身的上电复位时序来启动。此时如果Flash里的内容没问题就只剩下一个可能下载完成后CPU并没有被配置为“复位后自动运行”而调试器在断电瞬间也没有发出正确的复位信号导致CPU卡在了一个未初始化状态。知道了这个逻辑排查范围一下子就小了优先检查烧录工具的复位配置再检查板子的BOOT0设置最后才考虑程序本身有没有问题。大部分“烧录成功但不运行”的案例都死在前两步。2. 第一嫌疑Keil新版本把“Reset and Run”选项弄丢了如果你遇到的正是“烧录提示成功但板子不跑手动按复位才跑”的情况恭喜你90%的概率是Keil里的“Reset and Run”没有被勾选。这个选项的作用是在下载完成后通过调试器自动对芯片做一次复位并让程序开始运行。2.1 Reset and Run是干什么的为什么新版Keil容易踩英文名Reset and Run翻译过来就是“复位并运行”。打开Keil工程在Options for Target里找到Debug选项卡右侧Settings按钮然后在弹窗最下方的Flash Download页签里就能看到这个勾选框。它的含义非常直白下载完固件之后调试器负责给目标芯片一个复位信号然后让CPU从复位向量开始执行。为什么说新版本Keil容易在这种小地方坑人我实测过MDK 5.36、5.37、5.38、5.39这几个版本发现从5.37开始整个Debug驱动设置窗口的布局和默认行为一直在变。最典型的问题是旧工程从旧版本MDK迁移过来UVOPTX工程配置文件里保存的Flash Download设置项会因为新版本界面重排而丢失或重置成默认值。默认值是什么在部分新版本组合下Reset and Run就是不勾选的。另外一个隐蔽点是新版Keil安装时如果芯片包不是最新可能同时存在多套调试驱动配置文件。你明明在某个路径下勾选了Reset and Run但MDK实际调用的却是另一套配置。所以很多人在论坛里问“为什么我勾了还是不行”大概率是没改对地方。2.2 Debug 和 Utilities 两个入口都要查这里必须专门强调一个经验Keil里存在两个长得几乎一模一样的“Flash Download”设置入口。一个在Options for Target → Debug → Settings → Flash Download另一个在Options for Target → Utilities → Settings → Flash Download。绝大多数初学者只改了Debug入口而Keil在烧录时默认使用的可能是Utilities入口里的配置。尤其是当工程在Utilities选项卡里选择了“Use Flash Download”而不是“Use Debug Driver”时两套配置是独立的。Debug页里勾了Reset and RunDownload时却不生效因为Download命令走的是Utilities页的配置。最稳妥的改法是在Utilities页左上角把使用方式选成“Use Debug Driver”意思是让下载操作也复用Debug页里的那一套调试驱动配置。这样你只需要在Debug → Settings → Flash Download里勾一次Reset and Run。如果你的工程用的是独立Flash Download配置那就必须两边都进一遍把Reset and Run、编程算法、擦除方式全部核对一致。提示改了配置之后别急着点Download先重新编译一次。Keil的Flash Download配置有时会被“Build”动作重新加载不编译直接下载还是会用上一次的旧配置。这个细节很多人不知道实测多次踩坑。2.3 怎么确认问题就是它看输出窗口和手动复位判断是不是Reset and Run没勾有个一眼就能看的办法。下载完成后留意Build Output窗口的最后几行输出。如果程序在下载后被正常复位并运行输出窗口通常会多一行类似Application running的提示。如果下载结束后直接停在编程完成的输出来没有看到任何“运行”相关字样那基本可以断定目标芯片没有被复位程序自然也不会跑。此时手动按一下板子上的复位按键观察现象。如果LED开始闪烁、串口开始打印说明Flash里的程序完全正常问题确实出在缺了一次自动复位。下载成功后手动复位能运行而自动复位不生效99%就是Reset and Run没有勾选或者没有生效。注意如果按复位键也不运行那就先别执着于这个选项往下继续排查BOOT0和硬件复位电路。3. 第二个坑AC6编译器把程序“编译”得起了不步Reset and Run解决了一大批问题但还有一批工程卡在更隐蔽的地方——编译器。MDK 5.37之后新装的Keil MDK默认编译器变成了Arm Compiler 6也就是AC6。老工程如果一直用的AC5突然被新版本Keil接管非常容易出现“编译能过、烧录正常、上电不跑”的现象。3.1 MDK 5.37之后默认编译器切到AC6老工程最容易中招AC6和AC5虽然都是ARM的编译器但语法标准、优化策略、内建函数行为差异很大。很多老工程为了兼容代码里会写一些AC5特有的扩展语法比如__attribute__((section(xxx)))、特殊的#pragma pack写法、匿名结构体、内联汇编的格式等等。AC6不一定报错但处理方式不同导致生成的目标代码行为发生变化。最经典的翻车现场是工程在AC5下编译延时函数正常LED闪得清清楚楚切到AC6之后同样的代码编译零警告烧录下去LED要么不闪要么闪烁速度肉眼根本看不清。原因是AC6在-O2优化级别下会把一些“没有副作用”的空循环直接优化掉。如果你的延时函数里没有加volatile修饰空循环在AC6看来等于什么都没做直接被删掉延时时间从100毫秒变成了几微秒。程序是在跑的但现象看起来就像“没运行”。还有一种更严重的老工程的启动文件版本太旧和AC6编译器、新版Device Family Pack里的CMSIS核心不匹配。编译虽然通过但启动阶段SystemInit的调用顺序、堆栈初始化、数据段拷贝出现偏差程序一上电就跳进了HardFault_Handler然后卡死。这种现象同样表现为“烧录成功但不运行”。3.2 用调试器看PC停在哪里几分钟定位启动异常如果怀疑是编译器或启动层面的问题不要瞎猜直接进调试模式看PC指针停在哪里。方法是点Debug进入调试然后全速运行等两三秒后点暂停看左下角Registers窗口里的PC值以及Call Stack窗口里的调用栈。这里有一张我整理过很多次的对应表可以直接对照PC停下位置可能原因处理方向Reset_Handler 或 SystemInit启动文件或时钟初始化卡住检查芯片PACK版本、SystemCoreClock赋值HardFault_Handler启动阶段发生硬件异常编译器兼容性、内存越界、DMA/外设提前访问main 函数内部但外设无反应程序在跑但初始化被优化或寄存器映射异常检查优化级别、寄存器结构体定义0xFFFFFFFE 或特殊地址向量表损坏或堆栈指针错误检查Flash首地址内容和启动文件停在某条空循环里循环被优化或等待标志位永远不置位检查volatile、外部中断、上拉配置如果PC停在HardFault_Handler而你的老工程又刚被新MDK接管AC6兼容性就是头号嫌疑人。这时候不要硬刚AC6先切回AC5验证程序本身是否正常。3.3 老工程不想折腾两步切回AC5怎么切回AC5打开Options for Target → Target选项卡在右上角ARM Compiler那一栏默认显示的可能是“Use default compiler version 6”。把它手动改成“Use installed toolchain version 5.06”然后重新编译下载。如果下拉菜单里没有AC5选项说明你装的MDK没有带Legacy Support需要去Keil官网单独下载Arm Compiler 5的兼容支持包装上之后重启Keil就能看到。如果你的工程必须用AC6那就需要花点时间做兼容性修正。重点检查几类问题所有__asm内联汇编改成AC6支持的__ASM格式或直接外置汇编文件位域和结构体对齐方式用pragma显式声明所有循环延时里的循环变量加上volatile还有把优化级别从-O2调回-O0至少能排除掉“空循环被优化”这一大类的坑。这类问题没有统一脚本可跑只能靠编译警告和调试器逐条修。心得我在给客户迁移老项目时默认策略永远是先保持AC5不动保证业务功能稳定再单独开一个分支去测AC6兼容性。烧录后不运行这种问题发生在编译器切换时AC5和AC6的区别就是主要矛盾。4. 硬件和工程配置层面的“伪坑”BOOT0、Flash算法、复位线排查完软件配置之后如果问题还没解决就得回到板子本身。烧录后不运行有时候不是Keil的锅而是几个老生常谈的硬件细节没做到位。4.1 BOOT0没拉低程序烧进去也白搭STM32F103系列有BOOT0和BOOT1两个引脚它们决定芯片上电后从哪里启动。BOOT00从主Flash启动也就是你烧录程序的地方这是正常运行时的标准配置。BOOT01、BOOT10从系统存储器启动那一块是芯片出厂自带的Bootloader区通常用于串口ISP下载里面没有你的程序。所以只要BOOT0被拉高你烧再多次程序上电后跑的永远不是你的代码表现就是“板子完全没反应”。很多最小系统板、蓝色Pill板的板载跳线帽位置特别坑。BOOT0和BOOT1跳线挨在一起用万用表量一下很容易发现用户把跳线帽插错了位置。排查步骤也就几步确认BOOT0连接到一个10K下拉电阻到GND或者跳线帽插在0的位置BOOT1也建议直接接地避免启动模式进入SRAM这种异常状态。上电后测量BOOT0引脚电压正常应该是0V附近如果量出来是3.3V问题找到了。4.2 Flash Download算法选错写入位置不对还有一个容易被忽略的坑藏在工程配置里Flash编程算法和芯片型号不匹配。STM32F103C8T6是64KB Flash的中容量芯片对应编程算法是STM32F10x Medium-density Flash。如果在Options for Target → Debug → Settings → Flash Download的Programming Algorithm里选的是High-density Flash这种大容量算法Keil会按512KB甚至1MB的擦除和编程时序去操作Flash。后果有两种。一种是下载时直接报错因为擦除算法访问了芯片不存在的地址区间。另一种更折磨人下载时没有明显报错但程序被写进了一个错误的Flash扇区或者编程时序不对导致写入的数据在Bootloader启动时根本不被识别。上电后CPU从0x08000000取向量表里面全是0xFF或者垃圾数据自然什么都干不了。正确的做法是在Flash Download配置里先和芯片型号核对一下。C8T6对应Medium-densityCBT6、RBT6同样ZET6是High-density。同时确认擦除方式是Erase Sectors还是Erase Full Chip如果你只是想快速烧个测试程序选Erase Sectors就够能省不少时间。4.3 ST-Link RST没接复位控制失效很多教程教你用SWD模式烧录接线只需要SWDIO、SWCLK、GND三根。三根线确实能完成下载和调试但在某些情况下它会限制“复位”相关功能的正常工作。Keil的ST-Link调试驱动里有一个Reset模式选项常见的是Normal和HW RESET两种。Normal模式用SWD协议内部复位和外部RST引脚无关HW RESET模式则要拉动ST-Link的RST引脚让芯片产生一次硬件复位。如果你在Flash Download里勾选了Reset and Run但ST-Link和目标板的RST引脚没接同时调试驱动又配置成HW RESET模式下载后复位动作根本发不出去程序不会运行。解决办法很简单把ST-Link的RST引脚接到目标板的NRST复位引脚上四根线SWDIO、SWCLK、GND、RST全接齐然后到Reset模式里选择Normal或HW RESET中的一种。我习惯有RST线就用HW RESET没有RST线就用Normal两者保证和硬件连接方式匹配就行。5. 完整排障流程与最终解决方法附自检清单讲了这么多理论最后用一个真实排障记录把整个过程串起来。以后你再遇到“STM32烧录后不运行”直接按这个顺序走一遍极少有跑不出来的问题。5.1 从现象到根因一次完整排障实录我朋友那块板子的情况是这样的LED闪烁程序MDK 5.39ST-Link V2下载提示Verify OK但LED没反应。我的排查过程如下步骤操作现象判断1看Build Output末尾提示Verify OK无Application running烧录完成但目标未被自动复位2手动按复位键LED开始正常闪烁Flash内容无问题问题在复位流程3打开Debug → Settings → Flash DownloadReset and Run未勾选找到直接原因4检查Utilities页使用方式为Use Flash Download内部Reset and Run同样未勾选确认两套配置都失效5勾选Debug页Reset and Run并把Utilities改成Use Debug Driver重新编译下载输出出现Application runningLED闪烁正常6拔掉ST-Link重新上电LED依旧正常闪烁问题彻底解决如果第2步手动按复位也不亮我就会继续套用下面的流程先量BOOT0电压确认不是从系统存储器启动再用STM32CubeProgrammer读回0x08000000地址的数据看前4个字节是否是0x2000xxxx这种合法的SRAM地址0x08000004处是否指向0x0800xxxx的Flash地址最后确认Flash算法芯片容量是否匹配。这套流程走完基本能覆盖所有常见故障点。5.2 三步组合拳把“烧录后不运行”一次解决针对绝大多数情况我总结了一个三步走方案你现在就可以拿去用。第一步打开Options for Target → Utilities把Flash Download方式改为Use Debug Driver。同时在Debug → Settings → Flash Download里勾上Reset and Run确认芯片型号和Flash编程算法正确地址范围从0x08000000开始。第二步检查硬件接线。ST-Link和板子之间接SWDIO、SWCLK、GND、RST四根线BOOT0引脚确认是低电平板子有独立复位按键的话测一下NRST引脚按下复位时能被拉低松开后恢复高电平。第三步重新编译然后点Download。看输出窗口是否出现Application running。如果没有手动按复位键确认程序能跑。能跑说明问题在复位配置不能跑用调试器看PC停在哪个位置按第3节的表格继续排查。这里还有一个万能辅助工具STM32 ST-LINK Utility新版叫STM32CubeProgrammer。在Keil烧录完成但板子不跑的时候用这个工具连接芯片读取整个Flash内容或执行Verify能很直观地告诉你Flash里面的程序和编译出来的axf/hex是不是一致。它也能对芯片执行复位操作很多情况下在CubeProgrammer里点一下Reset板子就能跑这本身就是一种判别手段。5.3 以后怎么避坑新工程上电前的自检清单用清单的方式结束这篇文章的实操部分。我每次接触一块新板子、或者切换Keil版本之后都会过一次这个清单电源指示灯是否正常亮起NRST引脚复位后是否恢复高电平。BOOT0是否为低电平BOOT1是否接地。ST-Link/J-Link接线是否包含RSTReset模式和硬件连接是否匹配。Options for Target → Debug → Settings → Flash Download是否勾选了Reset and Run。Programming Algorithm是否和芯片实际容量匹配。Utilities页是否和Debug页共用同一套配置。烧录后输出窗口是否出现Application running。拔掉调试器重新上电程序是否依然正常运行。如果工程是旧工程迁移确认ARM Compiler版本是否和代码兼容。这一套流程不需要花费太多时间但它能帮你在烧录阶段就把90%的“不运行”问题拦截下来。尤其是“Reset and Run”和“BOOT0”这两项说是嵌入式新手翻车率最高的两个坑毫不夸张。按我个人经验Keil的新版本确实会在一些配置细节上给你“惊喜”但它的稳定性没问题。遇到烧录后不运行的怪事先别骂编译器、别怀疑芯片按照2.1、2.2小节检查复位配置再核对BOOT0和Flash算法十有八九就解决了。如果你正在经历这个问题建议直接照着第5.2节的三步走试一遍大部分情况下几分钟就能让板子稳稳跑起来。