我先说结论:这四件套你一个都别想删,但它们确实不是四个干同样事情的软件。把它们理解成一条流水线上的四个工位,你就再也不会对着满屏图标发懵了。
事情是这样。朋友甩给我一个STM32开发环境清单,说"照着装就行",我也没多想,装完打开桌面一看:STM32CubeMX、Keil MDK、STM32CubeProgrammer、VSCode,四个图标整整齐齐。然后问题来了——我该先点开哪个?为什么写个嵌入式程序要同时开四个软件?这四年下来,我已经被问过很多次同样的问题。今天这篇,我就用最直白的方式把这四件套拆开讲清楚,顺便把新手最容易踩的"边界混用"坑也一起排掉。
1. 流水线思维:四个软件其实是同一条生产线的四个工位
1.1 从"点亮一颗LED"看懂整条工具链的输入输出
很多人一上来就盯住"软件"本身,却忘了它们本质上是一道工序。你写嵌入式程序,最终要做的事情只有一件:把源代码变成芯片Flash里的机器码,让芯片上电后按你的逻辑跑。
这条链路拆开就是四个环节:
- 规划:告诉芯片"哪个引脚接LED、使用哪个定时器、时钟跑多快"。
- 写码:把业务逻辑用C/C++写出来。
- 编译:把代码翻译成芯片能执行的机器码,生成烧录文件。
- 烧录:把机器码文件写进芯片Flash。
四件套刚好对应这四个环节:
- STM32CubeMX负责规划和"初始化代码生成",输出的是工程骨架和引脚配置。
- VSCode负责写码,它只是一个文本编辑器,不编译、不烧录。
- Keil MDK负责编译+下载+调试,它是施工队,也是监理。
- STM32CubeProgrammer负责烧录,是独立的搬运工。
我打个比方你就懂了。CubeMX像是装修公司的设计师,先画图纸,告诉你哪个插座放哪、哪面墙拆掉;VSCode是你的办公桌,你在上面写装修需求文档;Keil是施工队,照着图纸把房子盖起来;CubeProgrammer是搬家师傅,把盖好的房子里的家具(固件)一件件搬进去。
所以你会发现:这四个软件没有一个是可以被单独扔掉的,除非你找到替代品。它们之间不是竞争关系,是上下游关系。
1.2 为什么没有一个"全家桶"软件
这是我当年最气的地方。明明都是ST官方或者行业老牌的东西,为什么不能合成一个?
答案有点历史包袱。Keil从8051时代就是独立IDE,它的强项是编译器和调试器,但它对"图形化初始化代码"这件事一直不太上心。而STM32这种芯片外设复杂,寄存器多到你根本不想手写初始化代码,于是ST推出了CubeMX来干这个活。再后来,ST想把事情收拢,推出了STM32CubeIDE——它把CubeMX、编译链、调试器整合到了一起。
那为什么大家还是习惯装四个?因为行业惯性太大了。绝大多数教程、公司项目、开发板资料都是"CubeMX生成 + Keil编译"的路子,CubeIDE虽然也在推广,但你要是进了个老团队,还是免不了跟Keil打交道。而CubeProgrammer又恰好解决了一个Keil不太擅长的场景:产线烧录、批量烧录、芯片读保护设置。
所以别纠结"为什么这么多",直接接受这个生态现状就行。下面逐个拆。
2. 逐个拆解:每款软件的职责边界和产出物
2.1 STM32CubeMX:画图先生,负责把引脚和时钟"画"出来
CubeMX的核心定位是图形化配置工具。它干三件事:
- 选芯片型号,比如STM32F103C8T6。
- 可视化配置引脚功能,比如把PA5设为GPIO输出,把USART1的TX/RX分配到PA9/PA10。
- 配置时钟树,比如把系统时钟倍频到72MHz。
配置完之后,CubeMX不是"生成一个能直接编译的完整程序",而是生成一份初始化C代码和工程骨架:main.c、gpio.c、usart.c、时钟初始化函数、外设句柄结构体等。这些代码是给你后续写业务逻辑打地基用的。
它输出的关键文件:
| 文件/目录 | 作用 |
|---|---|
.ioc文件 | 工程配置记录,再次打开CubeMX时恢复界面状态 |
Core/Src/main.c | 主程序入口,里面已生成外设初始化调用 |
Core/Src/gpio.c | GPIO初始化代码 |
Core/Inc/ | 头文件目录 |
Makefile或.uvprojx | 根据你选的Toolchain生成的构建/IDE工程文件 |
注意,CubeMX不负责编译。它生成代码就完成了自己的使命。
2.2 Keil MDK:施工队+监理,编译、烧录、调试一条龙
Keil MDK全称是MDK-ARM,它本质是一个集成开发环境(IDE)+编译工具链。核心作用有两个:
- 编译:把你写的.c/.cpp文件、CubeMX生成的初始化代码,编译链接成机器码,输出.hex/.bin/.axf文件。
- 下载/调试:通过ST-Link等调试器,把固件烧进芯片,还能在线打断点、看寄存器、看变量值。
很多人把Keil当成"写代码的地方",其实写代码只是顺带的,它的编辑器体验一般。Keil真正不可替代的是编译器——ARMCC(AC5)或armclang(AC6)。AC6对C++11/14支持还行,这也是它还能在嵌入式C++项目里存活的原因之一。
Keil工作时的输入输出:
- 输入:工程里所有源代码文件、启动文件、链接脚本。
- 输出:
Objects/目录下生成的.axf(含调试信息)、.hex(烧录文件)、.map(内存映射文件)。 - 依赖:芯片支持包(Device Family Pack),比如你要做STM32F1系列,就通过Pack Installer装Keil.STM32F1xx_DFP。
2.3 STM32CubeProgrammer:独立烧录员,不写代码但管固件
这个软件最容易让人困惑:Keil明明也能下载,为什么还要单独装一个烧录工具?
CubeProgrammer是ST官方的独立烧录/调试工具,它跟Keil重叠的部分是"能烧录",但它的定位更广:
- 支持多种连接方式:ST-Link、USART、USB DFU、FDCSP等。
- 能烧录.hex/.bin,也能读回Flash内容、比对校验。
- 能配置选项字节(Option Bytes),比如设置读保护(RDP)、看门狗配置。
- 能单独擦除整片Flash、操作OTP区域。
- 提供命令行CLI版本,方便产线脚本化批量烧录。
在实际项目中,CubeProgrammer最常见的场景是:在产线上不装Keil,只装这个工具 + 一个.hex文件,咔咔烧板子。Keil是有License的,产线不可能每台电脑都装,CubeProgrammer免费,命令行一敲就完事。
它还负责修一些"Keil不管的事",比如芯片被读保护锁死了,你用Keil是没法直接解除的,得靠CubeProgrammer把RDP级别降回来。
2.4 VSCode:你的写字台,只负责代码文本本身
VSCode在这四件套里的角色最容易被高估或低估。被高估的人以为"我在VSCode里写了代码,就等于项目完成了";被低估的人觉得"它就是高级记事本"。
准确说,VSCode是个通用代码编辑器,它对嵌入式开发的价值是:
- 插件生态好,装个C/C++插件后,语法高亮、代码补全、跳转、括号匹配都比Keil原生编辑器强太多。
- 配合EIDE插件或CMake,可以把Keil或GCC工具链的编译命令拉起来跑。
- 配合Cortex-Debug插件,可以接OpenOCD做调试界面。
- 对C++工程友好,智能提示(IntelliSense)对模板、类、STL的体验远胜Keil。
但是,VSCode自己不会编译,也不会烧录。它定位是"更好的写字台",写好的纸最终要交给施工队(Keil或GCC工具链)去盖房。
所以你观察一下就会发现,四件套里只有Keil(或CubeIDE)是"能闭眼从头干到尾"的,其他三个都是围绕它做配套。
3. 实操串一遍:CubeMX生成、Keil编译、串口打印的完整链路
光讲定位太空了。我拿一个最典型的小实验——STM32通过串口每秒打印一行Hello STM32——把四个软件完整走一遍。走完你就知道"现在这个阶段该打开哪个软件"了。
3.1 CubeMX端:芯片选型、外设配置、Toolchain选择
第一步打开CubeMX,新建工程,搜你手上的芯片型号。我用的是最常见的STM32F103C8T6。
配置重点:
- SYS-> Debug:选
Serial Wire,这是为了引出SWD调试接口,不然ST-Link连不上。 - USART1:Mode选
Asynchronous(异步模式),默认引脚PA9/PA10就行,波特率设115200。 - 时钟树(Clock Configuration):直接在HCLK输入72,回车让CubeMX自动分配PLL参数,F103最高就是72MHz。
关键的一步在这里:左侧栏切到Project Manager->Project,Toolchain/IDE下拉框要选MDK-ARM。这个选项决定CubeMX生成的是Keil工程(.uvprojx)还是Makefile工程。
再切到Code Generator,勾选Generate peripheral initialization as a pair of .c/.h files per peripheral,这样每个外设的初始化和头文件是分开的,结构清爽。
最后点右上角GENERATE CODE,会生成一个包含MDK-ARM文件夹的完整工程目录。CubeMX这一段的"产出物"就是这个工程文件夹。
3.2 Keil端:工程组织、编译链接、下载运行
CubeMX生成后,进入MDK-ARM目录,双击.uvprojx文件,Keil就打开了。
此时你会看到左侧工程树已经有main.c、gpio.c、usart.c、stm32f1xx_hal_msp.c等文件。这些文件是CubeMX帮你生成好的,已经编译得通。
现在打开main.c,在main()函数的while (1)循环里加一行串口发送代码:
#include <string.h> // 在main函数while(1)里加入: char msg[] = "Hello STM32\r\n"; HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY); HAL_Delay(1000);写完代码,先别急着点下载。按快捷键F7编译,或者点工具栏Build按钮。
这里有个新手必踩的点:Keil默认不生成.hex文件。如果你后面想用CubeProgrammer烧录,得先设置:Options for Target->Output-> 勾选Create HEX File。不勾选的话,你编译一百遍也找不到.hex在哪。
编译通过后,Objects/目录下会出现.axf和.hex。现在把ST-Link接到板子,Keil里点LOAD(F8)下载,点START/STOP Debug Session(Ctrl+F5)进入调试。芯片跑起来后,你用任意串口助手打开对应COM口,波特率115200,就能看到每秒钟蹦一行Hello STM32。
这一套下来,你会清晰感受到:CubeMX画图,VSCode/Keil写字,Keil编译下载,三个工具各干各的。
3.3 CubeProgrammer端:脱离Keil的烧录验证
现在我们把Keil关掉,模拟"生产环境"——只有一台电脑、一个.hex文件、一个CubeProgrammer的场合。
打开CubeProgrammer图形界面,右上角选择连接方式ST-LINK,点Connect。连接成功后,擦除芯片(Full chip erase),然后点Open file选择刚才Keil生成的.hex,点Download。烧完你会看到Verification通过。
更常用的是命令行版本,适合写脚本批量烧:
STM32_Programmer_CLI.exe -c port=SWD mode=UR -w .\Objects\Demo.hex -v-c是连接参数,port=SWD指定SWD接口,mode=UR表示热复位模式,-w指定烧录文件,-v烧完校验。
如果你只是想验证"烧录能成功",用CubeProgrammer会比Keil更直观——它把擦除、写入、校验、选项字节全部拆成独立步骤,看得清清楚楚。这也是我建议新手专门用它烧一次的原因:它能帮你在脑子里建立"编译产物"和"烧录动作"的分离感,别再把两个概念混在一起。
4. 新手最容易栽的"软件边界"坑
4.1 "我在VSCode写了代码,Keil里什么都没有"
这是问得最多的一种情况。你在VSCode打开CubeMX生成的main.c,改了几行,回到Keil一看——还是老代码。
原因很简单:VSCode只是改了你磁盘上的文件,而Keil打开的是同一个文件,需要重新编译/重新打开才看得到。Keil不会自动监测外部文件变化,你切回Keil后要点一下Rebuild或者重新打开文件,它才会重新读取。
实际开发建议:要么统一在Keil里改,要么统一在VSCode里改,别来回换。我最推荐的做法是,普通代码阅读和搜索用VSCode,真正写业务逻辑时直接在工程目录上加文件,再用Keil添加文件引用。
4.2 "CubeMX生成的工程,Keil打不开"
CubeMX生成完,发现MDK-ARM文件夹里没有.uvprojx,或者Keil打开工程提示找不到芯片。
两个排查点:
- Toolchain/IDE选错了。在Project Manager里如果选了
STM32CubeIDE或Makefile,那你得到的就不是Keil工程文件。重新生成时改成MDK-ARM就行。 - Keil没装对应芯片包。比如你用F103芯片,要装
Keil.STM32F1xx_DFP。打开Keil的Pack Installer,左侧搜STM32F1,右侧点Install。这个包不装,CubeMX生成几百个文件,Keil一个都不认。
顺带提一句关于"Keil5兼容C51和STM32"的疑惑:MDK-ARM(支持STM32)和C51(支持8051)是两个不同产品,可以用Keil的安装机制共存,但工程文件不通用,别拿C51的工程去MDK里打开。装的时候记得分别装到不同目录,或者用Pack Installer管理各自的Packs。
4.3 "CubeProgrammer连不上芯片"
连不上芯片,九成不是软件问题,而是硬件/连接问题:
- ST-Link与板子的接线:SWDIO(SWDIO)、SWCLK(SWCLK)、GND三条线必须接对,VCC有时也要接。
- 驱动没装:装CubeProgrammer前,先把ST-Link的驱动装好,Windows设备管理器里能看到
STLink dongle。 - 芯片已设置读保护:连接时会报
Error: No STM32 target found或者读保护错误,需要先执行Option Bytes里的RDP level降级(选择AA翻到level 0),再Full chip erase。 - 复位电容/BOOT0状态:某些板子需要断开调试接口供电,或者短接BOOT0到3.3V让芯片从系统存储器启动,才能连上。
如果是在Keil里能下载,但CubeProgrammer连不上,优先怀疑驱动版本冲突,重装ST-Link驱动基本能解。
4.4 CubeMX、CubeIDE、CubeProgrammer三兄弟怎么区分
很多人第一次装软件时,看到三个带"Cube"的软件直接晕掉。
- CubeMX:负责生成工程和初始化代码。它不是IDE,不编译。
- CubeIDE:是一个完整的IDE,内置了CubeMX的配置界面,也内置了GCC编译器和调试器。它想做"全家桶",能替代"CubeMX + Keil"的组合。
- CubeProgrammer:只管烧录/调试/读保护,跟前面两个不在一个环节。
所以如果你的教程用的是Keil,那CubeIDE就多余;如果你的教程用的是CubeIDE,那Keil就多余。两者取一,剩下的CubeMX和CubeProgrammer大概率还是会装上。
4.5 嵌入式C++工程的坑:CubeMX生成的C文件和C++工程混编
这个系列既然叫"嵌入式C++编程之旅",那这条坑一定要单拎出来。
CubeMX生成的文件全部是.c,里面调用的是HAL库的C接口。你想用C++写业务逻辑,比如建个类、用个模板,最简单的方法是把main.c改成main.cpp重命名后再加入工程,然后在文件头部用extern "C"包住HAL头文件:
extern "C" { #include "main.h" #include "usart.h" }如果直接用.cpp文件包含.h头文件而不加extern "C",链接时会出现类似undefined reference to HAL_UART_Transmit的报错。原因:C++编译器会对函数名做名字修饰(mangling),而HAL库是按C语言编译的,两者对不上。
Keil里要把文件编译成C++,还需要在Options for Target->C/C++->Language C里选择对应C++标准(AC6选gnu++17也行)。这一块如果你平时写C++写得多,会非常舒服;如果只想跑通例程,老老实实全用C也没毛病。
5. 按需精简:这套工具链怎么配才不冤枉
5.1 入门学习期:CubeMX + Keil 是最稳的组合
如果你刚入门,我强烈建议只装这两个,VSCode和CubeProgrammer先放一边。理由很简单:入门阶段你的心思要放在"看现象、改代码"上,工具越少,干扰越少。
CubeMX生成工程,Keil编译下载,一个串口助手看输出,这就够跑完LED、按键、串口、定时器、中断这些基础实验。等跑完一轮再回头看CubeProgrammer,你会觉得水到渠成。
5.2 想用C++和VSCode:免费GCC路线怎么搭
如果你被Keil的编辑器折磨得不行,又不想花钱买License,可以走VSCode + ARM GCC + Makefile/CMake的路线。
流程是这样:CubeMX生成工程时,Toolchain/IDE选Makefile,生成一份带Makefile的工程。然后:
- 安装
arm-none-eabi-gcc工具链,配置环境变量。 - 在VSCode里装
C/C++插件(微软官方的那个)和Cortex-Debug插件。 - 装
OpenOCD,配置openocd.cfg,指定ST-Link和芯片参数。 - 在工程目录跑
make编译,生成.hex。 - 用CubeProgrammer烧录,或者用VSCode的Cortex-Debug接OpenOCD打断点调试。
这条路对C++极其友好:GCC对C++17的支持完整,模板、STL随便用,VSCode的智能提示也是第一梯队。但代价是你需要懂一点Makefile和OpenOCD配置,排查链路更长。这条路线更适合已经玩明白Keil的兄弟,不建议零基础开局。
5.3 什么时候才必须用CubeProgrammer
我用几个场景帮你判断:
- 你的板子设置了读保护,Keil下载时报错,需要降低RDP级别 —— 必用。
- 公司产线要批量烧录很多块板子,需要命令行自动化 —— 必用。
- 你想备份芯片里的固件,读出来存成.hex —— 必用。
- 你只是自己连ST-Link下载调试 —— Keil就够了,不必开CubeProgrammer。
5.4 我个人的习惯:把"软件"翻译成"工序"再记
踩过几年坑之后,我搭环境的第一件事不再是"装什么软件",而是先想清楚我的流程是什么:从芯片初始化到固件烧录,在哪一步、用什么工具、产出什么文件。软件只是这道工序的载体,你脑子里有流程,图标再多也不会乱。
我个人对这套四件套的最终评价是:VSCode让写代码舒服,CubeMX让初始化省事,Keil让编译调试稳当,CubeProgrammer让烧录独立可控。它们各有长处,拼起来正好补足彼此。比起纠结"为什么四个",不如现在就去把CubeMX工程生成一遍,再用Keil编译烧录一次,走完一个完整的LED闪烁流程。等你看到板子上的灯按你的代码亮起来,这四个图标在你桌面上的意义,就再也不是谜了。