从零开始:STM32F103 + Keil5 程序烧录实战指南
你是不是也经历过这样的场景?
代码写得满满当当,编译通过无报错,信心满满地点击“Download”按钮——结果弹出一个红框:“Cortex-M3 Error: Cannot access target.”
或者更糟:烧录成功了,但板子一上电,LED纹丝不动,程序仿佛“消失”了一样。
别急,这几乎是每个嵌入式新手必踩的坑。而问题的核心,往往不在代码本身,而是整个开发链路中那几个看似简单却极易被忽视的关键环节:驱动、连接、配置、启动模式……
本文不讲空泛理论,也不堆砌术语。我们将以STM32F103为硬件平台,Keil uVision5(Keil5)为开发环境,ST-Link V2为调试工具,带你走完一条真实可复现、步步有解释的程序烧录学习路径。目标只有一个:让你第一次就能把程序稳稳烧进芯片,并让它跑起来。
为什么是 STM32F103?它真的适合入门吗?
在众多MCU中,STM32F103被称为“国产工控之王”,不是没有道理的。
它基于 ARM Cortex-M3 内核,主频高达72MHz,自带64KB~512KB Flash 和 20KB~64KB SRAM,支持USART、SPI、I2C、ADC、定时器等丰富外设。更重要的是,它的封装多样(LQFP48/64/100都很常见),价格便宜,且有官方原厂调试支持。
最关键的一点:资料多、社区大、出问题有人救。
比如最常见的“蓝 pill”开发板(STM32F103C8T6),成本不到十块钱,却能完成大多数基础实验。虽然资源有限(Flash 64KB),但对于学习GPIO、中断、UART通信等基本技能绰绰有余。
✅ 小贴士:如果你是初学者,建议从 STM32F103C8T6 或 RCT6 开始,搭配最小系统板 + ST-Link V2 使用。
Keil5 到底是个啥?为什么大家都在用?
Keil uVision5 并不是一个简单的“写代码”的编辑器,它是一套完整的嵌入式开发闭环系统。
你可以把它想象成一个“总控中心”:
- 写代码 → 编辑器
- 编译代码 → ARM Compiler(AC5 或 AC6)
- 生成机器码 → 输出.axf可执行文件
- 下载到芯片 → 调试器(如 ST-Link)
- 调试运行 → 单步跟踪、变量监视、内存查看
它的强大之处在于对 ARM 生态的高度集成,尤其是对 Cortex-M 系列的支持非常成熟稳定。相比一些新兴 IDE(如 STM32CubeIDE),Keil5 在工业项目中依然占据主导地位,特别是在需要严格代码优化和长期维护的场合。
但也要注意:Keil5 仅支持 Windows,这是目前无法绕开的事实。
烧录的本质:不只是“下载程序”那么简单
很多人以为“烧录”就是把 hex 文件拷贝到芯片里,其实远不止如此。
STM32 的程序存储在片上 Flash中,地址从0x0800_0000开始。CPU 上电后会从此处取指执行。而我们所说的“烧录”,实际上是通过 SWD/JTAG 接口,让调试器控制 MCU 进入调试状态,然后:
- 暂停 CPU 运行
- 擦除目标 Flash 区域(必须先擦再写)
- 将编译后的机器码写入指定地址
- 校验数据一致性
- 复位并跳转至入口函数
这个过程依赖于 Keil 内部的Flash Algorithm(闪存算法)——一种针对特定芯片型号定制的底层操作程序。如果没选对算法,哪怕连接正常,也会提示“Flash Timeout”或“Programming Failed”。
⚠️ 常见误区:认为只要接上线就能烧录。实际上,供电、接地、BOOT引脚、NRST信号任何一个出问题,都会导致失败。
核心三件套:STM32 + Keil5 + ST-Link 如何协同工作?
让我们画一张最简化的系统图:
[PC] │ (USB) ↓ [ST-Link V2] │ (SWD: SWCLK, SWDIO, GND, NRST) ↓ [STM32F103] └─ [电源][晶振][复位电路][BOOT配置][外设负载]各组件职责拆解:
| 组件 | 功能 |
|---|---|
| Keil5 | 控制整个流程:编译 → 下载指令下发 → 调试管理 |
| ST-Link | 物理桥梁:把 PC 的 USB 信号转为 SWD 电信号 |
| STM32F103 | 执行单元:接收命令、执行烧录、运行程序 |
其中,ST-Link 是关键枢纽。它是 ST 官方推出的调试器,与 STM32 完全兼容,无需额外配置即可识别绝大多数型号。
实战第一步:搭建开发环境
1. 安装 Keil MDK-ARM v5.x+
前往 Arm 官网下载 Keil MDK(包含 uVision5)。安装时建议勾选:
- C/C++ Compiler
- CMSIS Libraries
- ST Device Family Pack(后续可通过 Pack Installer 添加)
安装完成后打开 uVision5,首次使用可能会提示安装缺失的 Device Family Pack,按提示操作即可。
2. 驱动问题:ST-Link 需要装驱动吗?
答案是:通常不需要手动安装。
Keil 自带 ST-Link 驱动。只要你使用的是标准版 ST-Link V2(非山寨),插入电脑后设备管理器应显示为 “STMicroelectronics STLink Virtual COM Port” 或类似名称。
但如果出现感叹号或无法识别,请前往 ST 官网下载并安装 STSW-LINK009 驱动包。
🔧 检查方法:插入 ST-Link,打开设备管理器 → 端口 (COM & LPT),看是否有新增 COM 口;同时在“通用串行总线控制器”中看到 STLink 设备。
创建你的第一个工程:从零开始不靠 CubeMX
虽然 STM32CubeMX 很方便,但我们先不用它,目的是理解底层机制。
步骤 1:新建工程
- 打开 Keil5 → Project → New uVision Project
- 选择保存路径,命名工程(如
Blink_LED) - 选择芯片型号:输入
STM32F103RCT6(或其他你使用的具体型号)
- 注意:一定要选对!不同密度 Flash 的算法不同!
Keil 会自动加载对应的 Startup File(启动文件)和 Flash Algorithm。
步骤 2:添加必要源文件
至少需要以下三个文件:
| 文件 | 来源 | 作用 |
|---|---|---|
startup_stm32f103xe.s | Keil 安装目录\ARM\PACK\...\Device\Source\ | 定义中断向量表与复位处理 |
system_stm32f1xx.c | ST 提供的标准库或 HAL 库 | 系统时钟初始化 |
main.c | 自建 | 主函数入口 |
右键 Target → Manage Components → Add Files 添加这些文件。
步骤 3:编写 main 函数示例
#include "stm32f1xx.h" void delay(volatile uint32_t count) { while(count--); } int main(void) { // 使能 GPIOC 时钟 RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; // 配置 PC13 为推挽输出(LED 常接此处) GPIOC->CRH &= ~GPIO_CRH_MODE13; GPIOC->CRH |= GPIO_CRH_MODE13_0; // 最大输出速度 10MHz GPIOC->CRH &= ~GPIO_CRH_CNF13; // 推挽输出模式 while(1) { GPIOC->BSRR = GPIO_BSRR_BR13; // LED ON (假设低电平点亮) delay(0xFFFFF); GPIOC->BSRR = GPIO_BSRR_BS13; // LED OFF delay(0xFFFFF); } }📌 说明:这段代码直接操作寄存器,避免依赖复杂库。RCC->APB2ENR用于开启时钟,GPIOC->CRH设置端口模式,BSRR实现原子级置位/清零。
关键设置:让 Keil 成功连接目标芯片
这是最容易出错的部分。即使代码没问题,配置不对也白搭。
Step 1:选择调试器
进入Project → Options for Target → Debug Tab
左侧选择:ST-Link Debugger
✅ 必须确认这里选择了正确的调试器类型!
Step 2:进入 Settings
点击右侧的Settings按钮,弹出新窗口。
➤ Debug 选项卡
- Connect:Under Reset(强烈推荐!防止因低功耗模式导致连接失败)
- Speed: 初始设为100 kHz(通信不稳定时可降速)
➤ Flash Download 选项卡
- 勾选Erase Full Chip或Erase Sectors
- 点击Add→ 加载对应 Flash Algorithm
例如:STM32F10x High-density Flash(适用于 >256KB Flash 的型号)
若是 C8T6,则选Medium-density
⚠️ 如果这里为空或未加载算法,一定会失败!
💡 小技巧:若不确定该选哪个算法,可在 Keil 安装目录搜索
*.flm文件,查看支持列表。
开始烧录!点击 Download 前你要知道的事
一切就绪后,按下快捷键F7编译工程,确保无 error。
然后按F8或点击工具栏上的 “Download” 图标。
此时你会看到输出窗口打印:
Programming... Erase Done. Program Success. Verify OK.恭喜!程序已成功写入 Flash。
接下来:
- 断开调试器 → 重新上电 → 观察 LED 是否闪烁
- 或在 Keil 中点击 “Reset” 和 “Run” 按钮直接运行
常见问题排查清单(亲测有效)
| 故障现象 | 可能原因 | 解决办法 |
|---|---|---|
| Cannot access target | 目标未供电 / 地线未连通 / BOOT 引脚错误 | 检查 VDD/GND 是否正常;测量电压;确认 BOOT0=0 |
| Flash Timeout | Flash 算法未加载 / MCU 处于休眠 | 更换算法;设置 Connect Under Reset |
| Verification Failed | 写入不稳定 / 电源噪声大 | 降低 SWD 速率至 100kHz;加滤波电容 |
| 程序不运行 | BOOT0 被拉高 / 启动文件缺失 | 确保 BOOT0 接地;检查 startup 文件是否加入工程 |
| ST-Link 不识别 | 驱动异常 / 固件过旧 | 更新 ST-Link Utility 并升级固件 |
🛠️ 工具推荐:
- 使用ST-Link Utility单独测试连接状态
- 用万用表测目标板供电是否稳定(3.3V ±5%)
- 示波器观察 SWCLK 是否有波形(通信时)
高阶技巧:提升开发效率的几个实践
1. 启用 HEX 文件输出
在 Output 选项卡中勾选Create HEX File,可用于后期通过其他工具(如 FlyMcu)进行串口 ISP 烧录。
2. 使用分散加载(Scatter Loading)
对于需要自定义内存布局的项目(如 Bootloader + App 分区),可在 Linker 中配置.sct文件,精确控制代码段位置。
3. 快速切换优化等级
在 C/C++ 选项卡中设置 Optimization Level:
--O0:调试友好,变量可见性强
--O2:发布推荐,减小代码体积
4. 集成版本控制
将.uvprojx、.uvguix、Startup.s、main.c等纳入 Git 管理,便于团队协作与回溯。
写在最后:掌握这条路径,你就掌握了嵌入式的起点
当我们说“学会 keil5 烧录程序 stm32”,其实学的不只是一个操作流程,而是对整个嵌入式开发链条的理解:
- 你知道 CPU 是如何启动的;
- 你明白 Flash 是如何被擦写的;
- 你能看懂调试器与目标之间的握手逻辑;
- 你不再害怕“Cannot access target”这种报错,因为你知道它背后意味着什么。
这条路走通了,后面的 USART、ADC、RTOS、FreeRTOS、LVGL……都将变得水到渠成。
未来也许你会转向 GCC + VSCode + OpenOCD 的开源组合,或是拥抱 STM32CubeIDE 的图形化便利,但Keil + ST-Link + 手动工程构建这一经典组合,依然是检验你是否真正理解底层原理的“试金石”。
🌟 温馨提醒:下次遇到烧录失败,别急着换线换板,先问自己三个问题:
- BOOT0 是不是接地了?
- Flash Algorithm 有没有选对?
- 是不是忘了给目标板供电?
搞清楚这三个,90% 的问题都能解决。
如果你正在学习嵌入式开发,欢迎留言交流你在烧录过程中踩过的坑,我们一起排雷。