Keil/IAR/GCC 三足鼎立:STM32 工程从零搭建全对比
👁 8 阅读 · 2026-08-17 · STM32 工具
在 STM32 开发中,Keil MDK、IAR EWARM 和 GCC(配合 Makefile/CMake)是最主流的三种工具链。它们各有优劣,选择往往取决于团队习惯、调试需求和许可证成本。本文将从零开始,分别演示如何用这三种工具链搭建一个最简单的 STM32 工程(以 STM32F103C8T6 为例),深入对比工程结构、启动文件、链接脚本、编译配置和调试方法,帮助你根据项目特点做出明智选择。
## 引言
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 工程创建
1. 新建项目,选择芯片型号(如 STM32F103C8)。
2. 添加启动文件 `startup_stm32f103xb.s`(Keil 自带或从 ST 库获取)。
3. 添加 `stm32f1xx.h`、`system_stm32f1xx.c` 和 `main.c`。
4. 配置魔术棒(Options for Target):
- Target 标签:设置晶振频率(如 8MHz),勾选 Use MicroLIB(减少代码体积)。
- C/C++ 标签:定义宏 `STM32F10X_MD`,添加头文件路径。
- Debug 标签:选择 ST-Link 或 J-Link。
### 2.2 代码示例
```c
// 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 工程创建
1. 创建新工作区,新建项目,选择芯片型号。
2. 添加启动文件(IAR 版本,如 `startup_stm32f103xb.s`)。
3. 添加源文件,注意 IAR 使用 .icf 链接配置文件,默认会生成,但可自定义。
4. 配置 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)
```c
/* 内存布局 */
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 核心规则
```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 工程,并做出明智的工具选择。