
1. 为什么还要折腾串口烧写这件事手里攥着一块STM32最小系统板J-Link和ST-Link都在抽屉里躺着但偏偏遇到产线小批量试产、客户现场返修、或者板子已经把SWD接口封在结构件里拆不出来的情况——这时候能救场的往往就是那根不起眼的USB转TTL线。串口烧写ISPIn-System Programming不是什么新鲜技术但真正把它用稳、用透、出了问题能自己定位的人并不多。FlyMCU这个工具在圈子里流传很广界面朴素得像上个时代的产物可它背后调用的是芯片出厂固化的Bootloader走的是STM32系统存储器里的那段引导程序这条路子跟调试器烧写完全是两套逻辑。这篇文章想解决的问题很具体让你在没有调试器、或者调试器接口不可用的情况下仅凭一个USB转串口模块和FlyMCU把程序可靠地写进STM32。适合谁看刚入门的嵌入式学习者、需要做小批量烧录的产线技术员、以及那些手头项目已经定型、不想再为烧写专门留调试口的开发者。我会把Bootloader的启动条件、BOOT引脚的电平组合、FlyMCU的配置项含义、以及我实际踩过的坑都摊开讲重点放在“为什么这么配”和“出问题怎么查”上而不是简单罗列步骤。需要提前说明的是串口烧写依赖芯片内部的系统Bootloader不同系列F1、F4、L4等的Bootloader版本和协议细节有差异本文以最常见的STM32F103系列为主线展开其他系列在关键差异处会单独标注。另外FlyMCU本质是一个串口ISP上位机它做的事情就是按照芯片厂商定义的同步协议把HEX文件分包发进去理解了这个协议框架你排查问题时就不会只盯着“点下载没反应”干着急。2. 串口烧写的底层逻辑与方案选型2.1 Bootloader是怎么被唤醒的STM32上电或复位后芯片会采样BOOT0和BOOT1两个引脚的电平决定从哪块存储区域取指令。这个机制是硬件层面的跟你在代码里写了什么完全无关。以F103为例BOOT0接高、BOOT1接低时芯片从系统存储器启动那段区域是出厂时固化的Bootloader用户改不了也擦不掉BOOT0接低时从主闪存启动也就是你正常跑程序的状态。这里有个容易被忽略的细节BOOT引脚的电平是在复位信号的上升沿被锁存的不是持续采样。也就是说你先把BOOT0拨到高电平再按一下复位键芯片才会进入Bootloader如果只是拨了开关没复位芯片还停留在原来的运行状态。我见过不少人拨完开关就直接点下载然后抱怨“连不上”其实芯片压根没进ISP模式。系统Bootloader启动后会初始化USART1F103上是PA9为TX、PA10为RX然后等待上位机发来同步字节0x7F。收到同步字节后Bootloader回一个ACK0x79握手就算建立。之后上位机发命令、Bootloader回响应整个协议是命令-应答式的每一步都有校验。FlyMCU做的就是把这套流程封装成图形界面你点“下载”时它在背后跑的就是这一串交互。2.2 为什么选FlyMCU而不是官方工具官方有STM32CubeProgrammer功能更全支持串口、USB DFU、SWD多种通道。但在纯串口ISP这个场景下FlyMCU有几个实际优势体积小、免安装、启动快在一台老旧的工控机上双击就能跑界面上的“读芯片”“擦除”“写Flash”“校验”按钮一目了然产线工人培训五分钟就能上手最关键的是它对HEX文件的解析比较宽容一些由老版本编译器生成的、格式不太规范的HEX文件CubeProgrammer可能会报错FlyMCU往往能正常处理。当然FlyMCU也有短板它不支持命令行批量操作做自动化烧录得另想办法对新型号芯片的器件ID识别依赖内置数据库太新的片子可能认不出来。所以我的建议是日常开发调试用CubeProgrammer或调试器产线小批量、现场应急、教学演示这类场景用FlyMCU两者不冲突。2.3 硬件链路的几个硬性条件USB转TTL模块的选择有讲究。市面上常见的CH340、CP2102、FT232都能用但要注意电平匹配STM32的USART是3.3V电平如果你的模块输出是5V TTL长期直连可能损伤芯片的IO。稳妥做法是选带3.3V/5V电平选择跳线的模块拨到3.3V档或者模块本身是3.3V输出的。我实测过5V模块直连F103的情况短时间能用但RX引脚长期承受5V属于超规格使用不建议这么干。接线只有三根是必须的模块的TX接芯片的PA10RX模块的RX接芯片的PA9TXGND对接GND。注意是交叉连接TX对RX。很多人第一次接会接成TX对TX然后死活通不了。另外如果目标板是独立供电的USB转TTL的VCC不要接避免两个电源打架如果目标板没电可以用模块的3.3V输出给板子供电但要确认模块的3.3V输出电流够不够CH340的3.3V输出通常只有几十毫安带不动整板只适合给最小系统供电。BOOT0的处理方式取决于你的板子设计。有拨码开关或跳线帽的最省事没有的话可以用杜邦线把BOOT0接到3.3V烧写完再拔掉接回GND。我个人的习惯是在自己的测试板上焊一个两位拨码开关BOOT0和BOOT1各一位省得每次插拔杜邦线。3. FlyMCU配置项逐个拆解与实操要点3.1 端口与波特率的取舍打开FlyMCU第一件事是选端口。这里有个坑如果你插上USB转TTL后设备管理器里能看到COM号但FlyMCU的下拉列表里没有点一下旁边的刷新按钮通常就能出来。如果还是没有检查驱动是否装好CH340在Win10以上系统有时需要手动装驱动。波特率的选择是个权衡。FlyMCU默认115200这个速率在大多数情况下够用烧一个几十KB的工程大概几秒钟。想更快可以上到230400甚至460800但前提是你的USB转TTL模块和线材质量过关。我用过一根劣质USB线115200下正常提到230400就频繁校验失败换线后问题消失。所以波特率不是越高越好稳定优先。产线环境如果线缆较长、干扰较大反而建议降到57600牺牲一点速度换可靠性。还有一个隐藏参数是“校验方式”FlyMCU界面上通常有“偶校验”和“无校验”的选项。STM32的Bootloader协议默认使用偶校验8位数据1位偶校验这个必须跟芯片侧一致选错了握手就过不去。大部分情况下保持默认即可但如果你用的是某些特殊的串口转接方案比如经过隔离器校验位可能被改动这时候要回来检查这一项。3.2 HEX文件与“编程到文件末尾”的含义加载HEX文件后FlyMCU会显示文件大小和起始地址。这里要理解一个概念HEX文件里记录的地址是芯片Flash的绝对地址FlyMCU会按照这些地址去写而不是从0x08000000无脑顺序写。所以如果你的工程链接脚本里把程序起始地址设成了0x08004000比如做了IAP升级前面留了Bootloader区FlyMCU会正确地写到0x08004000不会覆盖前面的引导程序。这一点比某些只会从固定地址开始写的工具要灵活。“编程到文件末尾”这个选项字面意思是只写到HEX文件记录的最后地址后面的Flash区域不动。如果不勾选有些版本的FlyMCU会按芯片全容量擦除后再写。对于做IAP升级的场景这个选项很关键你要保留前面的Bootloader区就必须确保擦除范围不越界。我的做法是烧写前先用“读芯片”功能确认一下目标区域的内容烧完再读回来比对虽然多花几十秒但能避免把引导程序擦掉的惨剧。3.3 擦除、写入、校验的时序关系FlyMCU的“下载”按钮背后其实是一串动作握手、发擦除命令、等待擦除完成、逐页写入、最后整体校验。擦除是以页为单位的F103小容量型号页大小1KB中容量2KB。擦除命令发出后芯片内部要花时间执行这段时间上位机在等应答界面上可能看起来“卡住”了其实是正常的。如果板子上Flash容量大、擦除范围广等个几秒甚至十几秒都正常不要急着拔线。写入阶段是按数据包发的每包最多256字节Bootloader每收一包回一个ACK。如果某一包没收到ACKFlyMCU会重试重试几次还不行就报错。校验阶段是把刚写进去的内容读回来逐字节比对这一步能抓出写入过程中的位翻转。我遇到过校验失败但重新烧一次就好的情况多半是接触不良或电源波动导致的偶发错误如果每次都失败在同一地址那就要怀疑Flash该区域是不是坏了或者HEX文件本身有问题。注意擦除操作不可逆烧写前务必确认HEX文件的地址范围没有覆盖到不该动的区域尤其是做了IAP分区设计的板子。3.4 读芯片与器件ID识别FlyMCU的“读芯片”功能会发命令获取芯片的器件ID和Flash容量。这个ID是芯片出厂时写死的可以用来确认你连上的是不是预期的型号。比如F103C8的ID对应64KB Flash如果读出来显示128KB那可能是C8T6的“扩容版”实际是C8的die但标了更大容量也可能是你连错了板子。产线批量烧录时先读一颗确认型号再批量操作能避免把A型号的程序烧进B型号的板子。器件ID读不出来通常意味着握手阶段就失败了问题出在硬件链路或BOOT模式上跟HEX文件无关。这时候别在软件配置里打转回头查接线和BOOT引脚。4. 完整烧写流程与现场操作记录4.1 从零开始的一次烧写实录拿一块F103最小系统板目标是把一个点亮LED的工程烧进去。第一步把USB转TTL的3.3V、GND、TX、RX分别接到板子的3.3V、GND、PA10、PA9注意TX-RX交叉。第二步BOOT0用杜邦线接到3.3VBOOT1接GNDF103的Bootloader不依赖BOOT1但接低是稳妥的。第三步插上USB设备管理器确认COM号比如COM5。打开FlyMCU端口选COM5波特率115200校验位偶校验。点“读芯片”如果一切正常下方信息栏会显示器件ID和Flash容量。这一步成功说明握手通了链路没问题。然后点“打开文件”加载HEX确认文件大小和起始地址合理。勾选“编程到文件末尾”和“校验”。点“下载”观察进度条和信息栏先擦除再写入最后校验全程大概几秒到十几秒。烧完后把BOOT0拨回GND按一下复位键程序就跑起来了。如果LED没亮先别怀疑烧写失败用调试器读一下Flash内容确认程序确实写进去了再查程序本身的逻辑。我见过烧写成功但LED不亮的情况最后发现是工程里LED的引脚定义跟板子实际接线对不上跟烧写过程无关。4.2 批量烧录的节奏控制小批量烧录时如果每烧一颗都要手动点一次“下载”效率低还容易漏。FlyMCU没有内置的批量队列但可以利用它的“自动下载”选项部分版本有配合产线夹具实现半自动夹具压针接触测试点操作员按一下启动按钮上位机自动执行握手-擦除-写入-校验。如果没有自动选项就老老实实按流程走但可以把BOOT0的切换做成夹具上的联动开关减少手动插拔。批量场景下我建议每烧10颗抽检一颗用“读芯片”加校验的方式确认。另外烧录工位的电源要稳USB口供电能力参差不齐最好用带外部供电的USB Hub避免多设备同时插导致电压跌落。4.3 关键参数速查表参数项推荐值说明波特率115200稳定优先线材好可上230400校验位偶校验与Bootloader协议一致不可随意改数据位8固定停止位1固定BOOT0高电平烧写时复位上升沿锁存拨完要复位BOOT1低电平F103上非必需接低稳妥接线TX-RX交叉GND共地3.3V电平匹配擦除范围按HEX地址做IAP时务必确认不越界5. 故障排查实录与避坑经验5.1 握手失败的三层排查法“读芯片”没反应是最常见的故障。我的排查顺序是先查物理层再查配置层最后查芯片层。物理层看接线是否交叉、GND是否共地、USB转TTL的TX/RX指示灯在发数据时是否闪烁不闪说明上位机根本没发出去可能是端口选错。配置层看波特率和校验位是否匹配端口号是否选对。芯片层看BOOT0是否真的在高电平、复位是否执行过、芯片是否供电正常。有一次我折腾了半小时最后发现是杜邦线内部断了外表看不出来万用表一量才露馅。所以线材要备几根好的出问题先换线这是成本最低的排除法。5.2 校验失败的几种典型原因校验失败说明写进去的内容跟HEX文件对不上。偶发失败重烧一次就好多半是电源波动或接触不良。固定地址失败先确认HEX文件本身是否完整用文本编辑器打开看末尾有没有异常再考虑Flash该区域是否损坏。还有一种情况是芯片被读保护了读保护状态下Flash内容读不出来校验自然失败这时候需要先解除读保护会全片擦除再重新烧写。读保护的判断方法是能握手、能擦除、能写入但一校验就报错且读芯片时Flash内容全是0xFF或乱码。解除读保护的操作在FlyMCU里通常没有直接按钮需要用官方工具或调试器执行这也是为什么我建议手边常备一个ST-Link专门处理这类“疑难杂症”。5.3 烧写成功但不运行的排查思路程序烧进去了复位后不跑先确认BOOT0是否已经拨回低电平。这是最容易被遗忘的一步芯片还在Bootloader里等着当然不跑用户程序。BOOT0没问题的话用调试器连上去看PC指针停在哪是HardFault还是卡在启动文件的某个循环里。还有一种情况是程序本身依赖的外部晶振没起振而Bootloader阶段不涉及晶振所以烧写一切正常一跑用户程序就卡住。5.4 常见问题速查表现象可能原因处理方式读芯片无响应接线错误/BOOT0未拉高/未复位查交叉接线、拨BOOT0后复位握手成功但擦除失败芯片读保护/Flash损坏解除读保护后重试写入中途报错电源不稳/线材质量差换线、降波特率、外部供电校验失败偶发接触不良/干扰重烧、检查GND校验失败固定地址Flash坏块/HEX异常换芯片验证、检查HEX烧写成功不运行BOOT0未拨回/程序问题拨回BOOT0、调试器查PC6. 几个容易被忽略的细节串口烧写的速度瓶颈不在波特率而在擦除和校验。擦除是芯片内部操作快不了校验要把整个文件读回来比对文件越大越慢。所以优化烧录时间优先考虑减小HEX文件体积比如开优化、去掉调试信息而不是一味拉高波特率。USB转TTL模块的TX/RX指示灯是个好东西发数据时TX灯闪、收数据时RX灯闪能直观判断数据有没有出去、有没有回来。握手阶段如果TX闪了RX不闪说明芯片没应答问题在芯片侧如果TX都不闪问题在上位机或端口。最后说一个我自己的习惯每次烧写前先用“读芯片”确认器件ID和容量再加载HEX烧完再读一次目标区域的前几十个字节跟HEX比对。多花十几秒但能避免“以为烧进去了其实没烧进去”的尴尬尤其是在产线环境里返工的成本远高于这十几秒。