Keil5 工程迁移到 STM32CubeIDE 的一次整理:C 工程、C++ 工程和 FreeRTOS 注意点

最近把一个原本在 Keil5 里维护的 STM32 工程迁移到了 STM32CubeIDE。然后在网上没找到使用CubeMX生成,并且包含c++的工程的迁移教程。因此研究完后写了这篇文章,给遇到同类问题的朋友做个参考。

迁移过程本身不算复杂,但有几个地方比较容易踩坑:CubeMX 生成工程时的 Toolchain 选择、CubeIDE 的 Source Location、C++ 文件不会自动加入编译、FreeRTOS 的 port 文件也要换成 GCC 版本。

适用场景

本文主要适用于下面几类情况:

  • 原工程使用 Keil5 编译,现在想迁移到 STM32CubeIDE。

  • 工程由 STM32CubeMX 生成,包含 .ioc 文件。

  • 工程可能是纯 C 工程,也可能混合了 C/C++ 文件。

  • 工程可能使用 FreeRTOS。

目录

一、纯 C 工程迁移

1. 在 CubeMX 中切换 Toolchain

2. 在 STM32CubeIDE 中导入工程

3. 添加头文件路径

4. 添加宏定义

5. 配置 Source Location

6. 设置优化等级

7.编译工程

二、带 FreeRTOS 工程的注意点

三、编译结果中的 text、data、bss 怎么看

四、C/C++ 混合工程迁移

1. 在 CubeMX 中切换 Toolchain

2. 在 CubeIDE 中新建或导入 IOC 工程

3. 手动导入 C++ 文件

4. 添加 C++ 工程的头文件路径

五、为什么 Keil 能编译 C++,IDE 导入后却按 C 工程处理

六、迁移检查清单

总结


一、纯 C 工程迁移

1. 在 CubeMX 中切换 Toolchain

先打开工程对应的 .ioc 文件,在 STM32CubeMX 中把工程的 Toolchain / IDE 改为 STM32CubeIDE。

这里建议勾选生成工程相关选项,然后重新生成代码。

2. 在 STM32CubeIDE 中导入工程

打开 STM32CubeIDE,导入工程根目录。

导入完成后,可以在工程属性里的 C/C++ Build 页面检查构建配置是否正常生成。

如果这里能看到 Debug / Release 之类的构建配置,说明 CubeIDE 已经识别到了工程的构建信息。

3. 添加头文件路径

打开工程的 Properties,在编译器设置里补齐 include path。

常见需要确认的目录包括:

  • Core/Inc

  • Drivers/STM32F1xx_HAL_Driver/Inc

  • Drivers/CMSIS/Device/ST/STM32F1xx/Include

  • Drivers/CMSIS/Include

  • 项目中自己新增的模块头文件目录

具体路径要根据自己的芯片型号和工程目录调整。

4. 添加宏定义

Keil 工程中原本配置的宏定义,也需要同步到 CubeIDE 中。

常见宏包括:

USE_HAL_DRIVER
STM32F103xB

这里的芯片宏一定要和实际芯片型号匹配。例如 STM32F103C8T6 一般使用 STM32F103xB,不要直接照抄其他工程。

5. 配置 Source Location

这一步要看实际情况。如果工程已经可以正常编译,就不需要额外调整。

如果编译时出现一堆来自 CMSIS 示例、RTOS、NN、Template 等目录的错误,多半是 Source Location 把过大的目录加进来了,导致 CubeIDE 把不该参与编译的文件也编译了。

处理思路有两个。

第一种方式是只加入真正需要编译的源码目录,例如:

Drivers/STM32F1xx_HAL_Driver/Src

然后按需添加工程自己的源码目录。

第二种方式是保留当前目录结构,但把不需要编译的文件手动排除。

在文件属性中勾选 Exclude from build。

我个人更推荐第一种方式:只把必要目录加入构建。这样工程结构更清楚,后续也不容易莫名其妙编译到示例文件。

6. 设置优化等级

CubeIDE 使用 GCC 工具链,优化等级也可以在工程属性中配置。

几个常见选项的含义:

优化等级 含义
-O0 不优化,最适合初期调试
-Og 为调试体验做优化,推荐调试阶段使用
-O1 轻度优化
-O2 常用性能优化,发布版本比较常见
-O3 更激进的速度优化,可能增大代码体积
-Os 优先优化代码体积
-Ofast 非常激进的速度优化,会放宽部分标准规则
-Oz 更极限地压缩代码体积

调试阶段建议先用 -O0-Og,否则断点、变量观察、单步执行都可能变得不直观。

7.编译工程

二、带 FreeRTOS 工程的注意点

如果工程使用了 FreeRTOS,要特别注意 portable 目录下的 port 文件。

Keil 工程常用的是 RVDS 路径:

Middlewares\Third_Party\FreeRTOS\Source\portable\RVDS\ARM_CM3\port.c

迁移到 STM32CubeIDE 后,因为编译链变成了 GCC,所以应该改成 GCC 对应路径:

Middlewares\Third_Party\FreeRTOS\Source\portable\GCC\ARM_CM3\port.c

对比起来就是:

