STM32F103烧录全攻略:从零开始用Keil5部署你的第一段代码
你有没有过这样的经历?
电路板焊好了,ST-Link插上了,Keil也打开了——结果一点击“下载”,弹窗却冷冰冰地告诉你:“No target connected”。
那一刻,是不是觉得硬件、软件、玄学都站在了你对立面?
别急。今天我们就来彻底拆解STM32F103通过Keil5烧录程序的全过程,不讲空话,只说实战中真正有用的细节。无论你是刚入门的新手,还是被某个奇怪问题卡住的老手,这篇文章都会帮你打通“写代码 → 下载 → 运行”这条关键链路。
为什么是 Keil5 + STM32F103?
在嵌入式开发的世界里,STM32F103几乎是绕不开的一个型号。它基于ARM Cortex-M3内核,主频72MHz,Flash从64KB到512KB不等,价格便宜、资料丰富,被戏称为“国产芯片杀手”。
而Keil MDK(即Keil5),作为ARM官方推荐的开发环境之一,凭借其成熟稳定的编译器和调试系统,在工业控制、汽车电子等领域仍占据主导地位。
虽然现在有STM32CubeIDE、VSCode+PlatformIO等更现代的选择,但很多企业项目依然沿用Keil,原因很简单:
✅ 稳定性高
✅ 调试体验好
✅ 对老旧项目的兼容性强
所以,掌握“Keil5烧录STM32”这项技能,并不是复古,而是为了能看懂别人的工程、接手老项目、甚至量产烧录时不出错。
烧录的本质是什么?
很多人以为“烧录”就是把.hex或.axf文件拷贝进芯片,其实不然。
真正的烧录是一个四步闭环过程:
- 连接:PC通过ST-Link与目标芯片建立物理通信;
- 识别:读取芯片ID,确认型号匹配;
- 擦除 → 写入 → 校验:将程序数据写入Flash,并逐字节比对;
- 运行:跳转到复位向量,启动用户程序。
这其中任何一个环节出问题,都会导致失败。下面我们一步步来看怎么确保每一步都能走通。
第一步:搭建开发环境
必备工具清单
| 组件 | 推荐配置 |
|---|---|
| 开发主机 | Windows 10/11(64位) |
| IDE | Keil MDK v5.38 或以上版本 |
| 下载器 | ST-Link/V2 或 Nucleo 板载调试器 |
| 目标板 | STM32F103C8T6最小系统板(蓝 pill)或其他F103系列 |
| 连接线 | 2.54mm排针+杜邦线 或 SWD专用下载线 |
⚠️ 注意:不要使用劣质USB线!很多“无法连接”问题其实是供电不足造成的。
安装Keil与器件支持包
- 安装Keil MDK后,打开μVision5;
- 点击
Project → Manage → Pack Installer; - 搜索并安装:
-Keil::STM32F1xx_DFP(设备固件包)
-ARM::CMSIS(核心外设库)
安装完成后,新建工程时就能看到STM32F103系列选项了。
第二步:创建一个可烧录的工程
我们以最常见的STM32F103C8T6(64KB Flash)为例。
新建工程流程
Project → New uVision Project- 选择芯片型号:
STMicroelectronics → STM32F103C8 - Keil会自动添加启动文件
startup_stm32f10x_md.s(注意:MD = Medium Density)
🔍 小知识:F103根据Flash大小分为不同密度类型:
- LD: ≤32KB
- MD: 32~128KB → C8属于此类
- HD: >128KB → 如VE、ZE等
选错密度会导致Flash算法不匹配,后续烧录失败!
添加主程序代码(点亮LED)
#include "stm32f10x.h" int main(void) { // 初始化系统时钟(默认为内部HSI,建议外部晶振) SystemInit(); // 使能GPIOC时钟(APB2总线) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); // 配置PC13为推挽输出 GPIO_InitTypeDef gpio; GPIO_StructInit(&gpio); gpio.GPIO_Pin = GPIO_Pin_13; gpio.GPIO_Mode = GPIO_Mode_Out_PP; gpio.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOC, &gpio); while (1) { GPIO_SetBits(GPIOC, GPIO_Pin_13); // LED灭(共阳) for(volatile int i = 0; i < 1000000; i++); GPIO_ResetBits(GPIOC, GPIO_Pin_13); // LED亮 for(volatile int i = 0; i < 1000000; i++); } }📌关键点说明:
-SystemInit()是标准库自带函数,初始化时钟至72MHz(需外部8MHz晶振);
- PC13通常接板载LED,低电平点亮;
- 使用volatile防止循环被编译器优化掉。
第三步:配置下载器与Flash算法
这是最容易出错的地方!
设置调试器
进入Project → Options for Target → Debug标签页:
- 选择ST-Link Debugger
- 点击右侧Settings
在新窗口中:
- 切换到Debug选项卡:
- Interface:SWD
- Clock:1 MHz(初次连接建议设低,避免不稳定)
- 切换到Flash Download选项卡:
- ✅ 勾选 “Program”
- ✅ 勾选 “Verify”
- ❌ 不要勾选 “Reset and Run”(除非确定没问题)
加载正确的Flash算法
点击Add按钮,选择适合你芯片的算法:
| 芯片型号 | 推荐算法文件 |
|---|---|
| STM32F103C8 (64KB) | STM32F1xx Medium-density Flash |
| STM32F103ZE (512KB) | STM32F1xx High-density Flash |
路径一般为:C:\Keil_v5\ARM\FLASH\STM32F1xx_Med-density_Flash.pdsc
💡 如果没加载算法,会出现经典错误:“Flash Algorithm download failed”
第四步:正确连接硬件
ST-Link与STM32F103接线表
| ST-Link引脚 | STM32F103引脚 | 功能说明 |
|---|---|---|
| SWCLK | PA14 | 时钟线 |
| SWDIO | PA13 | 数据线 |
| GND | GND | 公共地 |
| 3.3V | 3.3V(可选) | 供电或电平参考 |
✅ 正确做法:优先让目标板自己供电,ST-Link只用于调试(不供VCC)
❌ 错误做法:两边同时供电,可能造成电源冲突!
BOOT模式必须正确!
STM32有三种启动方式,由BOOT0和BOOT1引脚决定:
| BOOT0 | BOOT1 | 启动区域 |
|---|---|---|
| 0 | X | 主闪存(正常运行)✅ |
| 1 | 0 | 系统存储器(ISP升级) |
| 1 | 1 | 内部SRAM |
👉烧录和运行时,BOOT0必须接地(拉低)!
否则芯片不会从Flash启动,即使程序烧进去了也不会执行。
第五步:执行烧录并验证结果
一切就绪后,按下快捷键F8(Load),观察输出窗口日志:
Connecting to target... Target connected. Erase Done. Programming... Verification... OK Download completed successfully.🎉 成功标志:看到最后一行“Download completed successfully.”,并且板载LED开始闪烁!
如果失败,常见提示及应对如下:
| 错误信息 | 可能原因 | 解决方案 |
|---|---|---|
| No target connected | 接线错误 / 未上电 / SWD接触不良 | 检查GND是否共地,测量PA13/PA14电压 |
| Cannot access target | BOOT0=1 或 复位脚悬空 | 确保BOOT0接地,NRST接10kΩ上拉 |
| Flash algorithm failed | 算法未加载 / 芯片型号选错 | 重新选择正确密度的Flash算法 |
| Programming failed at 0x08000000 | 写保护开启 | 在Options → Debug中取消勾选“Enable Code Readout Protection” |
高级技巧与避坑指南
1. 如何判断当前连接的是哪颗芯片?
在Keil的调试模式下,执行以下命令查看芯片ID:
> mon vendorid > mon deviceinfo或者直接看输出栏中的:
Device ID: 0x416 (STM32F103xx)不同封装和密度的F103,ID略有差异,可用于精准识别。
2. 批量烧录怎么做?
对于小批量生产,可以使用ST-Link Utility工具导出批处理脚本:
st-link_cli.exe -c SWD -P firmware.bin 0x08000000 -V -Q配合自动化测试平台,实现一键刷机。
3. 烧录成功但不运行?检查这些地方!
- 是否开启了独立看门狗(IWDG)且未喂狗?
SystemInit()是否成功配置了外部晶振?- 中断向量表偏移是否正确?(尤其使用Bootloader时)
建议首次运行时先单步调试,进入main函数后再全速运行。
最佳实践总结
| 类别 | 推荐做法 |
|---|---|
| 硬件设计 | PCB预留SWD接口测试点;BOOT0通过0Ω电阻接地 |
| 软件配置 | 使用标准外设库或HAL库;统一命名规范 |
| 烧录流程 | 固化操作SOP;记录版本号与烧录时间 |
| 防呆机制 | 外扩SPI Flash保存校准参数,避免被覆盖 |
| 安全策略 | 出厂前关闭读保护,防止锁死芯片 |
写在最后
烧录看似只是“点一下按钮”的小事,但它背后涉及软硬件协同、协议通信、存储管理等多个层面的知识。一旦掌握,你会发现:
- 再也不怕别人说“程序下不进去”;
- 能快速定位是代码问题还是硬件问题;
- 在团队中成为那个“搞定下载器”的人。
而这,正是嵌入式工程师成长的第一步。
下次当你再次面对那根小小的四线SWD接口,请记住:它不只是几根导线,而是你通往芯片世界的大门。
现在,去点亮你的第一个LED吧。💡
如果你在实际操作中遇到具体问题,欢迎留言交流。我们可以一起分析log、查接线、调设置——毕竟,每个成功的烧录背后,都曾有过无数次失败的尝试。