☰
VSCode+Keil Assistant 配置 STM32 补全编译烧录
2026/10/2 16:02:17 网站建设 项目流程

先把结论放前面:如果你现在还在 Keil 里一个字母一个字母地敲 STM32 代码,同时又眼馋 VSCode 那套丝滑的代码补全和跳转,那你大概率的结局是——装了一堆插件、改了半天的c_cpp_properties.json,最后发现连编译按钮都找不到,然后灰溜溜地滚回 Keil。我见过太多人卡在这一步,包括我自己。

这篇东西就干一件事:把 Keil Assistant 插件这条路线彻底讲透,从装软件的顺序、插件配置的每个字段、到代码补全为什么全是红线、再到那些新手一定会踩的编码和路径坑。这篇是写给新手的,但我不打算把关键决策藏起来——每一步为什么这么做,我都会说清楚。看完你应该能做到:在 VSCode 里正常写 STM32 代码,有补全、有跳转、能一键编译、能一键烧录,并且清楚这套方案的天花板在哪。

1. 为什么我最后还是把 STM32 工程搬进了 VSCode

1.1 Keil 的问题不在功能,在手感

Keil MDK 本身没啥可挑的,编译器、调试器、芯片包、寄存器视图一应俱全,工程管理也稳。对一个只写 STM32 标准库或者 HAL 库的人来说,Keil 其实是"够用且省心"的。真正让人难受的是它那套编辑器的手感:

  • 代码补全基本靠猜,函数参数提示时有时无,结构体成员不敲完整点号经常不出来;
  • 跳转到定义经常跳到头文件的声明,而不是源头;
  • 没有多光标、没有正则替换预览、没有 Git 集成面板;
  • 主题和字体方案固定,长时间盯着眼睛累。

这些东西单看都不致命,但一天写八小时,累积起来的效率损失很可观。更关键的是,现代嵌入式项目越来越依赖 Git 做版本管理、依赖脚本做自动化构建,而这些在 Keil 里几乎没法优雅地做。

1.2 Keil Assistant 到底是什么定位

先把这个插件的定位说透,能省掉你后面很多无用功。Keil Assistant 做的事情非常朴素:它把 Keil 的编译和烧录命令,包装成了 VSCode 里的命令。

具体来说,它读取你的.uvprojx工程文件,拿到工程里的文件列表和目标名称,然后在 VSCode 侧边栏生成一个树形结构,让你能点开看文件。当你点"编译"的时候,它在后台调用UV4.exe -b 工程路径 -o 输出日志,相当于帮你敲了一遍 Keil 的命令行。编译日志解析出来,错误和警告显示在 VSCode 的问题面板里,点一下就能跳到出错的行。

所以它的本质是:VSCode 负责编辑体验,Keil 负责编译和烧录。它不接管编译器,不接管调试器,也不修改你的工程文件结构。这个定位决定了它的优点(改动小,老工程直接能用)和缺点(调试还得回 Keil)。

1.3 三条路线的取舍,你得先想明白

配置 STM32 开发环境,市面上主流的有三条路,我做个对照,你先选路线再动手:

路线编译工具链调试方案上手难度适合谁
Keil AssistantKeil ARMCC/ARMCLANG回 Keil 调试低老工程迁移、新手、课程作业
Makefile + arm-none-eabi-gccGCCVSCode + Cortex-Debug中高想彻底脱离 Keil、玩开源工具链
STM32CubeCLT + CMakeGCC/CLANGVSCode + Cortex-Debug中新项目、CubeMX 生成工程

这条分岔路口很容易走错。如果你的工程是从老师、同事那里拿来的 Keil 工程,里面有.uvprojx,那 Keil Assistant 是最省事的,半小时能跑起来。如果你想从零建项目并且要完整调试,那 CMake + Cortex-Debug 更顺。最怕的是你以为 Keil Assistant 能调试——它不能,作者也明确说了不做这块。

所以我选 Keil Assistant 的理由很简单:我的项目是现成的 Keil 工程,有几百个文件、多个目标配置,重写成 CMake 的成本远大于收益。如果你的情况一样,往下看。

2. 装之前先想清楚:这套环境的依赖链条

2.1 软件清单与安装顺序

