1. 项目缘起:为什么还要用串口烧录STM32?
在玩STM32单片机的圈子里,一提到程序烧录,大家脑子里蹦出来的第一个工具多半是ST-Link或者J-Link。确实,这些调试器功能强大,支持在线调试、断点、单步,是开发阶段的绝对主力。那为什么我们今天还要回过头来,聊一个看起来有点“复古”的话题——通过串口给STM32烧录HEX程序呢?
这背后有几个非常实际的场景。首先,成本控制。一个正版的ST-Link V2或者J-Link OB价格不菲,而对于一些简单的、批量的、或者对调试需求不高的产品(比如一些定制的控制器、小家电的主控),每一分钱成本都要精打细算。一个几块钱的USB转TTL串口模块(比如CH340、CP2102)就能搞定烧录,这中间的差价是实实在在的。其次,生产与维护的便利性。在生产线上,工人可能不需要复杂的调试环境,只需要一个稳定的、傻瓜式的程序烧录工位。串口烧录接线简单(通常就VCC、GND、TX、RX四根线),操作界面直观,不容易出错。再者,对于一些空间极其受限的板子,可能根本没有预留标准的SWD或JTAG调试接口,但UART串口作为最基础的通信外设,几乎是必留的。最后,它也是实现IAP(在应用编程)功能的基础。你的产品需要通过网络、蓝牙或者SD卡进行固件远程升级吗?其底层往往就是通过芯片自带的串口Bootloader来实现的。
所以,掌握串口烧录,绝不是学习一个过时的技术,而是掌握了一项在特定场景下极具性价比和实用性的核心技能。它让你在硬件设计、生产部署和后期维护上,都多了一个可靠的选择。
2. 核心原理:STM32的Bootloader与HEX文件解析
要理解串口烧录,必须搞明白两个核心概念:STM32内置的Bootloader,以及我们要烧录的HEX文件到底是什么。
2.1 STM32的Bootloader:芯片自带的“刷机模式”
你可以把STM32想象成一台电脑。平常我们开发程序,就像在电脑的Windows系统里运行各种软件。而Bootloader,就像是电脑的BIOS或者U盘启动菜单。它是一个固化在芯片内部系统存储区(System Memory)的一段出厂程序,独立于用户闪存(Flash)。当芯片满足特定条件启动时,就会运行这段程序,而不是跳转到你的用户程序。
STM32进入这个Bootloader模式的条件通常有两种:
- 通过启动引脚(BOOT0/BOOT1)配置:这是最常用的方式。以STM32F1系列为例,将BOOT0引脚接高电平(3.3V),BOOT1接低电平(GND),然后给芯片复位或重新上电,芯片就会从系统存储区启动,运行UART Bootloader。
- 通过软件方式调用:在你的应用程序中,可以通过设置特定的选项字节(Option Bytes)或者直接跳转到系统存储区的起始地址(例如0x1FFFF000 for F1)来软件复位并进入Bootloader模式,这常用于实现IAP功能。
进入Bootloader模式后,芯片就不再执行你的应用程序,而是等待通过串口(或其他接口,如USB、CAN,取决于型号)接收特定的命令,来完成对主闪存的擦除、编程、读取等操作。我们今天聚焦的,就是通过UART串口与这个Bootloader通信。
2.2 HEX文件:机器码的“带地址快递单”
我们在Keil、IAR等IDE中编译生成的可执行文件,通常是二进制的机器码。但如果直接把这一串0和1通过串口发给Bootloader,它是懵的:这些数据应该放在闪存的哪个地址呢?这就需要一种带地址信息的格式,HEX(Intel HEX)文件就是其中一种标准。
一个HEX文件不是一堆乱码,它有非常严谨的结构。我们拆开一行典型的HEX记录看看::1000000000040020D1000000D9000000D70000004A
- 起始符
:: 每一行HEX记录都以冒号开头。 - 数据长度
10: 表示这行记录包含0x10(即16个)字节的有效数据。 - 地址
0000: 这是一个16位的偏移地址,需要结合后续的扩展线性地址记录来确定最终地址。这里0000通常表示从0x08000000(STM32 Flash起始地址)开始的偏移。 - 记录类型
00:00表示这是数据记录(Data Record),即真正的程序数据。还有其他类型,如04(扩展线性地址记录)、01(文件结束记录)。 - 数据
00040020D1...: 这就是实际的程序机器码,每两个字符代表一个字节(十六进制表示)。 - 校验和
4A: 从数据长度到数据结束的所有字节相加,取和的低字节,然后计算其二进制补码。用于验证这一行数据在传输过程中没有出错。(0x10+0x00+0x00+0x00+0x00+0x04+...+0xD7) 的低字节补码 = 0x4A。
Bootloader协议的工作,就是解析我们发送过去的HEX文件(或者更底层地,解析我们按照HEX格式组织的数据和地址),然后根据地址信息,将数据准确地写入STM32芯片闪存的对应位置。
注意:除了HEX,还有一种常见的格式是BIN(二进制)文件。BIN文件是纯数据,不含地址信息。在用串口Bootloader烧录BIN文件时,你必须手动指定烧录的起始地址(通常是0x08000000)。而HEX文件自带地址,一般更不容易出错。很多烧录工具都支持这两种格式。
3. 硬件连接与软件准备:搭建你的烧录环境
理论清楚了,我们开始动手。你需要准备一些硬件和软件。
3.1 硬件连接:四线制与电平匹配
硬件连接非常简单,但细节决定成败。
所需硬件:
- STM32开发板或目标板。
- USB转TTL串口模块:推荐使用CH340G或CP2102模块,价格便宜,稳定性好。
- 杜邦线若干。
接线方法(重点!):
- USB转TTL模块的3.3V/VCC->STM32的3.3V(如果目标板可自供电,则只接GND,不接VCC,避免电源冲突)。
- USB转TTL模块的GND->STM32的GND(共地,必须接!)。
- USB转TTL模块的TX->STM32的RX(例如PA10,USART1的RX)。
- USB转TTL模块的RX->STM32的TX(例如PA9,USART1的TX)。
关键配置步骤:
- 启动模式设置:找到板子上的BOOT0和BOOT1引脚(参考你的芯片数据手册)。将BOOT0用跳线帽或杜邦线接至3.3V(高电平),BOOT1接至GND(低电平)。这是让芯片从系统存储区启动的关键。
- 串口引脚确认:确认你连接的STM32串口引脚(如PA9/PA10)在芯片复位后,默认功能就是USART_TX/USART_RX,并且没有被其他复用功能占用。通常USART1是首选。
- 复位按钮:确保你能方便地对STM32进行复位操作。很多开发板都有复位按键。
实操心得:电平匹配至关重要!确保你的USB转TTL模块是3.3V电平的。虽然STM32的IO口多数兼容5V耐受,但Bootloader通信期间使用5V电平可能存在风险,强烈建议使用3.3V模块。如果模块只有5V输出,TX线可以串一个1kΩ电阻到STM32的RX,但最好还是换用3.3V模块。
3.2 软件工具选择:各有千秋的烧录利器
与串口Bootloader通信,需要上位机软件。这里介绍几款主流且免费的工具:
STM32CubeProgrammer(ST官方推荐):
- 优点:ST官方出品,支持连接方式最全(ST-Link, UART, USB DFU, SPI, I2C等),功能强大,不仅可以烧录HEX/BIN,还能擦除、读取、修改选项字节、加解密等。界面现代化。
- 缺点:软件体积较大,启动稍慢。
- 适用场景:综合开发、生产烧录、IAP调试。这是目前ST主推的通用烧录工具,逐渐取代了旧的Flash Loader Demonstrator。
Flash Loader Demonstrator(旧版官方工具):
- 优点:软件小巧,启动快,专注于UART串口烧录,操作简单直接。
- 缺点:ST已停止更新,对新系列芯片支持可能不全。界面较老。
- 适用场景:仅需UART烧录老旧型号STM32(如F1系列)的简单场景。
mcuisp(FlyMcu):
- 优点:国产软件,非常轻量,绿色免安装。对串口烧录支持很好,特别是对STM32F1系列。很多国内开发者熟悉。
- 缺点:界面较为简陋,更新不频繁,对新芯片支持依赖社区。
- 适用场景:快速、简单的STM32F1系列串口烧录。
Tera Term/PuTTY(需配合脚本):
- 优点:极度灵活,可以通过编写脚本(Tera Term的Tcl,或配合其他命令行工具)实现自动化烧录流程。
- 缺点:需要用户自行理解Bootloader协议并编写或寻找脚本,门槛较高。
- 适用场景:需要集成到自动化生产线或特定定制流程中。
对于大多数初学者和常规应用,我推荐直接使用STM32CubeProgrammer,它代表了ST未来的工具方向,且功能全面。下面我们将以它为例进行详细演示。
4. 实战演练:使用STM32CubeProgrammer完成串口烧录
我们以STM32F103C8T6(蓝桥杯、正点原子等很多开发板用的核心芯片)为例,演示完整流程。
4.1 步骤一:生成HEX文件
首先,确保你的工程能正确编译并生成HEX文件。
- 打开你的Keil MDK工程。
- 点击
Options for Target->Output选项卡。 - 勾选
Create HEX File。 - 重新编译工程(F7)。编译成功后,在工程目录下的
Objects文件夹里,你会找到.hex文件。
4.2 步骤二:硬件连接与上电顺序
按照第3.1节的说明连接好硬件。这里强调一个至关重要的上电顺序,这是很多新手失败的原因:
- 先将USB转TTL模块插入电脑,并安装好对应驱动(CH340或CP2102驱动)。在设备管理器中确认串口号(如COM3)。
- 确保STM32的BOOT0已设置为高电平(接3.3V),BOOT1为低电平(接GND)。
- 给STM32目标板上电。
- 此时,STM32运行的是系统存储区中的Bootloader程序,正在等待串口指令。
踩坑记录:顺序错了大概率会失败。如果先给STM32上电,再设置BOOT0,或者先插USB再设置BOOT,芯片可能已经从用户闪存启动了你的旧程序,从而无法进入Bootloader模式。正确的逻辑是:让芯片在复位或上电的瞬间,根据BOOT引脚的状态决定启动源。
4.3 步骤三:STM32CubeProgrammer 配置与连接
- 打开STM32CubeProgrammer。
- 在左上角连接方式中选择
UART。 - 在右侧配置串口参数:
- Port:选择你在设备管理器中看到的COM口。
- Baud Rate:波特率。这里是个关键点!STM32的UART Bootloader支持多种波特率,但它会先尝试用最低波特率(如F1是9600)进行初始通信(发送0x7F)。上位机工具必须能自动侦测或匹配这个初始波特率。STM32CubeProgrammer的
Autobaudrate功能通常能很好地处理。你可以先勾选Autobaudrate,如果不行,再根据芯片手册手动指定一个(常见有9600, 115200等)。 - Parity:偶校验(Even)。这是另一个极易出错的地方!STM32 Bootloader默认使用偶校验,而不是我们常用的“无校验”(None)。务必设置为“Even”。
- 其他参数:数据位8,停止位1。保持默认即可。
- 点击
Connect按钮。
如果连接成功,你会在下方的Log窗口看到类似“Version: ...”的信息,并且软件界面会显示芯片的UID、闪存大小等信息。如果连接失败,请按以下顺序排查:
- 确认BOOT0/BOOT1引脚电平是否正确且稳定。
- 确认TX/RX线是否接反(交叉连接)。
- 确认串口号选择是否正确。
- 尝试降低波特率,并确认奇偶校验设置为“Even”。
- 尝试给STM32进行一次硬件复位(按复位键),然后立刻点击软件的Connect。
- 换一个USB口或USB转TTL模块试试。
4.4 步骤四:烧录与验证
连接成功后,烧录就非常简单了:
- 在
Download区域,点击Browse,选择你刚才生成的.hex文件。 - 在
Start Address中,如果是HEX文件,地址会自动填充(通常是0x08000000),无需修改。如果是BIN文件,则必须手动填入0x08000000。 - 勾选
Verify after download(下载后校验)和Run after download(下载后运行),这是个好习惯。 - 点击
Start Programming按钮。
软件会依次执行擦除、编程、校验等操作。进度条走完,Log窗口显示“Download verified successfully”和“Programming Complete.”,即表示烧录成功。
4.5 步骤五:切换回正常模式
烧录完成后,必须将BOOT0重新设置为低电平(接GND),然后给STM32复位或重新上电。这样芯片才会从用户闪存(0x08000000)启动,运行你刚刚烧录进去的新程序。
5. 进阶话题与深度避坑指南
掌握了基本操作,我们来看看一些更深入的问题和常见“坑点”。
5.1 Bootloader协议浅析与手动测试
了解一点协议,能让你在出问题时更有底气。Bootloader通信基于简单的请求-应答模型。上位机发送命令帧,Bootloader回复应答帧。一个典型的初始化序列是:
- 上位机发送
0x7F(同步字节)。 - Bootloader回复
0x79(ACK)或0x1F(NACK)。- 收到
0x79表示同步成功,可以进行后续命令。 - 收到
0x1F表示失败,可能是波特率或校验位不对。
- 收到
你可以使用串口调试助手(如SSCOM、AccessPort)手动测试:
- 按正确顺序让STM32进入Bootloader模式。
- 打开串口调试助手,设置端口、波特率(先试9600)、偶校验、8数据位、1停止位。
- 在发送框输入
7F,以十六进制格式发送。 - 如果收到回复
79,恭喜,Bootloader已就绪。如果没反应或回复1F,检查接线和配置。
这个手动测试能最直接地验证你的硬件连接和Bootloader模式是否成功进入,剥离了上位机软件的复杂性。
5.2 不同STM32系列的差异与注意事项
并非所有STM32的串口Bootloader都一样,主要差异在:
- 支持的波特率:F1系列通常支持9600~115200等,而F4/H7等系列可能支持更高的波特率。务必查阅对应系列的《参考手册》中“Bootloader”章节。
- 使用的串口:大部分系列USART1(PA9/PA10)是默认的Bootloader串口。但有些型号(如某些F0、L0)可能使用其他串口(如USART2)。最权威的信息来源永远是芯片的官方参考手册和数据手册。
- 进入方式:除了BOOT引脚,有些系列还支持通过选项字节配置、或特定GPIO状态在复位时进入Bootloader。
重要提示:在设计和调试时,务必为你计划用于Bootloader的UART引脚预留上拉电阻(例如在PA9/PA10上接10kΩ电阻到3.3V)。这是因为在芯片刚上电、Bootloader运行初期,GPIO可能处于浮空状态,易受干扰导致通信失败。加上拉电阻可以显著提高通信稳定性,尤其是在干扰环境或长线连接时。
5.3 常见失败原因分析与解决
连接失败,无任何回应:
- BOOT引脚配置错误或接触不良:用万用表测量BOOT0引脚电压,确保为稳定的高电平(>2V)。
- TX/RX接反:交换TX和RX线再试。
- 目标板未供电或供电不足:检查3.3V电源,确保芯片正常工作。
- 串口驱动问题:在设备管理器中确认串口设备无感叹号,尝试更换USB口或模块。
连接失败,收到NACK(0x1F):
- 奇偶校验设置错误:99%的情况是这个问题。确保软件和手动测试中都设置为偶校验(Even Parity)。
- 波特率不匹配:尝试更换波特率,或使用工具的自动波特率检测功能。
- 芯片型号不支持:确认你的STM32型号确实支持UART Bootloader(绝大多数都支持)。
烧录过程中失败(如擦除错误、编程错误):
- Flash写保护未解除:可能之前设置了读保护(RDP)。在STM32CubeProgrammer的“OB”(Option Bytes)页面,可以尝试将RDP Level从1降为0(这会触发全片擦除!)。
- 电源不稳定:在擦写Flash时功耗较大,确保电源能提供足够电流。
- HEX文件地址错误:检查HEX文件是否指向了合法的Flash地址空间(如0x08000000开始)。不要试图烧录到系统存储区或其他保护区。
烧录成功但程序不运行:
- 忘记切换BOOT模式:烧录后,必须将BOOT0改回低电平并复位。
- 用户程序本身有问题:比如中断向量表地址设置错误、时钟配置失败导致程序“卡死”。可以用调试器(ST-Link)连接看看PC指针停在哪里。
- 选项字节配置冲突:例如,某些启动配置或写保护选项阻止了用户程序的正常启动。在STM32CubeProgrammer中检查并恢复选项字节为默认值。
5.4 从串口烧录到IAP的思维延伸
串口烧录的本质是“外部工具通过Bootloader更新芯片程序”。IAP(In Application Programming)则是“芯片内运行的程序自己更新自己”。实现IAP,通常需要:
- 将Flash划分为两部分:Bootloader区(存放你的IAP引导程序)和APP区(存放用户应用程序)。
- 编写一个IAP引导程序,它也是一个STM32程序,但通常通过串口、USB、CAN、网络等接收新的APP程序数据,并写入到APP区的Flash中。
- 这个IAP引导程序的核心逻辑,和我们今天使用的ST官方Bootloader非常相似:解析数据包、擦除Flash、写入数据、校验、跳转。区别在于,通信协议和触发方式由你自定义。
- 应用程序(APP)需要编译为从APP区地址开始运行(例如0x08004000),并在其中设置好中断向量表的偏移。
因此,熟练掌握串口Bootloader的使用,是理解并自行设计IAP功能的重要基石。你甚至可以先利用官方Bootloader实现一个简单的IAP原型,再逐步替换成自己的引导程序。