开篇
我在b站获取了up主“陈加油嗯”的 STM32F103C8T6 智能小车项目(蓝牙遥控 + 循迹 + 避障三合一),他是用 Keil5 + 标准外设库写的。但我平时的主力编辑器是 VS Code,所以目标很明确:
在 VS Code 里把这个 Keil 工程编译、烧录、跑起来,源代码一行不改。
折腾了半天,搜索了一些教程,最终用 EIDE 插件顺利跑通:导入工程 → GCC 编译 → ST-Link 烧录,全程图形化点击。这篇文章把完整流程和 4 个遇到的坑记录下来,以后任何 Keil 工程想迁移都能照搬。
一、为什么要从 Keil 搬到 VS Code
| 对比项 | Keil5 | VS Code + EIDE |
|---|---|---|
| 编辑器体验 | 编辑器老、代码补全弱 | 现代编辑器,补全/跳转/主题好 |
| 编译器 | ARMCC(Keil 专用) | ARM GCC(开源,通用) |
| 烧录 | 内置 | 支持 ST-Link/J-Link/OpenOCD |
| 跨平台 | 仅 Windows | Windows/Linux/Mac |
| 版本管理 | 弱 | 原生 Git 集成 |
| 学习成本 | 工程文件是黑盒 | 构建过程透明可见 |
标准外设库(SPL)工程的结构非常规整,天然适合迁移:
1 | 工程目录/ |
二、三条路线怎么选
把 Keil 工程搬到 VS Code,我研究后有三条路线:EIDE 插件、手写 CMake、ST 官方扩展。
1. 主路线:EIDE 插件(我选的)
| EIDE 插件 | 手写 CMake | |
|---|---|---|
| 移植工作量 | 零(直接导入 .uvprojx) | 写 CMakeLists + 链接脚本 + 换启动文件 |
| 操作方式 | 图形化按钮 | 命令行 |
| 宏/头文件路径 | 自动从 Keil 工程解析 | 手动照抄 |
| 适合人群 | 想快速跑通 | 想深入理解构建流程 / 做 CI |
学习阶段选 EIDE 最快——它只是编译工具,不影响你读代码理解代码。CMake 方案留作进阶(做 CI、复杂工程时再用)。
2. 为什么不选 ST 官方扩展?
keysking的stm32教程中安装的是stm32Cube插件,为什么不用它,用第三方 EIDE? 关键区别在这里:
| STM32 官方扩展 | EIDE | |
|---|---|---|
| 出身 | ST 官方 | 第三方 |
| 支持的芯片 | 仅 STM32 | 几乎所有单片机 |
| 支持的工程格式 | 仅 CubeMX 生成(.cproject) | Keil(.uvprojx)、CubeMX、ESP-IDF… |
| 支持的库 | 仅 HAL 库 | 标准库(SPL) + HAL 库都行 |
| 编译器 | armclang / GCC | GCC / ARMCC / IAR |
| 导入别人现成的 Keil 工程 | ❌ 不认 | ✅ 一键导入 |
ST 官方扩展是ST 生态的延伸:它的世界只有”CubeMX 生成的 HAL 工程”这一种工作流。而我们的目标是导入别人用 Keil + 标准外设库写的现成工程,官方扩展根本不认这种格式——EIDE 是通用工程管理器,芯片、工程格式、编译器都”来者不拒”。
所以不是官方扩展不好,是它只管自己生态,管不了别人的 Keil 工程。而EIDE 是超集。
三、环境搭建
1. 安装 ARM GCC 编译器
EIDE 编译需要 ARM 交叉编译器(GCC 的 ARM 版本,替代 Keil 的 ARMCC)。
- 下载:ARM 官方 GNU 工具链(搜索 “Arm GNU Toolchain Downloads”),Windows 版选
arm-none-eabi目标 - 安装:一路 Next,安装时勾选 “Add path to environment variable”(以后终端直接敲
arm-none-eabi-gcc) - 安装路径默认在:
C:\Program Files (x86)\Arm GNU Toolchain arm-none-eabi\<版本>- ⚠️ 注意版本目录名是
14.2 rel1(空格),不是14.2.rel1(点)
- ⚠️ 注意版本目录名是
验证安装(新开终端):
1 | arm-none-eabi-gcc --version |
2. 安装 EIDE 插件
VS Code 扩展市场搜 Embedded IDE(cl.eide),或命令行安装:
1 | code --install-extension cl.eide |
EIDE 需要 .NET 运行时(首次启动会自动检测,缺了会提示安装)。
3. 指定编译器路径(关键)
EIDE 默认不知道 GCC 装在哪,在 VS Code 用户设置(settings.json)里配置:
1 | "EIDE.ARM.GCC.InstallDirectory": "C:\\Program Files (x86)\\Arm GNU Toolchain arm-none-eabi\\14.2 rel1", |
四、导入 Keil 工程
第 1 步:VS Code 打开工程目录
VS Code → 文件 → 打开文件夹,选中包含 Project.uvprojx 的那个目录(不是打开 .uvprojx 文件本身,是打开它所在的文件夹)。
💡 先给工程目录起个纯英文名:比如
D:\projects\car\。这一步很重要,坑④会解释为什么——中文路径会导致链接失败,现在养成习惯最省事。
第 2 步:找到 EIDE 面板
安装 EIDE 插件后,左侧活动栏会出现一个新的图标(嵌入式芯片图案,⚠️ 不是资源管理器那个文件图标)。点击它,EIDE 面板就展开了。
第 3 步:导入 Keil 工程
- 在 EIDE 面板顶部找到 “导入工程” 按钮(Import),点击
- 弹出菜单选择 **”Keil”**,再选择 “Keil ARM project (.uvprojx)”
- 这里有两个选项:**”ARM 还是 C51?”**——答案是 ARM。Keil MDK 就是 ARM 版本(Microcontroller Development Kit),我们的 STM32F103 是 Cortex-M3 内核,属于 ARM;C51 是给 8051 单片机用的,选错后面全乱
- 在弹出的文件选择框中,选中工程目录下的
Project.uvprojx,确认
第 4 步:等待自动解析,EIDE 在做”配置搬运”
导入瞬间 EIDE 会只读解析 Project.uvprojx(Keil 工程文件本质是 XML,记录了全部配置),自动生成:
| 从 uvprojx 读出的内容 | EIDE 的处理 |
|---|---|
| 源文件清单(40 个 .c/.s) | 构建列表 |
| 头文件路径(IncludePath) | 编译选项 |
| 宏定义(Defines) | 预处理器定义 |
| 芯片型号(STM32F103C8) | 芯片支持包 |
这个过程只读,不会破坏原 Keil 工程——uvprojx 原封不动,原工程随时还能用 Keil 打开。EIDE 只是生成自己的一套工程配置(.eide/ 目录),两边共存互不干扰。
第 5 步:安装推荐扩展(可选)
导入完成后 VS Code 右下角可能弹窗推荐扩展(来自 dan-c-underwood 等的),直接点安装——ARM 汇编语法高亮、C/C++ 等。
第 6 步:切换编译器为 GCC
导入后 EIDE 默认沿用 Keil 工程的编译器设置 AC5(ARMCC)。注意:即使电脑上装了 Keil5,EIDE 也不知道 ARMCC 装在哪——它需要额外的路径配置(EIDE.ARM.ARMCC5.InstallDirectory 指向 Keil 的 ARM\ARMCC 目录),没配置的话此时点编译会报:
1 | 无法找到编译器 'AC5' 的位置![path]: 'null\bin' |
(null\bin 就是”路径没配置”的痕迹)
我的操作:在 EIDE 面板顶部工具栏找到编译器选择框(此时显示 “AC5”),点击弹出下拉,选择 **”GCC”**(GNU Arm Embedded Toolchain)。切换后 EIDE 会读取我们在第三章配置的 EIDE.ARM.GCC.InstallDirectory 路径,弹出确认框时点确定即可。
另一个选择:如果你想让 EIDE 直接用 Keil 的 ARMCC 编译,也可以在 VS Code 设置里配置 EIDE.ARM.ARMCC5.InstallDirectory 指向 Keil 安装目录。但推荐用 GCC——开源免费不依赖 Keil 安装、命令行通用、构建过程透明,本文后面的坑也都是按 GCC 写的。
判断标准:AC5/AC6 是 Keil 的编译器(ARMCC),GCC 是 ARM 官方工具链。EIDE 下拉框里显示哪个就点哪个,关键是让 EIDE 能找到对应编译器的真实路径。
第 7 步:认识 EIDE 面板
切换完成后,EIDE 面板展开成这样的结构:
1 | 📁 stdperiph (Target 1) |
到这里导入就完成了。接下来点编译按钮(锤子图标),会依次踩到坑①~④——别慌,都是工具链差异的小修补,下面逐个解决。
五、坑 ①:编译报错 “Please select first the target STM32F10x device”
标准外设库的 stm32f10x.h 第 96 行有个设备检查:必须定义芯片型号宏,否则 #error 直接拒绝编译:
1 |
Keil 工程里只有 USE_STDPERIPH_DRIVER 一个宏(uvprojx 里没写型号宏),EIDE 原样搬过来了 → 编译全报错。
解法:EIDE → C/C++ 属性 → 预处理器定义,改为:
1 | USE_STDPERIPH_DRIVER;STM32F10X_MD |
STM32F10X_MD= Medium Density 中容量 = F103C8/CB 系列(HD 是高容量 F103ZE,LD 是低容量 F103C6)- ⚠️ 分号分隔,不能有任何空格,否则报
cannot have whitespace on either side of '=',这里我直接点修改,老是报这个错误,然后我删掉原本的定义,重新添加,就不报错了,很神奇的bug。
这一个宏修好后,后面连带的 TIM4_IRQn、USART1_IRQn 未定义错误也全消失了——它们都是没定义型号宏导致的连锁反应。
六、坑 ②:启动文件汇编语法不兼容
39 个 C 文件全过了,栽在启动文件上:
1 | Error: bad instruction `stack_size EQU 0x00000400' |
原因:Keil 工程里的 startup_stm32f10x_md.s 是 ARMCC 汇编语法(EQU/AREA/DCD/PROC 是 Keil 汇编器的指令),而 EIDE 用的是 GNU 汇编器(arm-none-eabi-as),两者语法不通用。
解法:换成 GNU 语法的启动文件。ST 官方标准外设库里其实自带 GNU 版(RIDE7 工具链版),长这样:
1 | .syntax unified |
从 GitHub 的 STM32F103 GCC 模板仓库(如 0x0E86/STM32F103C8T6)拉一份即可,文件名不变,直接覆盖 Start/startup_stm32f10x_md.s。原文件先备份(改名 .bak),哪天回 Keil 还能还原。
判断启动文件是什么语法:看到
.syntax/.word/.section是 GNU 版;看到EQU/AREA/DCD是 ARMCC 版。
七、坑 ③:老 CMSIS 与 GCC 14 的兼容问题
编译 core_cm3.c 时报汇编错误:
1 | Error: registers may not be the same -- `strexb r0,r0,[r1]' |
原因:2011 年的老版 CMSIS 内联汇编写死了寄存器(ARMCC 的写法),GCC 14 的寄存器分配检查更严格,目标寄存器与源寄存器相同直接报错。
解法:替换为 GCC 兼容版 core_cm3.c/core_cm3.h(同上,模板仓库里有现成的)。新版里 GCC 分支用标准约束模板写法:
1 | __ASM volatile ("strexb %0, %2, [%1]" : "=&r" (result) : "r" (addr), "r" (value)); |
这种编译器差异的问题,stm32f10x.h 等库文件本身一般兼容(内部有 #if defined(__GNUC__) 分支),只有老汇编和 CMSIS 内核文件需要换。
八、坑 ④:中文路径导致链接失败
编译全过,链接报:
1 | ld.exe: cannot open linker script file ...1.STM32F1????...v1.1/...stm32f103c8.lds: Invalid argument |
注意是 Invalid argument(不是 No such file)—— Windows + GCC 的经典编码问题:链接器收到中文路径时编码损坏(????),文件明明存在却打不开。编译能过是因为 EIDE 编译用相对路径,而链接脚本存的是绝对路径,就踩雷了。
解法:工程目录必须全英文。把工程复制一份到纯英文路径(如 D:\stm32project\smartcar\stdperiph\),重新导入即可。
这条经验很重要:嵌入式工程路径永远用纯英文,中文路径在 OpenOCD 烧录、调试器、脚本里还会继续捣乱,趁早搬走。
九、编译 & 烧录
配置完以上四点,点编译,输出:
1 | [ INFO ] start compiling (jobs: 16) ... |
链接时出现的
_close is not implemented and will always fail等 warning 是裸机环境的正常提示(没有文件系统),无视即可。
烧录前把烧录配置从默认的 JLink 改为 ST-Link(构建配置里),第一次用会提示自动下载 STM32CubeProgrammer 烧录工具。接好 ST-Link(SWD 四线:3.3V/SWDIO/SWCLK/GND),点烧录按钮:
1 | STM32CubeProgrammer v2.8.0 |
烧录验证通过,程序跑起来了。
十、总结:迁移 Checklist,可直接照搬
以后任何 Keil 标准库工程迁移,按这个清单走:
1 | □ 1. 装 ARM GCC(勾选加 PATH),settings.json 配 EIDE.ARM.GCC.InstallDirectory |
核心思路:EIDE 帮你自动完成 90% 的配置搬运(源文件、宏、路径都从 uvprojx 解析),剩下 10% 是工具链差异的修补——启动文件语法、CMSIS 版本、编码问题,都是换文件/换路径的事,你的业务代码一行都不用动。
参考资料:
B站视频:再见了,Keil君!我已经爱上了EIDE插件(vscode+嵌入式开发)https://www.bilibili.com/video/BV1XGLozvEJf/?spm_id_from=333.337.search-card.all.click&vd_source=5a111e8d49f70e532d36ddb73be3d0aa
模板仓库:
github.com/0x0E86/STM32F103C8T6(GNU startup + 兼容 CMSIS)