- Middlewares\Third_Party\FreeRTOS\Source\portable\RVDS\ARM_CM3\port.c
+ Middlewares\Third_Party\FreeRTOS\Source\portable\GCC\ARM_CM3\port.c

原因也很好理解:FreeRTOS 本身是通用的,但任务切换、开关中断、进入临界区、触发 PendSV、处理 SVC/SysTick 这些底层动作,都依赖具体 CPU 架构和编译器汇编语法。

所以 FreeRTOS 会把这些平台相关代码放在 portable 目录中。Keil 对应 RVDS,STM32CubeIDE 对应 GCC,迁移时这里不能混用。

三、编译结果中的 text、data、bss 怎么看

CubeIDE 编译后经常会看到类似下面的结果:

text    48216
data      596
bss     12772
dec     61584
hex      f090

这些字段可以这样理解:

字段 含义
text 代码段和只读常量,主要占用 Flash
data 已初始化的全局变量或静态变量,初值存放在 Flash,运行时占用 RAM
bss 未初始化或初始化为 0 的全局变量或静态变量,只占用 RAM
dec 十进制总和,通常是 text + data + bss
hex dec 的十六进制表示

需要注意的是,dec 只是一个总和,不等同于真实 Flash 或 RAM 占用。更实用的判断方式是:

Flash 占用约等于 text + data
RAM 占用约等于 data + bss

四、C/C++ 混合工程迁移

如果项目里除了 C 文件,还有 C++ 文件,迁移时要多处理一步。

1. 在 CubeMX 中切换 Toolchain

这一步和纯 C 工程一样,先在 CubeMX 中把 Toolchain / IDE 改成 STM32CubeIDE,然后重新生成工程。


2. 在 CubeIDE 中新建或导入 IOC 工程

在 STM32CubeIDE 中新建 .ioc 工程。

3. 手动导入 C++ 文件

这里是 C/C++ 混合工程最容易忽略的点:CubeIDE 新建工程时通常只会自动加入 C 文件,.cpp 文件需要手动导入或手动加入工程,才会参与编译。

导入后,在工程属性里应该能看到 C++ 编译器相关配置。

4. 添加 C++ 工程的头文件路径

C++ 工程同样需要补齐 include path。

后续步骤和纯 C 工程一致:从1.4开始添加宏定义、检查 Source Location、处理 FreeRTOS port 文件、设置优化等级。

五、为什么 Keil 能编译 C++,IDE 导入后却按 C 工程处理

这个问题本质上是 Keil 和 STM32CubeIDE 对工程类型的判断机制不一样。

Keil 的工程文件是 .uvprojx。它会保存 C/C++ 编译设置,而且 Keil 对 .cpp 文件会自动使用 C++ 模式编译。

STM32CubeIDE 基于 Eclipse CDT,它主要读取自己的工程文件,例如:

.project
.cproject
.mxproject

如果这些文件里没有 C++ nature 或 G++ toolchain 配置,CubeIDE 不会因为目录里存在 .cpp 文件,就自动把整个工程转换成 C++ 工程。

几个文件的大致作用如下:

文件 作用
.project 描述 Eclipse 工程类型,包括工程名、builder、nature 等
.cproject CDT 构建配置,包括 Debug / Release、gcc / g++、编译器、链接器、include paths、宏定义、优化等级、链接脚本、排除规则等
.mxproject CubeMX 生成代码时的工程结构和文件清单,包括源文件、头文件、库文件和路径信息

所以 C++ 工程迁移时,不能只把 .cpp 文件放进目录里,还要确保 CubeIDE 工程本身具备 C++ 构建配置。

六、迁移检查清单

最后整理一个检查清单,迁移时可以按这个顺序过一遍:

  • CubeMX 的 Toolchain / IDE 是否已经切换为 STM32CubeIDE。

  • 是否重新生成了工程文件。

  • CubeIDE 中是否能看到正常的 C/C++ Build 配置。

  • include path 是否补齐。

  • Keil 中原有的宏定义是否同步到 CubeIDE。

  • Source Location 是否只包含需要编译的源码目录。

  • 不需要编译的示例文件、Template 文件是否已排除。

  • 使用 FreeRTOS 时,是否切换到了 portable/GCC 下的 port 文件。

  • C++ 文件是否已经手动加入工程并参与编译。

  • C++ 工程是否能看到 G++ / C++ Compiler 相关配置。

  • 优化等级是否适合当前阶段,调试阶段优先考虑 -O0-Og

  • 编译后的 Flash / RAM 占用是否合理。

总结

Keil5 迁移到 STM32CubeIDE,核心不是“把代码复制过去”这么简单,而是要把原来 Keil 工程里的构建信息迁移完整,包括头文件路径、宏定义、源码目录、编译器类型、FreeRTOS port 文件和优化等级。

纯 C 工程一般比较顺,主要注意 Source Location 不要误编译无关文件。C/C++ 混合工程则要额外关注 .cpp 文件是否真正加入了 CubeIDE 的 C++ 构建系统。

这次整理下来,最大的经验是:迁移后先别急着改业务代码,先把构建系统理顺。只要编译链、路径和宏定义对齐,后面的错误定位会轻松很多。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