尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

用VSCode+JLink替代Keil:STM32开发环境搭建与调试全攻略

发布时间:2026/9/27 2:53:43

资讯中心
01
ARTICLE

用VSCode+JLink替代Keil:STM32开发环境搭建与调试全攻略

用VSCode+JLink替代Keil:STM32开发环境搭建与调试全攻略
不知道有多少人和我一样过去几年写STM32固件几乎被Keil MDK拿捏得死死的。工程一复杂代码补全慢到怀疑人生界面还停留在十年前每次函数跳转都要靠键盘上下翻遇到稍微大一点的项目Keil那个老旧编辑器的体验真的是劝退。后来我去折腾VSCode JLink这套组合把编译、烧录、调试全挪到VSCode里试完之后只有一个感觉为什么我没有早点这么干。这篇文章不是什么理论分析而是我踩了一堆坑之后沉淀下来的一套Windows环境下可复现的全流程方案。适合那些已经能跑通Keil工程、但实在受不了Keil编辑体验的开发者也适合刚接触STM32、想一步到位用现代工具链的新手。你不需要提前会配环境变量不需要懂复杂的CMake语法我会从JLink驱动安装、ARM GCC工具链、VSCode插件配置到调试配置文件的每一行都拆开讲清楚尽量让你照着做就能跑起来。关于方案本身我先说一句大实话我不是要你彻底卸载KeilKeil在库文件管理、例程兼容性上依然有它的价值。但日常编码、调试我基本已经不再打开Keil了。VSCode JLink这套组合本质上是把“编辑器”和“编译调试工具链”解耦各用各家最擅长的部分。VSCode负责代码编辑体验GCC负责编译JLink负责烧录和调试各管一摊组合起来却能干翻Keil的日常体验。1. 方案选型为什么用VSCode JLink替代Keil而不是别的组合先聊一聊选型这件事。很多人问为什么不用IAR为什么不用STM32CubeIDE我的回答是IAR跟Keil一样有编辑器老旧的问题而且License管理同样麻烦STM32CubeIDE基于Eclipse功能是全面但启动慢、界面吃内存在普通笔记本上体验一般。VSCode的优势在于轻量、插件生态丰富、补全和跳转快而且完全免费。这一套组合的核心结构是这样的编辑器VSCode负责代码查看、补全、重构、Git集成编译器arm-none-eabi-gcc负责把C代码编译成ARM指令构建系统CMake Ninja负责管理编译规则和依赖关系调试器SEGGER JLink负责连接芯片、下载固件、断点调试调试前端Cortex-Debug插件负责在VSCode里把JLink的各项能力图形化。你可能会想既然要配这么多东西还不如直接用Keil。但实际用下来你会发现这些工具每个只要配好一次之后就是双击打开、秒级启动、流畅编码的体验。而且GCC工具链对C99、C11的支持比Keil的AC5编译器好很多报错信息也更清晰很多在Keil里模棱两可的编译问题在GCC下能直接给出原因。这套组合还有一个隐藏优势跨平台。今天你在Windows上配好一套明天同事拿Mac、Linux一样能跑环境配置和命令行几乎一致。如果你以后做Linux下的嵌入式开发这套技能是完全复用的。这也是我坚持用CMake而不是VSCode自带的C/C插件直接编译的原因。2. 环境搭建从零开始装好工具链2.1 JLink驱动安装别选错版本先说JLink驱动。很多人直接去官网下载最新版装完发现调试连不上经常是因为驱动版本和你的仿真器固件不匹配。SEGGER的驱动会自带固件升级功能但有时候升级到一半断电仿真器就变砖了。所以我建议第一步确认你的JLink是正版还是兼容版。正版用户直接去SEGGER官网下载最新驱动省心兼容版用户建议先问卖家要一个配套驱动版本不要盲目追新。我手头有两家不同方案的兼容JLink有一家最新版驱动下经常出现连接不稳定换回4.90版反而一直很稳。第二步安装驱动时选择安装方式和路径。需要注意驱动安装时有一个“Install USB driver”的选项一定要勾上否则VSCode里的GDB Server虽然能启动但Windows根本识别不到JLink的USB设备。装完后打开设备管理器在“通用串行总线控制器”下应该能看到“J-Link”字样。第三步打开SEGGER自带的J-Link Commander输入usb回车看到能读出芯片内核信息就说明连接正常。这一步是验证驱动是否装好的黄金标准比任何IDE提示都靠谱。2.2 编译工具链安装ARM GCC与你熟悉的Keil编译器有何不同这里要明确一个概念VSCode本身不编译代码它只是个编辑器。真正干活的是arm-none-eabi-gcc。这个工具链是ARM官方的开源交叉编译器你写的C代码通过它编译成STM32能跑的bin/hex文件。去Arm GNU Toolchain官网下载Windows版本找一个“x86_64-arm-none-eabi”或其他对应你系统架构的安装包一路Next安装即可。安装完之后最关键的一步是配置环境变量。安装目录默认在类似C:\Program Files\Arm GNU Toolchain arm-none-eabi\bin的位置把这个路径加到系统的PATH环境变量里不然之后CMake找不到编译器。验证方式同样是命令行大法打开cmd或PowerShell输入arm-none-eabi-gcc --version能打印出版本号就说明一切正常。我记得第一次配的时候因为装了个老的2019版工具链编译一些用C11特性的代码报错换到最新版本后问题全没了。建议直接用网站上的最新稳定版不用为所谓“兼容性”用旧版。2.3 VSCode本身与必要插件把编辑器变成IDEVSCode的安装我就不展开了官网下载就是个exe装完打开推荐勾选“添加到PATH”。这一步容易被忽略没有它很多终端操作会多出不少麻烦。然后重点说插件。我当前在用的插件列表如下C/C微软出的提供智能补全、跳转、语法高亮必装。Cortex-Debug连接JLink实现调试的核心插件必装。CMake Tools让VSCode能识别CMake工程必装。CMake提供CMake语法高亮辅助性。Serial Monitor串口监视器调试时顺手看printf输出用。Chinese Language Pack中文界面包按需安装。装完插件重启一下VSCode然后按CtrlShiftP打开命令面板输入CMake: Select a Kit如果能看到arm-none-eabi-gcc作为工具链选项说明插件和工具链已经打通。这一步如果找不到Kit基本可以确认是环境变量没配好或者VSCode没能获取到你系统PATH里的新内容重启VSCode或系统就能解决。2.4 CMake与Ninja为什么我一直强调用它们我见过不少人在VSCode里直接用C/C插件的“IntelliSense模式”编译STM32说实话那样配置出来只能看代码构建能力很弱。我更推荐用CMake Ninja。CMake负责描述工程Ninja是真正干活的构建器编译速度快配合CMake Tools插件用起来非常顺手。CMake需要从官网下载Windows安装包安装时勾选“Add CMake to the system PATH for all users”。Ninja是一个exe文件下载后丢到任意一个已在PATH中的目录即可。不想手动折腾的后面也可以用CMake Tools插件自动下载Ninja但手动放一次更稳。3. 构建系统用CMake管理STM32工程3.1 最小工程结构一个能编译的STM32项目长什么样如果你从STM32CubeMX生成开发环境CubeMX默认支持CMake输出形式新版CubeMX已经支持生成CMake工程了可以直接生成一个基础的CMake工程模板再用VSCode打开即可。如果你像我一样手头有个老的Keil工程不想从CubeMX重新配置外设那就得自己写CMakeLists。不能“工程既能Keil编译又能GCC编译”的兼容性需要你在原Keil工程的基础上额外加构建系统。但首先我们得梳理一下一个最基本的STM32固件工程需要哪些元素启动文件startup_stm32f103xe.s或类似文件链接脚本STM32F103RETx_FLASH.ld芯片厂商提供的HAL库或LL库源码你自己的工作目录Core/Src、Core/Inc等。这里我不展开讲如何从CubeMX生成因为推荐路线就是让CubeMX帮你生成CMake工程然后在VSCode里打开改代码。自己手写CMakeLists的常见办法是模仿CubeMX生成的那份再按自己需求改。3.2 关键CMakeLists配置逐行解释下面这份是我在STM32F103RET6项目上用的精简版CMakeLists我删掉了很多不必要的分支只保留最核心的“能编译、能烧录、能调试”的逻辑cmake_minimum_required(VERSION 3.16) project(stm32_demo C ASM) set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD_REQUIRED ON) set(TOOLCHAIN_PREFIX arm-none-eabi-) set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) set(LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/STM32F103RETx_FLASH.ld) set(SOURCES Core/Src/main.c Core/Src/gpio.c Core/Src/usart.c Core/Src/stm32f1xx_hal_msp.c Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal.c Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_gpio.c Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_uart.c Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_rcc.c Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_cortex.c startup_stm32f103xe.s ) add_executable(${PROJECT_NAME}.elf ${SOURCES}) target_include_directories(${PROJECT_NAME}.elf PRIVATE Core/Inc Drivers/STM32F1xx_HAL_Driver/Inc Drivers/STM32F1xx_HAL_Driver/Inc/Legacy Drivers/CMSIS/Device/ST/STM32F1xx/Include Drivers/CMSIS/Include ) target_compile_definitions(${PROJECT_NAME}.elf PRIVATE STM32F103xE USE_HAL_DRIVER ) target_compile_options(${PROJECT_NAME}.elf PRIVATE -mcpucortex-m3 -mthumb -Wall -fdata-sections -ffunction-sections -g ) target_link_options(${PROJECT_NAME}.elf PRIVATE -mcpucortex-m3 -mthumb --specsnano.specs -T${LINKER_SCRIPT} -Wl,--gc-sections )里面几个关键点我逐个备注一下CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY这行是为了避免CMake在检测编译器时尝试链接可执行文件交叉编译环境下不加这一行经常会报“找不到main函数”这类误报STM32F103xE和USE_HAL_DRIVER是给工程定义的宏前者决定了寄存器地址映射的容量范围后者决定调用HAL驱动-mcpucortex-m3是因为STM32F103是Cortex-M3内核换到F4就得改成cortex-m4--specsnano.specs是使用精简C库的方式能明显减少固件体积-Wl,--gc-sections配合-ffunction-sections能自动裁剪掉没有被引用的函数对减小Flash占用非常有用。3.3 用CubeMX生成的CMake工程要改哪些地方如果你是CubeMX生成CMake工程打开生成的CMakeLists通常只需要确认几件事编译器Kit是否选对了也就是arm-none-eabi-gcc构建目录选择为buildFlash下载地址是否和芯片匹配如果加了自己写的中间件需要在CubeMX的“Project Manager - Linker Settings”里把路径加进去或者直接手动改CMakeLists。这样保持CubeMX生成的结构以后用CubeMX改完引脚配置再重新生成手写的额外代码只要放在backup逻辑内就不会被覆盖。4. 烧录与调试JLink Cortex-Debug的完整配置这套组合的精华就在调试这一段。Keil的调试窗口看着密密麻麻——寄存器、汇编、内存表全挤在一起VSCode里面则保留了核心信息排版干净得多。4.1 JLink GDBServer是什么先理解调试链路很多人第一次配置Cortex-Debug时看到要填“server path”“device”等配置就懵。我先用一句话解释调试链路JLink是一个硬件仿真器它通过USB连接到你的电脑通过SWD引脚连接到STM32芯片。VSCode里的Cortex-Debug插件本身不懂怎么和STM32通信它需要借助JLink GDBServer作为中介。Cortex-Debug把GDB指令发给JLink GDBServerGDBServer再把这些指令转换成JLink底层的SWD协议操作芯片内部寄存器、读Flash、设置断点。所以要让调试跑起来除了VSCode插件你还得有一个能启动GDBServer的手段。你可以手动打开SEGGER自带的JLinkGDBServer程序也可以让Cortex-Debug插件帮你自动启动。我推荐后者因为自动化程度高不用每次去点外部程序。JLink接口定义我这里也顺手提一下SWD模式只需要4根线SWDIO、SWCLK、GND、VCC或参考电平也可以只接SWDIO、SWCLK、GND比JTAG模式少太多线了我平时调试基本都是SWD四个引脚。接线顺序错了非常容易“连接不上”或者读回全是FF最常见问题就是SWCLK是悬空状态。4.2 Cortex-Debug launch.json配置详解在VSCode里按F5或者点击“运行和调试”按钮然后在.vscode/launch.json里写入下面配置。这个文件控制的是“调试会话如何启动”我把每一行的含义都备注出来{ version: 0.2.0, configurations: [ { cwd: ${workspaceRoot}, name: JLink STM32 Debug, type: cortex-debug, request: launch, servertype: jlink, device: STM32F103RE, interface: swd, executable: ${workspaceRoot}/build/stm32_demo.elf, svdFile: ${workspaceRoot}/STM32F103.svd, runToEntryPoint: main, gdbPath: arm-none-eabi-gdb, serverpath: JLinkGDBServerCL.exe, serverArgs: [], preLaunchTask: build } ] }我来解释几个重点device字段直接决定GDBServer打开后选用哪个型号的Flash算法所以名字要和你的芯片严格一致。比如STM32F103ZET6和STM32F103RET6是不同型号Flash容量不同选错会导致下载卡住或校验失败。executable指向的是CMake生成的elf文件不是bin也不是hex。调试器需要elf里面的符号表信息才能显示函数名、变量名。如果没有elf文件或者路径配错断点是灰的调试功能直接废掉。svdFile是一个可选项但强烈建议加。SVD文件是芯片厂商提供的寄存器描述文件加上之后VSCode的调试窗口里外设寄存器就全有名字了看状态值很直观。preLaunchTask对应tasks.json里的构建任务作用是每次按F5调试前先自动编译一遍最新代码否则你改完代码直接按F5跑的还是旧固件。这一步是新手最容易忽略的坑。4.3 tasks.json配置按F5前自动编译在.vscode/目录下新建tasks.json把CMake构建任务挂载到VSCode的“任务系统”里{ version: 2.0.0, tasks: [ { label: build, type: shell, command: cmake --build build, group: { kind: build, isDefault: true }, problemMatcher: [] } ] }这里的前提是CMake已经先在build目录下完成过初始化配置。如果你刚打开工程需要先在终端里执行cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE你的工具链文件或者如果你用的是CMake Tools插件按CtrlShiftP输入CMake: Configure选择arm-none-eabi-gcc作为Kit插件会自动帮你完成初始化。初始化完之后task里的cmake --build build就可以直接用了。4.4 首次断点调试手把手走一遍配置完成后在main.c的某个位置打一个断点按F5。正常情况下你能看到右下角弹出提示“JLinkGDBServerCL started”然后很快停在断点处。左侧调试栏会出现变量、监视、调用堆栈、断点面板。至此你已经可以用和Keil类似的方式看变量值、单步执行、查看外设寄存器。首次调试如果卡住不动最多的原因是JLink驱动运行时弹了一个升级固件的窗口因为VSCode窗口在后边所以你没看到。去任务栏里点开JLink的弹窗升级完再重新按F5。兼容版JLink如果固件升级失败系统可能死锁需要连同USB设备一起重新拔插一次这个问题我在多个兼容版上都遇到过属于使用仿真器常见的“坑”。5. 实操记录从CubeMX工程到VSCode调试全流程5.1 准备一个能用CubeMX生成的工程介绍完配置我再说一遍我实际走过的完整流程。这里假设你还没用CubeMX生成过工程跟着一起走一遍。到官网下载STM32CubeMX安装时确认Java环境CubeMX新版自带运行时不用自己装Java。然后选择你的芯片型号比如STM32F103RETx。CubeMX本身可以按“芯片型号”搜索并初始化时钟、引脚、外设。我一般只初始化三种东西RCC时钟配置选HSE外部晶振Debug选项选Serial Wire也就是SWD这一项不开的话芯片第一次烧录完成后JLink可能找不到调试口一个UART串口方便调试时输出日志。然后切到Project Manager在Project选项卡设置工程名和路径在Toolchain/IDE下拉菜单里选择CMake。这就生成了一个可以直接用VSCode打开的CMake工程。注意Debug - Serial Wire这个选项非常关键。有些芯片出厂时读保护开启或者之前代码里把SWD引脚复用成GPIO了调试器就会“找不到芯片”。CubeMX里启用Serial Wire后HAL会正确配置SWD引脚避免这种坑。5.2 用VSCode打开工程并完成首次编译生成完成后在VSCode里“文件 - 打开文件夹”选择你的工程目录。如果不是首次配置选择CMake Kit然后执行CMake: Build。首次编译会比较慢因为HAL库的很多源文件都要参与编译。我实测过一个开了大部分外设的F103工程首次全量编译大概30秒到1分钟之后增量编译基本在几秒内。这个速度和Keil的编译体验相比也不算差。如果编译报错先看第一行错误信息不要被一堆红波浪线吓到。最常见的问题是找不到头文件检查CMakeLists里的target_include_directories路径和CubeMX生成的是否一致undefined reference多半是漏加了某个.c文件或者HAL库某个模块没编译进来编译器不支持某条指令确认你的工具链版本确实是最新的。5.3 接线与烧录从JLink到目标板的物理链路编译通过后把JLink和STM32开发板用杜邦线连好。SWD四线接法JLink的SWDIO接目标板的SWDIO/PA13JLink的SWCLK接目标板的SWCLK/PA14JLink的GND接目标板GNDJLink的3.3V或VTref脚接目标板的3.3V用于电平参考。这里有个值得注意的细节JLink的VTref引脚在网络许多原理图上写作TVCC它是用来检测目标板电平的不是给目标板供电的。如果目标板已经通过USB或其他方式供电VTref可以不接但接了也无妨只要电平匹配。很多人的目标板如果单独供电SWDIO/SWCLK的电压不一致也可能导致通讯失败如果你的目标板是3.3V系统但手头JLink的复位电平是5V就需要检查是否兼容。STM32F103绝大多数开发板IO容忍5V但为稳妥还是建议电平一致。接好后用J-Link Commander验证连接输入connect然后根据提示选择设备型号STM32F103RE选择SWD接口接着能看到识别出内核和Flash信息。这一步是通过的说明物理链路没问题了。5.4 在VSCode中把固件烧进去烧录时我建议直接用Cortex-Debug体系下的“flash”操作也可以通过cortex-debug里的“下载和运行”功能它会在启动调试会话前把elf烧录到芯片内部Flash。如果你不想进入调试模式只想烧录可以在CMake构建出elf后用命令行工具来烧录JLink.exe -device STM32F103RE -interface SWD -speed 4000 -CommanderScript flash.jlink其中的flash.jlink文件内容大致是si SWD speed 4000 device STM32F103RE connect r loadfile your_project.elf r go exit不过我更推荐直接在VSCode里按F5进入调试顺便就把烧录做了没必要单独维护一套烧录命令。烧录失败的时候先检查device字段是否和芯片一致再检查SWD接线最后检查芯片是否进入读保护状态。很多时候都是这几件事。6. 我把常见的坑整理成了一张排查速查表折腾这套配置的过程中我碰到了不少让人抓狂的问题。这里直接整理成一个速查表大家按表操作比在网上零散找解决方案高效得多。现象最可能原因排查/解决方法JLink USB设备不识别驱动未安装USB driver部分重装JLink驱动务必勾选Install USB driver设备管理器正常但Commander连不上SWD接错线或芯片SWD引脚被复用检查四线接线按住复位键重新连接GDBServer启动后报“Could not connect”target电压未提供或芯片掉电确认目标板供电正常VTref电压上报正确编译报错找不到头文件CMakeLists include路径缺失对比CubeMX生成路径补齐缺失目录编出来的程序能烧录但没反应工程宏定义不对检查目标芯片宏是否如STM32F103xE确认HAL库已启用断点打不上显示灰色elf路径或符号表信息不匹配确认executable指向当前最新构建的elf打印float变量显示不全GCC默认浮点格式问题加上编译选项-u _printf_float若用newlib nano烧录速度很慢速率设得太低在Commander里把speed调到4000kHz以上但前提是接线不虚首次烧录后JLink连不上读保护未关闭或SWD被禁用CubeMX里启用Serial Wire重新生成用ST-Link先连一次解除保护GDBServer卡住不进入调试弹窗升级固件到任务栏或后台窗口确认JLink弹窗并处理这张表是我自己遇到次数最多的10个问题。你们如果遇到表里没写的也别慌大部分情况下用JLink Commander去连一下看具体回显是哪一步报错定位会更快。7. 个人经验补充几个让调试体验再上台阶的小技巧到这里为止整套VSCode JLink调试环境已经能跑起来了。下面我分享几个让日常使用体验更舒服的细节这些不是必选项但加上了会顺手很多。第一个技巧是给F5调试前的自动构建加上增量判断。如果你工程很大每次按F5都全量编译会很耗时。推荐在任务里用cmake --build build -j并行编译实测8线程下中型工程增量编译基本1秒内完成。第二个技巧是利用Cortex-Debug的“表达式”面板实时查看外设寄存器。比如你想看某个定时器CNT当前值在监视窗口输入TIM2-CNT只要SVD和调试符号没问题这个变量会实时刷新。这在调试电机速度、捕获PWM频率的时候非常爽。第三个技巧是设置graphics: true打开Cortex-Debug的图形化绘图功能。可以在调试过程中把某个变量值随时间的变化可视化成波形简单调PID或者看传感器曲线时相当于白得了一个简易示波器。第四个技巧和代码补全有关。如果不配置C/C插件的IntelliSense路径VSCode的代码补全很可能搜不到HAL库的头文件。解决办法是在.vscode/c_cpp_properties.json里把include路径填好或者干脆让它读取CMake配置{ configurations: [ { name: STM32, includePath: [ ${workspaceFolder}/Core/Inc, ${workspaceFolder}/Drivers/STM32F1xx_HAL_Driver/Inc, ${workspaceFolder}/Drivers/CMSIS/Device/ST/STM32F1xx/Include, ${workspaceFolder}/Drivers/CMSIS/Include ], defines: [ STM32F103xE, USE_HAL_DRIVER ] } ], version: 4 }这里面的宏定义和CMakeLists里的保持一致否则IntelliSense看到的代码分支可能和实际编译的不一致就可能会出现“红色波浪线说未定义但编译能过”的怪现象。8. 回到最初的问题这套组合到底带来了什么变化说回到标题那个问题我现在日常写STM32项目基本不打开Keil了。不是说Keil一无是处而是对我来说VSCode JLink这套组合真正解决了三个痛点编辑体验差、编译速度慢、调试窗口不清晰。如果你也被Keil的编辑器搞得心烦不妨照着这篇配置一次哪怕把VSCode当纯编辑器用也值了。每次按F5直接进调试的感觉真的比Keil那边“编译下个固件再打开调试器”要流畅得多。工具链的搭建本身是有一定门槛的但一旦跑通你就再也不想回去了。我第一次配这套环境时也花了一个晚上反复在GDBServer报错和接线接触不良之间折腾。不过现在再看那些坑基本都能在十分钟内排干净。如果你照着这篇配置也跑通了或者卡在某一步欢迎在评论里把具体报错截图留下来我们一起把使用体验做到最好。毕竟嵌入式开发本来就有够多的芯片问题要面对工具链就别再让人受苦了。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。