STM32使用CMake+VSCode实现全平台开发
本文章撰写环境为Archlinux和STLinker调试器,Windows版本的配置理论上一致,只需要在VSC里面手动选择STM32CubeClt和内部工具链的路径即可(实测)。DAPLink和JLink等SWD调试器也可以使用,但需要自行修改配置文件(本人推荐STLinkerV3 MINIE,价格实惠且性能卓越)
STM32使用CMake+VSCode实现全平台开发
Tips:本文章撰写环境为Archlinux和STLinker调试器,Windows版本的配置理论上一致,只需要在VSC里面手动选择STM32CubeClt和内部工具链的路径即可(实测)。DAPLink和JLink等SWD调试器也可以使用,但需要自行修改配置文件(本人推荐STLinkerV3 MINIE,价格实惠且性能卓越)
1. 背景
众所周知,自固件库停止维护和CubeMX盛行以来,STM32开发主要依赖几种IDE:
- Keil MDK - 最广为人知,99%的嵌入式初学者首选
- IAR - 商业工具链,功能强大但价格昂贵
- STM32CubeIDE - ST官方基于Eclipse开发的IDE
然而,Keil MDK由于ARM公司更新缓慢(半年到一年才修个小版本)以及开发方向的摆烂(Keil6文档不全,功能难用),已成为跟不上时代步伐的老古董。其中的痛点包括:
- 编码乱码问题严重
- 智能提示卡顿(你先别管智能不智能吧,打错一个字母就卡IDE十多秒也太逆天了)
- 与现代IDE相比功能落后
虽然Keil的AC5和AC6编译器仍然性能不错,配置简单,但ARM"贴心"地只允许你使用随Keil捆绑的编译器,单独下载则需要商业License,这样的做法也就杜绝了Linux的配置使用可能,因为Keil以及配套的编译器只提供了Windows的版本。STM32CubeIDE同样存在智能提示不佳、配置繁琐、缺乏现代化体验等问题
最新悲报,亲测最新版本的Keil 5.42a破解License失效了,编译大小还是受限,必须降级回去使用,但是没有License的情况下ARM不提供在官网的旧版本下载,只能找第三方下载站,又要和下崽站斗智斗勇惹。。。。
2. 解决方案
那么,能否使用更现代化的VSCode来进行STM32开发呢?答案是肯定的!
2.1 历史尝试
-
Keil6 VSCode扩展:ARM曾尝试将Keil做成VSCode插件系列,但实用性差,配置文档至今仍是TODO状态。
-
EIDE插件:通过逆向KEIL、IAR、Eclipse的工程配置文件来创建VSCode工作空间。
- 可使用Keil的AC编译器和STM32CubeIDE工具链
- Debug功能存在诸多问题(无法调试、运行异常、芯片卡启动)
- 开发时需VSCode写代码,Keil专门Debug
- Keil的AC编译器仅限Windows使用,Linux用户需切换系统
2.2 官方解决方案
重大进展:2024年7月1日,ST发布了STM32CubeMX 6.12.0版本!
这次更新带来了两项关键功能:
- CMake工程生成选项:在CubeMX中直接生成CMake项目
- STM32 VS Code Extension:官方VSCode插件,支持CMake工程
虽然插件看起来相对简陋,但它能自动根据STM32工程生成配置文件和脚本,提供必要的编译、调试和下载功能,且允许用户自定义CMake文件以实现个性化配置
这种方案的最大优势在于:
- 跨平台支持:摆脱Windows限制
- 现代开发体验:利用VSCode的插件生态
- 完全自定义:通过CMake控制编译过程
- 全套功能:编译、调试、烧录一应俱全
经过实测,编译下载调试功能完全无问题,但是下载程序默认下载在用户空间起始地址,如果想要分散加载的话可以使用不同工程编译后将文件使用STM32CubePrg下载到对应地址即可(分散加载、BOOT和OTA实现另开文章叙述)
3. 安装
3.1 插件安装与环境配置
首先,我们需要在VSC里面安装ST的官方插件、Cortex-Debug(用于Debug)、C/C++和CMake插件(这两当然不用我说),扩展商店搜索STM32 VS Code Extension
根据STM32插件描述的内容,我们需要准备4个东西
- STM32CubeCLT v1.15.0 or later
- STM32CubeMX v6.11.0 or later
- ST-MCU-FINDER
- Libncurses
其实必要的是两个,STM32CubeCLT和Libncurses,STM32CubeCLT提供工具链。
Libncurses提供linux上使用的UI,使用 Linux 时必须安装此要求。(Win不需要)
STM32CubeCLT可以在Arch的AUR里面直接安装,也可以从ST官网手动下载然后配置环境变量,这里推荐AUR直接装(Win可以从官网直接下载解压)
yay -Sy stm32cubeclt
STM32CubeMX原则上不需要作为插件工作的依赖,插件可以独立使用STM32CubeCLT完成编译、下载、调试等工作,但是你不可能开发不使用STM32CubeMX,所以还是装一下,使用Arch也是可以AUR直接装(如果出现校验出错问题说明ST又不让没登陆的用户下载了,需要手动从ST官网下载包安装,具体方法在stm32cubemx的AUR仓库下的评论区里有,照做就行)
至于STM32Finder其实已经内置在STM32CubeMX里面了,只是一个选型工具,有最新的芯片信息,不安装也无所谓
yay -Sy stm32cubeclt
Windows的STM32CubeMX的安装和登陆就不在这里赘述了
关于Libncurses,Arch可以直接在pacman的core里面安装ncurses
sudo pacman -Sy ncurses
ubuntu用户可以使用APT安装
sudo apt install libncurses
安装插件后打开配置,将STM32CubeCLT的目录填写进设置中
Arch AUR安装的STM32CubeCLT默认目录在/opt/stm32cubeclt,另外两个可以不填写,因为作用只是从扩展启动一下,不是很有必要,想填也行,AUR安装的都在/opt/下。Windows就填写自己选择的安装/解压的目录即可
至此,我们就完成了环境的配置
3.2 工程的创建
插件创建工程的方式非常简单,也和我们传统使用Keil的工作流大差不差
首先,打开STM32CubeMX,登陆账号
(可以看到左下角写的大大的CMake支持(笑))
然后按照基本流程,选择MCU,我这里使用我最常用的STM32G431CBU6作为演示
Tips:这个页面其实就是STM32Finder,单独下载的Finder只有这个按条件查询和介绍的选型功能,所以说不是很有必要,而且CubeMX也包含在内了。
双击打开,进入配置页面,然后按照大家平常自己的习惯配置晶振、时钟 And so on…
我自己的板子一般喜欢用YXC的25MHz的有源晶振,贵一点点钱但是极大程度的确保了时钟系统的稳定性和试错Debug成本,所以就按有源配置了,配置如图所示(开发板硬件设计以后再出一篇文章讲讲吧~~)
然后就可以直接生产工程了,我们选到ProjetManager页面,决定工程名字和目录
填写好路径和名称后,这里和Keil不一样的地方就来了,我们把工具链选择的选项选到CMake,然后再选择生成,就会得到一个配置好CMake的工程目录
打开工程文件夹,你会看见:
现在可以从这个文件夹打开VSC了
打开以后就是这个样子,第一次打开CMake工程的时候,CMake插件会让你选择编译类型,这一步先别管,随便点一下外面就会消失
Tips:我遇到的问题,就是ESP-IDF插件会和STM32的官方插件冲突,如果你使用ESP-IDF记得在工作空间禁用一下
顺带说一个好玩的事情,这两的工程结构都差不多,而且编译工具都是ninja,所以当我不小心在STM32的工程下用了ESP-IDF的编译按钮,他居然成功编译了,而且因为之后会提到的一个ST非常逆天的CMake配置上的问题,STM32插件自己的编译还失败了,就很戏剧性(
之后我们打开左侧的STM32拓展页面,选择Import CMake Project
然后在弹出来的目录选择里面选取CubeMX生成的工程目录
点击确定以后,就会看到STM32的拓展弹出来的配置窗口,正常情况下就确认一下信息是否正确就好了,一般不会有问题,确认没问题直接点最下面的导入
这时候左下角会显示一个✅和Import down的字样,就说明导入成功了,这个时候我们就可以在左边CMake扩展的窗口选择编译类型,开始选择Debug就好,之后程序定稿了我们再选择Release
Tips:这里要注意,选择了Release编译出来的程序是没有调试信息的,所以你使用Release版本Debug会找不到调试信息和断点,点运行就跑飞,如果需要Release版本又要能Debug的话请选择RelWithDebInfo配置
然后我们就可以点击页面最下面的生成来测试编译能否通过啦~
点击编译按钮,看到右边出现这个ROM和RAM占用的信息就说明编译成功了
Tips:这里会出现因为环境变量错乱的问题导致工具链指向不正确,因为这里使用的编译工具全部都是Cubeclt内置的,如果你电脑本身也装了这些工具就有可能导致环境变量冲突、版本冲突、目录冲突等问题导致编译失败,这种时候需要在环境变量里面明确指向Cubeclt文件夹内的工具链,这个问题已经是我很久很久以前遇到的了,后来再新配好像也没有复现,怎么配置环境变量解决的具体操作忘了(诶嘿~),所以如果又遇到了请留言给我我
至此,工程的创建和初步的编译就已经完成了
3.3 工程配置相关
3.3.1 目录结构
这里需要了解一下工程目录的顶层目录结构
📁 CMAKEPROJECTDEMO
├── 📁 .vscode # VS Code 配置文件夹
├── 📁 build # 构建输出目录
├── 📁 cmake # CMake 相关配置文件
├── 📁 CMakeFiles # CMake 生成的中间文件
├── 📁 Core # 核心代码
├── 📁 Drivers # STM32 驱动
├── 📄 .mxproject # STM32CubeMX 项目文件
├── 📄 build.ninja # Ninja 构建系统文件
├── 📄 cmake_install.cmake # CMake 安装脚本
├── 📄 CMakeCache.txt # CMake 缓存
├── 📄 CMakeLists.txt # 主 CMake 项目文件
├── 📄 CMakePresets.json # CMake 预设
├── 📄 CMakeProjectDemo.ioc # STM32CubeMX 配置文件
├── 📄 compile_commands.json # 编译命令数据库(用于代码智能提示)
├── 📄 startup_stm32g431xx.s # 启动汇编代码
└── 📄 stm32g431cbux_flash.ld # 链接器脚本
VS Code 配置文件
📁 .vscode
├── 📄 c_cpp_properties.json # C/C++ 配置
├── 📄 extensions.json # 推荐扩展
├── 📄 launch.json # 调试配置
└── 📄 tasks.json # 任务配置
核心代码结构
📁 Core
├── 📁 Inc # 头文件目录
│ ├── 📄 main.h # 主头文件
│ ├── 📄 stm32g4xx_hal_conf.h # HAL 库配置
│ └── 📄 stm32g4xx_it.h # 中断处理函数声明
└── 📁 Src # 源文件目录
├── 📄 main.c # 主源文件
├── 📄 stm32g4xx_hal_msp.c # MSP (MCU Support Package) 初始化
├── 📄 stm32g4xx_it.c # 中断处理函数实现
├── 📄 syscalls.c # 系统调用实现
├── 📄 sysmem.c # 内存管理
└── 📄 system_stm32g4xx.c # 系统初始化
驱动文件结构
📁 Drivers
├── 📁 CMSIS # Cortex 微控制器软件接口标准
│ └── ...
└── 📁 STM32G4xx_HAL_Driver # 硬件抽象层驱动
└── ...
主要文件说明
- CMakeLists.txt: 项目的主 CMake 文件,定义项目设置、源文件、包含路径等
- CMakeProjectDemo.ioc: STM32CubeMX 配置文件,包含芯片配置信息
- stm32g431cbux_flash.ld: 链接器脚本,定义内存布局
- startup_stm32g431xx.s: 启动文件,包含启动代码和向量表
- main.c: 包含程序入口点和主循环
3.3.2 文件添加
这里要注意的是,添加源文件和配置文件需要在CMakeLists.txt文件里面添加包含路径,分头文件和源文件,如图所示,CMakeLists.txt文件里面已经标注好了如果需要添加文件在哪里添加
对于头文件来说,如果只是单一文件可以直接塞到Inc目录下,不需要做修改;如果是要添加一个新的头文件目录,就在对应target_include_directories位置添加目录的相对路径,要注意的是,.h文件是以目录为单位添加的,所以填写的是目录路径,而.c源文件是以文件为单位添加的,所以就算是在Src目录下添加.c文件,也需要在这里的target_sources下填写相对路径,下面给出一个我的工程例子
这里我没用到独立的头文件目录,所以头文件就留空了,而自己添加了两个源文件,就把相对路径填写在了这里。
3.3.3 编译配置
在STM32生成的cmake目录下的cmake/gcc-arm-none-eabi.cmake配置中,我们可以看到ST已经帮我们写好了完善的编译器配置选项,包括启用硬件浮点,Debug和Rel的优化级别,如果需要修改的话可以在这里修改,但一般不需要
这里需要注意一件事情,也是我自己遇到的,默认情况下编译的工程没法打印浮点数到字符串,也就是sprintf函数没法用于浮点数,需要手动在CMakeLists.txt文件中添加
target_link_options(${PROJECT_NAME} PRIVATE
-u _printf_float # 如果需要浮点打印支持
)
才可以开启浮点数打印支持
至此,配置相关的问题就说完了
4. 开发、下载与调试
4.1 开发
在VSC的开发和Keil也差不多,也是从main.c开始运行程序
使用CubeMX修改后重新生成,VSC也会自动重新读入文件,这里建议打开VSC的自动保存选项,在右上角选项的文件->自动保存,防止忘记保存时CubeMX修改后重新生成覆盖我们写的代码,也增加代码的同步性
然后其他内容也和Keil方法一致,编译点下面的生成即可,但是可以看出,用这套工具链我们的编译速度不Keil不知道高到哪里去了~
建议打开GitHub Copilot获得最佳极致体验哦~
4.2 下载
下载的实现很简单,就是给VSC写了个Task配置文件来调用STM32Cubeclt来选中编译好的文件进行下载,那我们下载的时候只要插上STLinker并确定识别,然后使用VSC运行Task即可
刚刚研究使用的时候我找了很久没找到怎么下载,插件也没设计按钮,后来翻生成的VSC配置文件才找到,所以我说插件简陋,按钮UI都舍不得做点((((
使用快捷键 Ctrl + Shift + P 我们可以打开VSC的运行页面,输入Task,选择如图所示的运行任务
Tips:如果使用过运行任务的话,之后按Ctrl + Shift + P 打开运行界面第一个就会是运行任务,此时直接按回车就可以直接调用了
然后我们连接STLinker和开发板,这里我使用自制的IMU板子和ST官方的STLinkerV3 MINIE来演示
[外链图片转存中…(img-YRhnq0ys-1744042568268)]
这里可以使用STM32CubePrg来检查调试器和开发板的连接状态,STLinker如果连接成功就会直接显示,点击Connect有数据就说明连接正常,这里我们成功正常连接
然后关闭STM32CubePrg,回到我们的VSC工程,Ctrl + Shift + P 输入Task ,选择运行任务,然后不出意外的话Build and Flash就会是第一个,这个选项就是编译并下载,我们直接按回车就可以完成下载
也就是说,当你运行过一次以后,下次按 Ctrl + Shift + P 加上两次回车就可以直接编译并下载了,很方便吧~
如果成功下载,下面的控制台会输出如下所示画面
没错,我的输出那么完整是因为我拉开了截图的,滚动查看一样就行
如此,我们就完成了一次下载
4.3 调试
完成了下载,接下来我们就需要调试了,确定插件Cortex-Debug已经安装,并且编译选项选择Debug,然后我们可以直接切换到VSC左侧选项栏的Debug界面直接点击Debug,理论上不出意外的话就可以直接开始调试了
很正常的获取到了调试信息,运行到断点也没有问题,变量值也可以正常显示和监控
至此,调试部分也就结束了,很简单对吧~
Q&A
CMake清理
前面我提到过 “而且因为之后会提到的一个ST非常逆天的CMake配置上的问题,STM32插件自己的编译还失败了” 这个这句话,那你一定很好奇是什么问题吧?
没错,这个工程没有配置CMake缓存清理类的脚本或者CMake任务,而他的缓存保存的是 绝对路径
没错!绝对路径!!!!
也就是说,一旦你第一次编译后,把工程移动一下位置,诶,这个工程就不能编译了,我第一次发现是在两台电脑上开发,一台推上GitHub另一台拉下来
诶,编译不能
就很逆天,然后我研究了半天他的缓存机制,总算手动解决这个问题,于是乎现在,我写了一个bash脚本来自动化解决这个问题,只要把这个脚本放在工程目录下,每次移动完以后运行一下,就可以正常编译了
#!/bin/bash
#获取当前脚本所在目录作为项目根目录
PROJECT_ROOT=$(cd `dirname $0` && pwd)
BUILD_DIR="$PROJECT_ROOT/build/Debug"
echo "=== 清理旧构建缓存 ==="
if [ -d "$BUILD_DIR" ]; then
rm -rf "$BUILD_DIR" && echo "已删除旧构建目录"
fi
echo -e "\n=== 生成新构建系统 ==="
cmake -DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_TOOLCHAIN_FILE="$PROJECT_ROOT/cmake/gcc-arm-none-eabi.cmake" \
-S "$PROJECT_ROOT" \
-B "$BUILD_DIR" \
-G Ninja
echo -e "\n=== 开始编译 ==="
cmake --build "$BUILD_DIR"
在工程下新建文件,名字随意后缀为.sh,把这个脚本复制进去保存,然后别忘了
chmod +x xxx.sh
然后运行即可,下面给出运行结果
尾声
至此,本篇教程就结束啦,希望你通过本篇教程可以得到一个舒适完美的STM32开发环境!
Q&A部分目前就想到这个,很多问题我可能自己解决了但是忘记遇到过了,后续如果再遇到相关的会在这个部分持续更新,如果有遇到问题也可以留言给我,我会把问题在Q&A部分继续更新
感谢您的观看!
相关链接
更多推荐
所有评论(0)