## 引言 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 工程,并做出明智的工具选择。