这一步看着简单,但顺序错了会浪费你一小时。顺序是有讲究的:

  1. 先装 Keil MDK,把芯片包(Device Family Pack)装好,确保能在 Keil 里正常编译出一个点灯工程。Keil 是整个方案的地基,地基没打牢,VSCode 那边再折腾都是白费。
  2. 验证 Keil 命令行可用。打开 CMD,敲"C:\Keil_v5\UV4\UV4.exe" -h,如果弹出一堆参数说明,说明命令行入口是通的。这一步很关键,因为 Keil Assistant 走的就是命令行。
  3. 再装 VSCode。从官网下最新稳定版,Windows 上建议选"添加到 PATH"那个勾。
  4. 最后装插件。插件依赖前面两个都就位,顺序反了它读不到路径。

2.2 Keil 版本和授权,别在这上面卡住

Keil MDK 有两个版本要注意:MDK-Lite 是免费的,但限制编译后代码大小不超过 32KB(准确的说是镜像大小限制),稍微复杂一点的工程加上 HAL 库直接超。MDK-Essential/Professional 是商业版,需要授权。

对新手来说,如果你的工程小于 32KB,Lite 够用。如果超了,Keil 会明确报错告诉你超了多少,不会静默失败,这点还算友好。我建议你先用 Lite 跑通流程,确认这套工作流真的适合你,再考虑授权的事。

另一个坑是Arm Compiler 版本。老工程用的是 AC5(armcc),新工程可能是 AC6(armclang)。这两个编译器的语法接受度不一样,AC6 对代码规范更严格,很多老代码在 AC6 下会报一堆警告甚至错误。你装 Keil 的时候若只勾了一个版本的编译器,打开别人的工程可能会报"compiler not found"。检查方式:Keil 里Project → Manage → Project Items → Folders/Extensions,看编译器路径是否有效。

2.3 VSCode 端最少要装哪几个插件

不要贪多,装得多冲突也多。核心就这几个:

  • Keil Assistant:主角,负责编译烧录。
  • C/C++(微软官方):负责代码补全、跳转、错误提示。这是体验提升的主要来源,没它 Keil Assistant 就只是个编译按钮。
  • Chinese (Simplified) Language Pack:想要中文界面的话装这个,不想要可以跳过。
  • 可选GitLens、EditorConfig、Trailing Spaces:工程规范类的,锦上添花。

这里提醒一句:网上有些老教程推荐装C/C++ Advanced Lint、Browse.vc.db相关的插件,别装。微软的 C/C++ 插件自己那一套 IntelliSense 引擎就够用了,再叠一套会出现"同一个变量两个插件给出不同颜色提示"的诡异现象,排查起来很烦。

3. Keil Assistant 的配置过程:从插件市场到第一个可编译工程

3.1 两个关键设置项:Keil 路径和 UV4.exe

装完插件,第一件事是打开设置,搜索KeilAssistant。你会看到几个关键项:

  • KeilAssistant.MDK.Uv4Path:默认值是C:\Keil_v5\UV4\UV4.exe。
  • KeilAssistant.C51.Uv4Path:如果你只玩 STM32,这条忽略。

你的 Keil 如果不是装在默认路径(比如装在 D 盘),这里必须改。判断方法很简单:打开文件资源管理器,找到UV4.exe,右键复制完整路径,粘进去。路径里的反斜杠在 JSON 设置里要写成双反斜杠\\,或者干脆用正斜杠/也认。

注意:改完设置建议重启一次 VSCode。插件的路径读取有些版本是在激活时做的,不重启可能读的是旧值,会让你怀疑自己是不是改错了地方。

3.2 导入工程:.uvprojx 和 .uvproj 的区别

Keil 的工程文件有两个后缀:老的.uvproj(Keil 4 时代的格式)和新的.uvprojx(XML 格式,Keil 5)。Keil Assistant 两个都支持,但.uvproj是老二进制格式,解析偶尔会出问题,尤其是工程里有中文文件名或者特殊字符的时候。

导入流程是用 VSCode 打开工程所在的文件夹,然后在 Keil Assistant 面板点那个加号图标,选择.uvprojx文件。这时候你会看到面板里出现一个树,展开就是工程组和文件。

