04 - 编译与烧录
本章目标:掌握 STM32F103C8T6 项目的编译流程和固件烧录方法,能够独立完成从源代码到硬件运行的完整过程。
目录
构建系统介绍
什么是 CMake?
CMake 是一个跨平台的构建系统生成器。它不直接编译代码,而是生成平台特定的构建文件(如 Makefile),然后由构建工具(如 make)执行实际的编译过程。
为什么选择 CMake?
| 优势 | 说明 |
|---|---|
| 跨平台 | 支持 Linux、Windows、macOS |
| 可扩展 | 易于添加新源文件和库 |
| 依赖管理 | 自动处理文件依赖关系 |
| 增量编译 | 只重新编译修改过的文件 |
| 广泛支持 | 主流 IDE 和 CI/CD 系统都支持 |
项目构建配置
本项目的 CMakeLists.txt 配置概览:
# 最低版本要求
cmake_minimum_required(VERSION 3.16)
# 设置交叉编译环境
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR ARM)
# 指定编译器
set(CMAKE_C_COMPILER arm-none-eabi-gcc)
set(CMAKE_ASM_COMPILER arm-none-eabi-gcc)
# 项目定义
project(STM32F1 VERSION 0.0.1 LANGUAGES C ASM)
# 编译选项
add_compile_options(
-mcpu=cortex-m3 # 目标处理器
-mthumb # Thumb 指令集
-O2 # 优化级别
-Wall -Wextra # 警告选项
-ffunction-sections # 函数分段
-fdata-sections # 数据分段
-DUSE_HAL_DRIVER # 启用 HAL 库
-DSTM32F103xB # 芯片型号
)
# 链接选项
target_link_options(STM32F1.elf PRIVATE
-mcpu=cortex-m3
-mthumb
-flto # 链接时优化
-T...FLASH.ld # 链接脚本
-nostartfiles
-specs=nano.specs # 精简 C 库
-specs=nosys.specs # 无系统调用
-Wl,--gc-sections # 垃圾回收未使用段
-Wl,-Map=STM32F1.map # 生成映射文件
)构建目标
| 目标 | 命令 | 说明 |
|---|---|---|
| 默认目标 | make | 编译生成 .elf 和 .bin 文件 |
| 烧录 | make flash | 通过 OpenOCD 烧录固件 |
| 擦除 | make erase | 擦除芯片 Flash |
编译步骤详解
步骤概览
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 创建 build │ -> │ cmake 配置 │ -> │ make 编译 │ -> │ 输出文件 │
│ 目录 │ │ 项目 │ │ 项目 │ │ .elf/.bin │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘步骤 1:进入项目目录
:: 进入模板项目目录
cd C:\path\to\ST-Forge\project\0_template步骤 2:创建构建目录
:: 创建 build 目录(用于存放编译产物)
mkdir build
:: 进入 build 目录
cd build提示:使用独立的 build 目录可以保持源代码目录整洁,便于清理编译产物。
步骤 3:运行 CMake 配置
重要:Windows 上必须指定 CMake 生成器。始终使用
cmake -G "MinGW Makefiles" ..。省略-G会导致 CMake 使用 Visual Studio 生成器,编译会失败。
:: 配置项目(生成 MinGW Makefile)
cmake -G "MinGW Makefiles" ..预期输出:
-- The C compiler identification is GNU 10.3.1
-- The ASM compiler identification is GNU 10.3.1
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: arm-none-eabi-gcc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting ASM compile features
-- Detecting ASM compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: C:/path/to/ST-Forge/project/0_template/build配置过程说明:
| 阶段 | 说明 |
|---|---|
| 编译器检测 | CMake 检测 arm-none-eabi-gcc 编译器 |
| 特性探测 | 确定编译器支持的语言特性 |
| 配置生成 | 生成 Makefile 和其他构建文件 |
步骤 4:执行编译
:: 编译项目
make提示:如果
make命令不可用,请尝试mingw32-make。
预期输出:
[ 5%] Building C object CMakeFiles/STM32F1.elf.dir/main.c.obj
[ 11%] Building C object CMakeFiles/STM32F1.elf.dir/system.c.obj
[ 17%] Building C object CMakeFiles/STM32F1.elf.dir/__/third_party/STM32CubeF1/Drivers/CMSIS/Device/ST/STM32F1xx/Source/Templates/system_stm32f1xx.c.obj
[ 23%] Building ASM object CMakeFiles/STM32F1.elf.dir/__/third_party/STM32CubeF1/Drivers/CMSIS/Device/ST/STM32F1xx/Source/Templates/gcc/startup_stm32f103xb.s.obj
[ 29%] Building C object CMakeFiles/STM32F1.elf.dir/__/third_party/STM32CubeF1/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal.c.obj
...
[ 88%] Building C object CMakeFiles/STM32F1.elf.dir/__/third_party/STM32CubeF1/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_uart.c.obj
[ 94%] Linking C executable STM32F1.elf
Generating STM32F1.bin
text data bss dec hex filename
1234 108 1024 2366 93e STM32F1.elf
[100%] Built target STM32F1.elf步骤 5:验证编译结果
:: 检查生成的文件
dir STM32F1.*预期输出:
2026/04/15 10:00 12,288 STM32F1.bin
2026/04/15 10:00 46,080 STM32F1.elf
2026/04/15 10:00 23,552 STM32F1.map完整编译流程(一键执行)
:: 进入项目目录
cd C:\path\to\ST-Forge\project\0_template
:: 清理(可选)
rmdir /s /q build
:: 创建 build 目录,进入,配置并编译
mkdir build && cd build && cmake -G "MinGW Makefiles" .. && make输出文件说明
编译完成后,build 目录中会生成以下文件:
文件类型详解
| 文件 | 格式 | 大小 | 用途 |
|---|---|---|---|
| STM32F1.elf | ELF | 较大 | 调试符号、反汇编、GDB 调试 |
| STM32F1.bin | Binary | 较小 | 直接烧录到 Flash 的二进制文件 |
| STM32F1.map | 文本 | 中等 | 内存映射、符号地址、段分布 |
ELF 文件 (.elf)
ELF (Executable and Linkable Format) 是包含调试信息的可执行文件格式。
特点:
- 包含完整的符号表和调试信息
- 包含段信息(代码段、数据段、BSS 段等)
- 用于 GDB 调试和反汇编分析
查看 ELF 信息:
:: 查看文件头信息
arm-none-eabi-readelf -h STM32F1.elf
:: 查看段信息
arm-none-eabi-readelf -S STM32F1.elf
:: 查看符号表
arm-none-eabi-nm STM32F1.elf
:: 反汇编
arm-none-eabi-objdump -d STM32F1.elf > disassembly.txtBinary 文件 (.bin)
Binary 文件 是纯二进制格式,直接对应 Flash 中的原始数据。
特点:
- 不包含任何元数据或调试信息
- 文件大小等于实际占用的 Flash 空间
- 直接用于烧录到芯片
生成方式(由 CMakeLists.txt 自动执行):
:: 从 ELF 生成 BIN
arm-none-eabi-objcopy -O binary STM32F1.elf STM32F1.binMap 文件 (.map)
Map 文件 记录了链接过程中的内存布局信息。
内容包含:
- 所有符号的内存地址
- 各段(section)的大小和位置
- 函数和变量的地址映射
- 内存使用统计
查看 Map 文件:
:: 在 Map 文件中搜索内存配置信息
findstr "Memory Configuration" STM32F1.map
:: 查看特定符号地址
findstr "main" STM32F1.map代码大小分析
:: 查看各段大小
arm-none-eabi-size --format=berkeley STM32F1.elf输出解读:
text data bss dec hex filename
1234 108 1024 2366 93e STM32F1.elf| 段 | 说明 | 存储位置 |
|---|---|---|
| text | 代码段(只读) | Flash |
| data | 已初始化数据段 | Flash(初始值)+ RAM(运行时) |
| bss | 未初始化数据段 | RAM |
| dec | 十进制总大小 | - |
Flash 占用 = text + data RAM 占用 = data + bss
烧录步骤详解
硬件连接
在烧录之前,请确保 ST-Link 与 Blue Pill 正确连接:
ST-Link V2 Blue Pill (STM32F103C8T6)
┌─────────┐ ┌──────────────┐
│ SWDIO │ ─────── │ SWDIO (PA13) │
│ SWCLK │ ─────── │ SWCLK (PA14) │
│ GND │ ─────── │ GND │
│ 3.3V │ ─────── │ 3.3V (可选) │
└─────────┘ └──────────────┘注意:
- 3.3V 引脚仅在开发板未通过 USB 供电时连接
- 确保 Blue Pill 的 BOOT0 跳线设置为 0(正常启动模式)
USB 权限
Windows 上无需手动设置 USB 权限。ST-Link 驱动(STSW-LINK009)会处理设备访问。如果烧录失败出现"未找到设备",请通过设备管理器验证驱动安装。
OpenOCD 配置
本项目使用 OpenOCD 作为烧录工具,配置文件位于 CMakeLists.txt:
# 烧录配置
add_custom_target(flash
COMMAND openocd
-f interface/stlink.cfg # ST-Link 接口配置
-f target/stm32f1x.cfg # STM32F1 目标配置
-c "program STM32F1.bin verify reset exit 0x08000000"
DEPENDS STM32F1.elf
COMMENT "Flashing STM32F1.bin via OpenOCD"
)配置说明:
| 参数 | 说明 |
|---|---|
-f interface/stlink.cfg | 使用 ST-Link 调试器 |
-f target/stm32f1x.cfg | 目标芯片为 STM32F1 系列 |
program ... verify | 烧录并验证 |
reset exit | 烧录后复位并退出 |
0x08000000 | Flash 起始地址 |
烧录步骤
步骤 1:确认 ST-Link 已被识别
方法一:通过设备管理器
- 按
Win + X,选择"设备管理器" - 展开"通用串行总线设备"或"STMicroelectronics"
- 查找类似 "STLink Virtual COM Port" 或 "STMicroelectronics STLink dongle" 的条目
方法二:通过 PowerShell
# 检查 ST-Link 设备
Get-PnpDevice | Where-Object { $_.FriendlyName -like "*ST-LINK*" }预期应看到状态为 OK 的 ST-Link 设备。
步骤 2:执行烧录
:: 在 build 目录中执行
make flash预期输出:
Open On-Chip Debugger 0.10.0
Licensed under GNU GPL v2
...
Info : clock speed 1000 kHz
Info : STLINK V2J14S0 (API v2) VID:PID 0483:3748
Info : Target voltage: 3.2V
Info : stm32f1x.cpu: hardware has 6 breakpoints, 4 watchpoints
Info : starting gdb server for stm32f1x.cpu on 3333
...
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x08000134
** Programming Started **
** Programming Finished **
** Verify Started **
** Verified OK **步骤 3:验证烧录结果
烧录成功后,开发板会自动复位运行程序。观察开发板上的 LED 或串口输出验证程序是否正常运行。
擦除芯片
如需完全擦除芯片 Flash:
:: 在 build 目录中执行
make erase预期输出:
Open On-Chip Debugger 0.10.0
...
Info : stm32f1x.cpu: hardware has 6 breakpoints, 4 watchpoints
target halted due to debug-request
stm32f1x mass erase complete手动烧录(不使用 make)
如果需要手动执行烧录命令,注意在 Windows 上 OpenOCD 可能需要使用完整路径:
:: 手动烧录(如果 openocd 已加入 PATH,可直接使用)
openocd -f interface/stlink.cfg -f target/stm32f1x.cfg -c "program STM32F1.bin verify reset exit 0x08000000"
:: 如果 openocd 未加入 PATH,使用完整路径
C:\Tools\openocd\bin\openocd.exe -f interface/stlink.cfg -f target/stm32f1x.cfg -c "program STM32F1.bin verify reset exit 0x08000000"
:: 手动擦除
openocd -f interface/stlink.cfg -f target/stm32f1x.cfg -c "init; halt; stm32f1x mass_erase 0; exit"常见问题排查
问题 1:ST-Link 未识别
症状:
Error: libusb_open() failed with LIBUSB_ERROR_ACCESS
Error: no device found原因分析:
- ST-Link 驱动未安装
- 硬件连接问题
- USB 线缆仅支持充电(不支持数据传输)
解决方案:
检查设备管理器
按
Win + X,选择"设备管理器",查看是否出现带黄色感叹号的未知设备或 ST-Link 设备。安装 ST-Link 驱动(STSW-LINK009)
从 ST 官网下载并安装 STSW-LINK009 驱动程序。安装完成后重新插拔 ST-Link。
使用 Zadig 替代驱动(备选方案)
如果安装 ST 官方驱动后仍无法识别:
- 下载 Zadig
- 在设备列表中找到 ST-Link
- 将驱动替换为 WinUSB 或 libusb-win32
- 替换后重新尝试烧录
问题 2:CMake 生成器错误
症状:
CMake Error: Could not create named generator Visual Studio或生成的项目文件无法用 make 编译。
原因分析:
- 未指定
-G "MinGW Makefiles"参数,CMake 默认选择了 Visual Studio 生成器
解决方案:
:: 必须始终指定 MinGW 生成器
cmake -G "MinGW Makefiles" ..
:: 如果 build 目录中已有错误的缓存,先清理
rmdir /s /q build
mkdir build && cd build
cmake -G "MinGW Makefiles" ..问题 3:编译器找不到
症状:
CMake Error: CMAKE_C_COMPILER not found
'arm-none-eabi-gcc' is not recognized as an internal or external command原因分析:
- ARM 工具链未安装
- 工具链未添加到系统 PATH
解决方案:
- 检查编译器是否在 PATH 中
where arm-none-eabi-gcc如果未找到,配置 PATH 环境变量
- 右键"此电脑" > "属性" > "高级系统设置" > "环境变量"
- 在"系统变量"中找到
Path,点击"编辑" - 添加 ARM 工具链的
bin目录路径,例如:C:\Program Files (x86)\GNU Tools Arm Embedded\10.3-2021.10\bin - 点击"确定"保存,重新打开 CMD 窗口使更改生效
验证安装
arm-none-eabi-gcc --version问题 4:链接错误
症状:
undefined reference to `main'
cannot find -lc原因分析:
- 缺少 main 函数
- 链接脚本配置错误
- 库文件缺失
解决方案:
:: 1. 确保 main.c 中有 main 函数
findstr "int main" main.c
:: 2. 检查链接脚本是否存在
dir STM32F103C8TX_FLASH.ld
:: 3. 清理并重新编译
rmdir /s /q build
mkdir build && cd build && cmake -G "MinGW Makefiles" .. && make问题 5:找不到头文件
症状:
fatal error: stm32f1xx_hal.h: No such file or directory原因分析:
- third_party 子模块未初始化
- 头文件路径配置错误
解决方案:
:: 初始化并更新子模块
cd C:\path\to\ST-Forge
git submodule update --init --recursive
:: 检查 HAL 库是否存在
dir third_party\STM32CubeF1\Drivers\STM32F1xx_HAL_Driver\Inc\
:: 重新配置并编译
cd project\0_template
rmdir /s /q build
mkdir build && cd build && cmake -G "MinGW Makefiles" .. && make问题 6:烧录失败 - 目标未响应
症状:
Error: target not halted
Error: flash programming failed原因分析:
- 芯片处于低功耗模式
- SWD 引脚被占用
- 芯片损坏
解决方案:
:: 1. 尝试连接时复位
openocd -f interface/stlink.cfg -f target/stm32f1x.cfg -c "init; reset halt; flash write_image erase STM32F1.bin 0x08000000; verify_image STM32F1.bin 0x08000000; reset run; shutdown"- 检查 BOOT0 跳线位置,确保 BOOT0 = 0(连接到 GND)
- 尝试降低 SWD 时钟速度,在 OpenOCD 配置中添加:
adapter speed 1000
问题 7:CMake 版本过低
症状:
CMake Error at CMakeLists.txt:1 (cmake_minimum_required):
CMake 3.16 or higher is required.解决方案:
- 检查当前 CMake 版本
cmake --version下载最新版本
前往 cmake.org 下载最新版 CMake 安装程序(
.msi文件),安装时勾选"Add CMake to the system PATH for all users"。
问题 8:make 命令失败
症状:
make: *** No targets specified and no makefile found. Stop.或
'make' is not recognized as an internal or external command原因分析:
- 未在 build 目录中执行
- 未运行 cmake 配置
- make 未加入 PATH
解决方案:
:: 1. 检查 make 是否可用
where make
:: 如果 make 找不到,尝试使用 mingw32-make
where mingw32-make
:: 2. 确保在 build 目录中
cd C:\path\to\ST-Forge\project\0_template\build
:: 3. 如果 build 目录不存在,创建并配置
mkdir build && cd build && cmake -G "MinGW Makefiles" ..
:: 4. 然后编译(根据上一步检测结果选择 make 或 mingw32-make)
make
:: 或
mingw32-make进阶技巧
增量编译
CMake 支持增量编译,只重新编译修改过的文件:
:: 修改源文件后,只需执行
makeCMake 会自动检测修改并只编译必要的文件。
清理编译产物
:: 清理所有编译产物
make clean
:: 完全清理(包括 CMake 缓存)
rmdir /s /q build查看详细编译信息
:: 显示完整编译命令
make VERBOSE=1并行编译
:: 使用多核并行编译(指定线程数)
make -j4
:: 自动使用所有 CPU 核心(CMD)
make -j%NUMBER_OF_PROCESSORS%查看编译数据库
:: CMake 生成的 compile_commands.json 可用于 IDE 和静态分析工具
type build\compile_commands.json调试构建
:: 查看 CMake 配置信息
cmake --system-information
:: 查看编译器标志
make VERBOSE=1自定义编译选项
如需修改优化级别或添加自定义标志,编辑 CMakeLists.txt:
# 修改优化级别
add_compile_options(-O0) # 无优化(调试用)
add_compile_options(-O1) # 基本优化
add_compile_options(-O2) # 标准优化(默认)
add_compile_options(-O3) # 最大优化
add_compile_options(-Os) # 优化大小
# 添加调试符号
add_compile_options(-g)
# 添加自定义定义
add_compile_options(-DDEBUG)
add_compile_options(-DMY_DEFINE=123)编译流程总结
┌─────────────────────────────────────────────────────────────────────────┐
│ 编译流程完整图 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ 源文件 (.c, .s) │
│ │ │
│ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 预处理 │ -> │ 编译 │ -> │ 汇编 │ │
│ │ (cpp) │ │ (gcc) │ │ (as) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ 预处理文件 (.i) 汇编文件 (.s) 目标文件 (.o) │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ 链接 │ │
│ │ (ld) │ │
│ └─────────────┘ │
│ │ │
│ ▼ │
│ ELF 文件 (.elf) │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ 转换 │ │
│ │ (objcopy) │ │
│ └─────────────┘ │
│ │ │
│ ▼ │
│ BIN 文件 (.bin) │
│ │
└─────────────────────────────────────────────────────────────────────────┘快速参考
常用命令速查
| 操作 | 命令 |
|---|---|
| 配置项目 | cd build && cmake -G "MinGW Makefiles" .. |
| 编译项目 | make |
| 清理编译产物 | make clean |
| 完全清理 | rmdir /s /q build |
| 烧录固件 | make flash |
| 擦除芯片 | make erase |
| 查看文件大小 | arm-none-eabi-size STM32F1.elf |
| 查看符号表 | arm-none-eabi-nm STM32F1.elf |
| 反汇编 | arm-none-eabi-objdump -d STM32F1.elf |
文件位置
| 文件 | 位置 |
|---|---|
| 源代码 | project\0_template\*.c |
| 构建配置 | project\0_template\CMakeLists.txt |
| 链接脚本 | project\0_template\STM32F103C8TX_FLASH.ld |
| 编译产物 | project\0_template\build\ |
下一步
恭喜您完成编译与烧录的学习!接下来建议:
- 实践调试:继续阅读 05_debugging 学习 GDB 调试
- 深入理解:阅读 03_code_walkthrough 理解代码逻辑
- 修改代码:尝试修改 main.c 并重新编译烧录
- 添加功能:尝试添加新的源文件并更新 CMakeLists.txt