引言
STM32 开发工具链的选择直接影响开发效率、代码可移植性和调试体验。Keil 和 IAR 是商业 IDE,开箱即用;GCC 则是开源免费,常配合 Makefile 或 CMake 使用。本文不讨论图形化配置工具(如 STM32CubeMX),而是聚焦于纯手工搭建,以揭示每种工具链的底层机制。
1. 工程文件组成
一个 STM32 裸机工程通常包含以下文件:
- 启动文件(startup_xxx.s):设置堆栈、中断向量表、调用 SystemInit 和 main。
- 系统初始化(system_stm32f1xx.c):配置时钟。
- 外设寄存器定义(stm32f1xx.h):芯片头文件。
- 主程序(main.c):用户代码。
- 链接脚本(仅 GCC 需要,.ld 文件)或分散加载文件(IAR 的 .icf,Keil 的 .sct)。
2. Keil MDK 搭建
2.1 工程创建
- 新建项目,选择芯片型号(如 STM32F103C8)。
- 添加启动文件
startup_stm32f103xb.s(Keil 自带或从 ST 库获取)。 - 添加
stm32f1xx.h、system_stm32f1xx.c和main.c。 - 配置魔术棒(Options for Target):
- Target 标签:设置晶振频率(如 8MHz),勾选 Use MicroLIB(减少代码体积)。
- C/C++ 标签:定义宏
STM32F10X_MD,添加头文件路径。 - Debug 标签:选择 ST-Link 或 J-Link。
2.2 代码示例
// main.c
#include "stm32f1xx.h"
void delay(void) {
for (int i = 0; i < 1000000; i++);
}
int main(void) {
RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
GPIOC->CRH &= ~(0xF << 20);
GPIOC->CRH |= (0x2 << 20); // PC13 推挽输出
while (1) {
GPIOC->ODR ^= (1 << 13);
delay();
}
}
2.3 编译与调试
点击 Build 即可生成 .axf 文件。Keil 内置调试器,可直接下载并单步调试,支持寄存器窗口和实时变量查看。
3. IAR EWARM 搭建
3.1 工程创建
- 创建新工作区,新建项目,选择芯片型号。
- 添加启动文件(IAR 版本,如
startup_stm32f103xb.s)。 - 添加源文件,注意 IAR 使用 .icf 链接配置文件,默认会生成,但可自定义。
- 配置 Project Options:
- General Options → Target:选择器件。
- C/C++ Compiler → Preprocessor:定义
STM32F10X_MD,添加 include 路径。 - Linker → Config:勾选 Override default,选择 .icf 文件(如
stm32f103xb_flash.icf)。 - Debugger:选择 ST-Link 或 J-Link。
3.2 代码示例
与 Keil 相同,但注意 IAR 对语法检查更严格,例如 #include 路径区分大小写。
3.3 编译与调试
IAR 的编译器优化选项丰富(如 High Speed、Balanced),生成的代码效率高。调试器支持代码覆盖率分析,但界面较复杂。
4. GCC + Makefile 搭建
4.1 工具链安装
在 Linux 或 Windows(MSYS2/WSL)下安装 arm-none-eabi-gcc、make 和 openocd。
4.2 工程结构
project/
├── src/
│ ├── main.c
│ └── system_stm32f1xx.c
├── inc/
│ └── stm32f1xx.h
├── startup/
│ └── startup_stm32f103xb.s
├── linker/
│ └── stm32f103xb_flash.ld
└── Makefile
4.3 链接脚本示例(stm32f103xb_flash.ld)
/* 内存布局 */
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 64K
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
}
_estack = 0x20005000; /* 栈顶地址 */
SECTIONS
{
.isr_vector : {
KEEP(*(.isr_vector))
} > FLASH
.text : { *(.text*) } > FLASH
.data : { *(.data*) } > RAM AT> FLASH
.bss : { *(.bss*) } > RAM
}
4.4 Makefile 核心规则
CROSS_COMPILE = arm-none-eabi-
CC = $(CROSS_COMPILE)gcc
OBJCOPY = $(CROSS_COMPILE)objcopy
CFLAGS = -mcpu=cortex-m3 -mthumb -Wall -O2 -DSTM32F10X_MD -Iinc
LDFLAGS = -Tlinker/stm32f103xb_flash.ld -nostdlib
OBJS = src/main.o src/system_stm32f1xx.o startup/startup_stm32f103xb.o
all: firmware.elf firmware.bin
firmware.elf: $(OBJS)
$(CC) $(LDFLAGS) -o $@ $^
firmware.bin: firmware.elf
$(OBJCOPY) -O binary $< $@
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
%.o: %.s
$(CC) $(CFLAGS) -c -o $@ $<
clean:
rm -f *.o src/*.o startup/*.o firmware.*
4.5 编译与烧录
运行 make 生成 .bin 文件,然后用 openocd -f interface/stlink.cfg -f target/stm32f1x.cfg -c "program firmware.bin 0x08000000 verify reset exit" 烧录。调试可使用 GDB 配合 OpenOCD。
5. 对比总结
| 特性 | Keil MDK | IAR EWARM | GCC + Makefile | |------|----------|-----------|----------------| | 许可证 | 商业(免费版有限制) | 商业(昂贵) | 开源免费 | | 易用性 | 高,适合新手 | 中,学习曲线陡 | 低,需熟悉命令行 | | 代码密度 | 良好 | 优秀(优化强) | 良好(依赖优化选项) | | 调试体验 | 优秀,集成度高 | 优秀,支持高级分析 | 一般,需配置 GDB | | 跨平台 | Windows | Windows/Linux | 全平台 | | 可移植性 | 低(工程文件私有) | 低 | 高(标准工具链) |
6. 选型建议
- 快速原型/学习:选择 Keil,上手快,资料多。
- 商业产品/追求极致性能:IAR 的优化能减小 Flash 占用,适合量产。
- 开源项目/CI/CD:GCC 配合 CMake 更易集成到自动化流程。
注意事项
- 启动文件必须与芯片型号匹配,否则中断向量表错误。
- 链接脚本中的 RAM 大小不能超过芯片实际值,否则运行时崩溃。
- 使用 GCC 时,需在启动文件中正确设置
_estack符号,否则栈溢出。 - 三种工具链的
__attribute__语法略有差异,跨平台代码需用宏封装。
结语
无论选择哪种工具链,理解其背后的编译、链接和调试原理才是关键。建议至少掌握一种商业 IDE 和一种开源方案,以便在不同项目中灵活切换。希望本文能帮助你搭建出第一个 STM32 工程,并做出明智的工具选择。