这一步最容易出的问题是:面板里空空如也,或者只显示了部分文件。常见原因有:

  • 工程使用了 Keil 的"Groups"分组,而插件只识别某些层级;
  • 工程路径里有中文或者空格(这一点后面单独讲);
  • 工程引用了绝对路径的外部文件,插件解析不到。

遇到这种情况,先在 Keil 里打开这个工程确认能正常编译,再回来看插件。先排除 Keil 自身的问题,再排查插件,这个顺序能省你很多时间。

3.3 一键编译、烧录与快捷键绑定

插件跑通之后,你能用的命令有:

  • Keil Assistant: Build:增量编译。
  • Keil Assistant: Rebuild:全量重编译。
  • Keil Assistant: Download:下载到芯片(需要 Keil 里已经配置好下载器)。
  • Keil Assistant: Open in Keil:直接用 Keil 打开当前工程。

这几个命令默认没有快捷键,得自己绑。打开keybindings.json,加几行:

[ { "key": "ctrl+alt+b", "command": "keil-assistant.build", "when": "editorTextFocus" }, { "key": "ctrl+alt+r", "command": "keil-assistant.rebuild" }, { "key": "ctrl+alt+d", "command": "keil-assistant.download" } ]

注意命令 ID 会随插件版本变化,如果绑了没反应,去命令面板(Ctrl+Shift+P)里搜 "Keil",看实际命令名是什么,再照着改。

编译输出面板里会显示 Keil 的原始日志,包括Program Size: Code=xxxx RO-data=xxxx RW-data=xxxx ZI-data=xxxx这一行。这一行很重要,它告诉你代码占了多少 Flash 和 RAM。我习惯把这段截图存档,改完功能对比一下,能第一时间发现"咦,怎么突然多了 8KB",及时揪出误引入的大数组或者误开的调试打印。

4. 让代码补全真正好用:c_cpp_properties.json 的坑

4.1 为什么默认补全全是红线

导入工程之后,你十有八九会看到满屏的红波浪线,#include "stm32f1xx_hal.h"那里标着"cannot open source file"。这不是你的代码错了,是C/C++ 插件不知道头文件在哪。

要理解这一点得先分清两件事:Keil 的编译和 VSCode 的 IntelliSense 是两套完全独立的系统。Keil 编译时靠.uvprojx里配置的 Include Paths 找头文件;VSCode 的补全靠c_cpp_properties.json里的includePath找头文件。两者互不通信。插件作者也没做自动同步(技术上可以做,但同步逻辑复杂,容易出错,所以没做)。

所以你要做的,就是把 Keil 里的 Include Paths 手动搬到c_cpp_properties.json。

4.2 includePath 和 defines 到底怎么写

在工程根目录建一个.vscode文件夹,里面放c_cpp_properties.json。以 STM32F103 + HAL 库为例:

{ "configurations": [ { "name": "STM32F103", "includePath": [ "${workspaceFolder}/**", "${workspaceFolder}/Core/Inc", "${workspaceFolder}/Drivers/STM32F1xx_HAL_Driver/Inc", "${workspaceFolder}/Drivers/STM32F1xx_HAL_Driver/Inc/Legacy", "${workspaceFolder}/Drivers/CMSIS/Device/ST/STM32F1xx/Include", "${workspaceFolder}/Drivers/CMSIS/Include" ], "defines": [ "USE_HAL_DRIVER", "STM32F103xB" ], "cStandard": "c11", "cppStandard": "c++17", "intelliSenseMode": "gcc-arm", "compilerPath": "" } ], "version": 4 }

几个要点解释一下:

  • ${workspaceFolder}/**表示递归搜索工作区下所有目录。这一条很省事,但工程文件特别多的时候会让 IntelliSense 变慢,如果卡顿可以去掉它,改成精确路径。
  • defines里的STM32F103xB这类宏必须写对。它是 CMSIS 用来选芯片寄存器的,写错了会导致补全出来的寄存器地址都是错的,或者头文件里的条件编译走进错误分支,表现为"明明有这个函数,但补全不提示"。
  • intelliSenseMode选gcc-arm是因为做嵌入式补全时这个模式的解析行为最接近实际。别选msvc-x64,那套是针对 Windows 桌面开发的。

4.3 defines 从哪抄,别靠猜

defines最靠谱的来源是 Keil 的工程配置。打开 Keil,Options for Target → C/C++ → Define,那一栏里用逗号分隔的宏,原样抄到defines数组里,每个宏一个字符串。同理,Include Paths那一栏里的每个路径也抄到includePath。

这个过程很枯燥,但一次性做好,后面基本不用动。我通常会在抄完之后,故意把鼠标悬停在一个 HAL 函数上,看能不能弹出完整的参数说明——能弹出来,说明头文件路径对了;弹出来是undefined或者什么也没有,说明路径还差一条。

4.4 几类补全不出来的典型情况

补全不生效,无非这几种:

  • 头文件确实没加进 includePath。症状是#include那行有波浪线。加路径即可。
  • 芯片包路径没加。CMSIS 的core_cm3.h在芯片包里,不在工程目录里,需要用绝对路径加进来,比如C:/Keil_v5/ARM/PACK/Keil/STM32F1xx_DFP/2.4.1/Drivers/CMSIS/Include。版本号会随更新变化,加的时候去文件夹里确认一下。
  • 宏定义漏了或写错了。症状是头文件能打开,但里面的条件编译块全灰着,函数不提示。
  • IntelliSense 引擎卡死了。按Ctrl+Shift+P,执行C/C++: Reset IntelliSense Database,通常能解决。

提示:修改c_cpp_properties.json保存后,IntelliSense 会重新索引,大工程可能要等半分钟到一分钟。别急着下结论,等右下角的进度条转完再说。

5. 那些第一次配置几乎必然踩到的坑

5.1 中文路径和空格

这是 STM32 开发里最古老、最经典、也最容易被忽视的坑。Keil 命令行对路径中的中文和空格处理得很糟糕,表现为命令行调用直接失败,或者编译到一半报找不到文件。

所以:

  • 工程路径不要有中文。D:\我的项目\STM32\这种结构迟早出事,改成D:\Work\STM32\。
  • 工程路径不要有空格。D:\My Project\也不行。
  • 用户名是中文的,那C:\Users\张三\下的工程也有风险,建议把工程放到 D 盘或 E 盘根目录附近。

我见过一个同学的工程编译一直失败,折腾了一下午,最后发现是文件夹名里有个中文的"、"。换掉立马好了。这种坑不值得你花时间,一开始就避开。

5.2 GBK 编码的注释乱码

Keil 的编辑器默认用 ANSI(中文系统下就是 GBK)保存文件,而 VSCode 默认按 UTF-8 读。结果就是:你写的中文注释在 VSCode 里全变成了乱码方框。

解决方式有两条,我推荐第一条:

方案一:让 VSCode 按 GBK 读。在工作区的.vscode/settings.json里加:

{ "files.encoding": "gb2312", "files.autoGuessEncoding": true }

autoGuessEncoding打开后 VSCode 会尝试自动判断编码,大部分情况能猜对。这个方案的优点是不动工程里的文件,Keil 那边依然正常,风险为零。

方案二:把工程整体转成 UTF-8。这需要在 Keil 里也做配置(加编译选项处理字符集),而且如果是 AC5 编译器,对 UTF-8 的支持并不好,容易出现编译警告。老工程不建议动。

这两种方案的取舍很清楚:只要 Keil 还在参与编译,就别轻易改文件编码。等哪天你彻底切到 GCC 工具链了,再统一转 UTF-8 也不迟。

5.3 芯片包缺失导致的 "Device not found"

现象是:在 Keil 里打开工程,弹窗报找不到目标器件,或者编译时报一堆Unknown device的错误。原因是你没装对应的 Device Family Pack(DFP)。

解决办法是打开 Keil 的 Pack Installer,搜索你的芯片系列,比如STM32F1,找到对应的 DFP 装上。装的时候注意版本,有些老工程依赖特定版本,装最新版反而会报错。Sei 一般建议先装最新版,出问题了再回退。

装完之后,记得回头把c_cpp_properties.json里芯片包的路径也更新成你实际装的版本号,否则补全还是不对。

5.4 编译输出乱码和终端编码

Keil 命令行输出的日志是 GBK 编码的,VSCode 的输出面板默认按 UTF-8 解析,于是你看到的编译错误信息里一片乱码——中文全花了,英文正常。这倒不影响编译本身,但看错误信息很痛苦。

处理办法:在编译输出里,把中文部分忽略掉,看英文的报错行号和错误类型就够了。或者更彻底的办法是给 Keil 的编译加英文输出选项。我个人的做法是直接在.vscode/settings.json里设置终端编码:

{ "terminal.integrated.defaultProfile.windows": "PowerShell", "terminal.integrated.env.windows": { "PYTHONIOENCODING": "utf-8" } }

说实话这一条对 Keil Assistant 的输出面板不一定生效,因为那是插件自己的输出通道,不是集成终端。所以更实用的建议是:关注错误代码和行号,别跟中文较劲。

5.5 工程引用了工程目录外的文件

Keil 允许在工程里添加任意路径的文件。如果这些文件在工程目录之外,VSCode 打开工作区时看不到它们,方案里的"${workspaceFolder}/**"也搜不到,于是补全失效、跳转失效。

我的建议是把工程整理成自包含的结构,所有源文件都在工程目录里。实在不行的,就把那些外部路径一条条加进includePath和工作区的folders配置里。这是个体力活,但是一次性投入。

6. 调试怎么办:Keil Assistant 管不了这一段

6.1 现实做法:写代码在 VSCode,调试回 Keil

先把预期管理好:Keil Assistant 不提供调试功能,它没有实现和 GDB/ULINK 的对接。所以你的日常是这样一个循环:

  1. 在 VSCode 里写代码,享受补全和跳转;
  2. 快捷键编译,看问题面板里的错误;
  3. 需要单步、看寄存器、看变量的时候,切到 Keil;
  4. 调完发现问题在某个文件,切回 VSCode 改。

这个循环听起来笨,但实际上手之后你会发现——写代码的时间远大于调试的时间,把 80% 的时间花在体验好的编辑器上,是划算的。而且 Keil 里已经打开的工程,你切回去直接按烧录就行,不需要重新打开。

插件面板里有个Open in Keil命令,点一下就跳过去,还算方便。

6.2 进阶做法:Cortex-Debug 加 OpenOCD

如果你确实想连调试也一起搬到 VSCode,那就得走另一条路,跟你用什么编辑器没关系,取决于你的编译产物能不能生成 ELF 和调试符号。Keil 编译出来的.axf文件其实就是 ELF 格式,理论上是能被 GDB 读的。

配置大概是:

  1. 装Cortex-Debug插件;
  2. 装 OpenOCD 或者 J-Link 的命令行工具(取决于你手上的下载器);
  3. 写launch.json,指定executable为 Keil 输出的.axf文件,servertype选openocd或者jlink;
  4. 按 F5 启动调试。

这条路能走通,但对新手来说门槛不低,尤其是 OpenOCD 的配置文件选错会导致连不上目标芯片。我的建议是:先用混合方案跑一两个月,等你对工具链足够熟了,再尝试全 VSCode 调试。别一上来就两条腿一起迈,容易摔。

7. 团队协作和长期维护的几点经验

7.1 哪些文件该进 Git,哪些必须忽略

用 VSCode 管工程之后,很自然会想上 Git。这时候.gitignore要写对,不然仓库里全是编译中间产物,几十兆的东西传上去会被同事骂。

针对 Keil 工程,我一般这么写:

# Keil 编译产物 *.o *.d *.crf *.axf *.htm *.lnp *.plg *.dep *.build_log.htm *.map *.lst # Keil 用户界面状态(换机器会重新生成) *.uvguix.* *.uvoptx *.uvopt # VSCode 个人配置 .vscode/ipch/ .vscode/browse.vc.db* # 系统文件 Thumbs.db .DS_Store

这里有争议的是*.uvoptx。它保存了断点位置、窗口布局这些用户状态,一般不入库。但有些团队的工程师习惯把下载器配置也放在这里面,删了之后每个人都要重新配一遍。视团队情况决定,但要在 README 里写清楚,别让人猜。

7.2 换电脑之后的复现清单

这套环境是本地配置,换台机器就得重来一遍。我给自己整理了一份清单,照着做大概 20 分钟能恢复:

步骤操作检查点
1装 Keil MDK + 对应 DFP能编译一个点灯工程
2验证UV4.exe -h命令行可调用有参数输出
3装 VSCode + Keil Assistant + C/C++插件面板出现 Keil 图标
4配置Uv4Path为本机实际路径面板能导入工程
5clone 代码仓库.uvprojx存在
6让同事把c_cpp_properties.json也提交或者自己按 4.2 节重建
7绑定编译烧录快捷键快捷键生效

第 6 步是我踩过的坑:一开始我把c_cpp_properties.json放进了.gitignore,结果团队里每个人都要自己配一遍 includePath,浪费了大量时间。后来改成把它提交进仓库(路径全用${workspaceFolder}相对路径),只有芯片包那条绝对路径需要各自改。凡是能用相对路径的地方,都用相对路径,这是让配置可共享的关键。

8. FreeRTOS 和复杂工程的几点补充

8.1 FreeRTOS 工程的文件组织

移植过 FreeRTOS 的人知道,工程里会多出一堆port.c、heap_4.c、FreeRTOSConfig.h。Keil Assistant 对这类工程的导入一般没问题,但补全方面要注意:

  • FreeRTOSConfig.h通常放在Core/Inc或者专门的Inc目录,确认它被includePath覆盖;
  • portmacro.h在portable/RVDS/ARM_CM3这类目录下,这个目录名跟编译器有关,Keil 用的是 RVDS 版本,GCC 用 GCC 版本。你把工程给别人的时候要说明这一点,不然对方用 GCC 编译会找不到符号;
  • 中断优先级相关的configPRIO_BITS,在FreeRTOSConfig.h里定义,如果和 CMSIS 那边的定义冲突,会有编译警告。

这些不是 Keil Assistant 的问题,是工程本身的组织问题,但配置补全的时候会放大它。我在配一个 F103C8T6 的 FreeRTOS 工程时,就遇到过xTaskCreate补全不出来,原因是FreeRTOS.h的 includePath 没覆盖到,加上就好了。

8.2 多目标工程的索引问题

Keil 工程可以配置多个 Target(比如一个 Debug 目标、一个 Release 目标,宏定义不同)。Keil Assistant 一般显示第一个可用的目标。如果你的补全提示跟实际编译的宏不一致,检查一下当前选的是哪个目标。

这种情况下,我通常会在c_cpp_properties.json里配两组 configurations,用configurationProvider或者干脆手动切换。VSCode 右下角状态栏可以快速切当前配置,改起来不麻烦。

9. 一些散碎但很实用的小技巧

写到这,顺手记几个我日常用得上的:

第一,把 Keil 的输出日志留着。插件输出的日志里包含完整的编译命令行,能看到每个文件用了哪些宏和 include 路径。补全出问题时,对着这个日志逐条比对c_cpp_properties.json,比瞎猜快得多。

第二,善用Ctrl+P。大工程里找文件,用文件名快速跳转比在文件树里翻快十倍。Keil Assistant 的树形面板更多是用来确认工程结构,不是用来找文件的。

第三,给常用头文件建代码片段。比如main函数的框架、GPIO 初始化模板、串口重定向的代码,做成 snippet,Ctrl+Space一敲就出来。新手觉得这是小聪明,等你写过几十个工程就知道这有多省事。

第四,VSCode 设置里打开"editor.formatOnSave": true要谨慎。嵌入式代码里经常有对齐好的宏定义、寄存器位域定义,格式化器一跑全给你打乱,反而不好读。我一般是关掉的,只在需要的时候手动格式化一段。

第五,别在 VSCode 里改工程文件结构。增删源文件、改文件分组这些,还是在 Keil 里做。工程文件是 XML 格式,手动改容易改坏,改坏了 Keil 打不开,插件更读不到。让 Keil 管工程结构,VSCode 只管写代码,这个边界划清楚,能省掉很多麻烦。

最后说说我个人对这套方案的判断。它不完美,调试那一段始终是个缺口,多目标工程也偶尔别扭。但对"手里有一个现成的 Keil 工程、想改善写代码体验"的人来说,它是投入产出比最高的一条路——半天配置,换来之后每一天的舒服。至于要不要继续往前走、切到 CMake 加 Cortex-Debug 那套,我建议你先用这套写两个完整的项目,摸清楚自己到底需要什么,再决定。工具是拿来干活的,折腾工具本身不该成为目的。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询