# CMake_STM32 **Repository Path**: lankii/cmake_stm32 ## Basic Information - **Project Name**: CMake_STM32 - **Description**: 一个基于CMake和STM32CubeMX的体系化、框架化STM32嵌入式开发框架。 - **Primary Language**: C - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2025-12-22 - **Last Updated**: 2025-12-22 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # STM32嵌入式开发框架 一个基于CMake和STM32CubeMX的体系化、框架化STM32嵌入式开发框架。 **架构特点**: - 按**芯片系列**组织HAL驱动(而非具体芯片型号) - BSP功能整合到drivers层,保持架构简洁 - 链接脚本由CubeMX在每个项目中生成,符合CubeMX工作流程 ## 📋 目录结构 ``` CMake_STM32/ ├── app/ # 应用层 - 多个应用项目 │ ├── default/ # 默认应用项目(示例) │ │ ├── cubemx/ # CubeMX生成的初始化代码(项目特定) │ │ │ ├── Inc/ # CubeMX生成的头文件 │ │ │ └── Src/ # CubeMX生成的源文件 │ │ ├── CMakeLists.txt │ │ └── main.c # 应用主程序和业务逻辑 │ └── project1/ # 项目1(可以有独立的CubeMX配置) │ ├── cubemx/ │ ├── CMakeLists.txt │ └── main.c ├── boards/ # STM32Cube软件包(HAL驱动和中间件) │ └── STM32CubeF1/ # STM32CubeF1软件包(F1系列) │ ├── Drivers/ │ │ ├── STM32F1xx_HAL_Driver/ # F1系列HAL底层驱动(所有F1芯片共享) │ │ └── CMSIS/ # CMSIS核心文件 │ └── Middlewares/ # 中间件(FreeRTOS、FatFS、LWIP等) │ ├── Third_Party/ │ │ ├── FreeRTOS/ │ │ ├── FatFs/ │ │ └── LwIP/ │ └── ST/ ├── cmake/ # CMake工具链和配置文件 │ └── middleware-config.cmake # 中间件配置管理 ├── components/ # 组件层 - 可复用功能模块 ├── drivers/ # 驱动层 - 外设驱动封装 │ ├── system/ # 系统驱动(延时、时钟等工具函数) │ ├── gpio/ │ ├── uart/ │ └── ... └── CMakeLists.txt # 根目录CMake配置 ``` ## 🚀 快速开始 ### 1. 环境准备 - **交叉编译工具链**: ARM GCC (arm-none-eabi-gcc) - Windows: [GNU Arm Embedded Toolchain](https://developer.arm.com/downloads/-/gnu-rm) - Linux: `sudo apt-get install gcc-arm-none-eabi` - Mac: `brew install arm-none-eabi-gcc` - **CMake**: 版本 >= 3.20 - **STM32CubeMX**: 用于生成初始化代码 - **Ninja** (可选但推荐): 用于快速构建 - Windows: 包含在 CMake 中或通过 `choco install ninja` - Linux: `sudo apt-get install ninja-build` - Mac: `brew install ninja` ### 2. HAL底层驱动(已包含) 框架已经配置为使用 `boards/STM32CubeF1/` 目录下的HAL驱动。 **说明**: - **HAL驱动**:`boards/STM32CubeF1/Drivers/` 包含F1系列所有芯片的HAL底层驱动 - **系列级别**:F1系列的所有芯片(如STM32F103RC, STM32F103C8等)共享同一套HAL驱动 - **自动识别**:框架会自动查找并使用这些驱动 ### 3. 生成CubeMX初始化代码(每个项目独立) **每个应用项目需要单独生成CubeMX初始化代码**: 1. 使用STM32CubeMX创建新项目,选择目标芯片(如STM32F103RC) 2. 配置所需的外设(GPIO、UART、SPI、I2C等) 3. **Project Manager → Project Settings**: - **Toolchain/IDE**: 选择 `Makefile` - **Project Location**: 指向 `app/default/cubemx/`(或你的项目目录) - **Code Generator**: - 选择 **"Add necessary library files as reference"** (不需要复制HAL驱动,已在boards中) 4. 生成代码(点击 **GENERATE CODE**) **说明**: - **CubeMX生成的初始化代码**:放在每个项目的 `app/${PROJECT}/cubemx/` 目录下 - **链接脚本**:由CubeMX生成,位于各项目的 `cubemx/` 目录或项目根目录 - **HAL底层驱动**:`boards/STM32CubeF1/` 目录,F1系列所有芯片共享 - 不同项目可以有不同的CubeMX配置(不同的外设、引脚等) ### 4. 创建新应用项目(可选) 框架支持多个应用项目,每个项目可以有独立的CubeMX配置: **方式一:从现有项目复制(推荐)** ```bash # 创建新项目目录 mkdir app/my_project # 复制项目模板(可以使用 10.14_PTC_Temp 作为模板) cp -r app/10.14_PTC_Temp/* app/my_project/ # 或者复制 default 项目 cp -r app/default/* app/my_project/ # 为新项目生成CubeMX初始化代码 # 1. 在CubeMX中创建新项目 # 2. 配置外设 # 3. Project Location 指向 app/my_project/cubemx/ # 4. 生成代码 # 修改项目名称(如果使用独立 CMakeLists.txt) # 编辑 app/my_project/CMakeLists.txt 中的项目名称 ``` **方式二:使用根目录构建系统** 如果项目使用根目录的构建系统,只需创建基本目录结构: ```bash # 创建新项目目录 mkdir app/my_project mkdir app/my_project/cubemx # 在CubeMX中生成代码到 app/my_project/cubemx/ # 创建 app/my_project/main.c(应用代码) ``` **注意**: - 使用方式一可以独立编译,推荐新项目使用 - 使用方式二需要从根目录构建,依赖根目录的 CMakeLists.txt ### 5. 构建项目 框架支持两种构建方式: #### 方式一:从项目目录独立构建(推荐) **每个项目可以在自己的目录下独立编译**,无需从根目录构建: ```bash # 进入项目目录 cd app/10.14_PTC_Temp # 创建构建目录 mkdir build cd build # 配置CMake(会自动查找项目根目录) cmake .. -G "Ninja" -DCMAKE_BUILD_TYPE=Debug # 编译 cmake --build . # 生成的 hex 文件位于:app/10.14_PTC_Temp/build/10.14_PTC_Temp.hex ``` **优势**: - 每个项目独立管理,互不干扰 - 可以在项目目录下直接编译,无需切换到根目录 - 自动查找项目根目录(包含 boards 和 drivers 的目录) - 生成的 hex/bin 文件直接在项目 build 目录下 #### 方式二:从根目录构建(传统方式) ```bash # 在根目录创建构建目录 mkdir build cd build # 配置CMake(指定芯片系列、芯片型号和应用项目) cmake .. -DSTM32_FAMILY=f1 -DSTM32_CHIP=stm32f103rc -DAPP_PROJECT=10.14_PTC_Temp # 编译 cmake --build . # 生成的 hex 文件位于:build/app/10.14_PTC_Temp/10.14_PTC_Temp.hex ``` **参数说明**: - `STM32_FAMILY`: 芯片系列(如 f1, f4, f7, h7) - `STM32_CHIP`: 芯片型号(如 stm32f103rc, stm32f103c8)- 用于链接脚本和芯片型号宏定义 - `APP_PROJECT`: 应用项目名称(如 default, 10.14_PTC_Temp) - `CMAKE_BUILD_TYPE`: 构建类型(Debug, Release, MinSizeRel, RelWithDebInfo) **注意**:如果项目目录下有独立的 `CMakeLists.txt`(自动查找根目录),推荐使用方式一。 ### 6. 初始化代码位置 **重要**:初始化代码应该在**应用层(app/)**的`main.c`中调用: ```c int main(void) { /* CubeMX生成的初始化函数 */ HAL_Init(); SystemClock_Config(); // CubeMX生成 MX_GPIO_Init(); // CubeMX生成 MX_USART1_UART_Init(); // CubeMX生成 /* 你的应用代码 */ // ... } ``` ### 7. 烧录 生成的固件文件位置: **方式一(项目目录构建)**: - `app/${PROJECT}/build/${PROJECT_NAME}.hex` - 十六进制文件 - `app/${PROJECT}/build/${PROJECT_NAME}.bin` - 二进制文件 - `app/${PROJECT}/build/${PROJECT_NAME}.elf.elf` - ELF文件 **方式二(根目录构建)**: - `build/app/${PROJECT}/${PROJECT_NAME}.hex` - 十六进制文件 - `build/app/${PROJECT}/${PROJECT_NAME}.bin` - 二进制文件 - `build/app/${PROJECT}/${PROJECT_NAME}.elf.elf` - ELF文件 使用ST-Link或其他烧录工具烧录 `.hex` 或 `.bin` 文件。 **编译输出示例**: ``` Memory region Used Size Region Size %age Used RAM: 10160 B 48 KB 20.67% FLASH: 14880 B 256 KB 5.68% ``` ## 📖 框架架构 ### 分层设计 ``` ┌─────────────────────────────────┐ │ 应用层 (app/) │ ← 用户应用程序 + CubeMX初始化代码 ├─────────────────────────────────┤ │ 组件层 (components/) │ ← 可复用功能模块(LED、按键等) ├─────────────────────────────────┤ │ 驱动层 (drivers/) │ ← 外设驱动封装(GPIO、UART等) ├─────────────────────────────────┤ │ 板级支持包 (boards/) │ ← 系列级BSP + HAL底层驱动 ├─────────────────────────────────┤ │ STM32Cube软件包 │ ← HAL驱动(按系列) └─────────────────────────────────┘ ``` ### 架构特点 **按芯片系列组织**: - **boards/STM32CubeF1/**:F1系列所有芯片的HAL底层驱动 - **boards/f1/**:F1系列BSP,适用于F1系列所有芯片 - **boards/f1/linker/**:具体芯片的链接脚本(按芯片型号) - **boards/f1/config/**:具体芯片的配置文件(可选,按芯片型号) **优势**: - F1系列所有芯片共享同一套HAL驱动和BSP代码 - 同一系列内切换芯片只需更换链接脚本 - 符合STM32Cube软件包的实际结构 ### 使用CubeMX生成的代码 #### 1. 初始化代码在应用层 **所有初始化代码应该在应用层(app/)的main.c中调用**: ```c int main(void) { /* HAL库初始化 */ HAL_Init(); /* CubeMX生成的初始化函数 */ SystemClock_Config(); // 系统时钟配置 MX_GPIO_Init(); // GPIO初始化 MX_USART1_UART_Init(); // UART初始化(如果配置了) // ... 其他外设初始化 /* 应用代码 */ // ... } ``` **架构说明**: - **boards层**:只提供HAL底层驱动(系列级别)和板级工具函数 - **app层**:包含CubeMX生成的初始化代码(项目特定)和应用业务逻辑 #### 2. 使用CubeMX生成的HAL句柄 **推荐方式**:直接使用CubeMX生成的HAL句柄: ```c #include "uart_driver.h" // CubeMX生成的句柄(在main.c中声明) extern UART_HandleTypeDef huart1; // 使用驱动层封装 uart_handle_t uart1; uart_init_from_cubemx(&uart1, &huart1); // 使用CubeMX句柄 uart_send_string(&uart1, "Hello!\r\n"); ``` **驱动层会自动识别CubeMX生成的句柄**,无需重复初始化。 ## 🔧 配置选项 在 `cmake/build-config.cmake` 中可以配置: - `ENABLE_DEBUG`: 启用调试输出 - `ENABLE_ASSERT`: 启用断言 - `ENABLE_FREERTOS`: 启用FreeRTOS支持(从`boards/STM32CubeF1/Middlewares/Third_Party/FreeRTOS/`引用) - `ENABLE_LWIP`: 启用LWIP协议栈(从`boards/STM32CubeF1/Middlewares/Third_Party/LwIP/`引用) - `ENABLE_FATFS`: 启用FatFS文件系统(从`boards/STM32CubeF1/Middlewares/Third_Party/FatFs/`引用) 使用CMake配置: ```bash cmake .. -DENABLE_FREERTOS=ON ``` **说明**: - 中间件从对应系列的STM32Cube软件包的Middlewares目录中引用 - 框架会自动配置相应的包含目录和源文件 - 无需手动配置中间件路径 ## 📝 添加新芯片系列支持 1. 在 `boards/` 目录下放置STM32Cube软件包(如 `boards/STM32CubeF4/`) 2. 修改根 `CMakeLists.txt`,框架会自动识别新系列(已支持自动识别) 3. 框架会自动查找并使用新系列的HAL驱动 **说明**: - 框架根据 `STM32_FAMILY` 变量自动查找 `boards/STM32Cube${FAMILY}/` 目录 - 无需创建额外的BSP目录,系统工具函数在`drivers/system/`中共享 - 链接脚本由CubeMX在各项目的`cubemx/`目录中生成 ## 📝 在同一系列内使用不同芯片 如果在同一系列内使用不同芯片(如从STM32F103RC切换到STM32F103C8): 1. **HAL驱动**:无需更改,F1系列所有芯片共享 2. **链接脚本**:由CubeMX在项目生成时自动创建,位于各项目的`cubemx/`目录 3. **构建时指定**:`cmake .. -DSTM32_FAMILY=f1 -DSTM32_CHIP=stm32f103c8` **注意**:链接脚本由CubeMX生成,每个项目独立管理。 ## 🛠️ 构建配置 ### 指定芯片系列和型号 ```bash cmake .. -DSTM32_FAMILY=f1 -DSTM32_CHIP=stm32f103rc ``` ### 指定构建类型 ```bash cmake .. -DCMAKE_BUILD_TYPE=Debug # 或 Release ``` ### 交叉编译工具链路径 **Windows**: 工具链默认路径在 `cmake/toolchain-arm-none-eabi.cmake` 中配置: ```cmake set(TOOLCHAIN_PREFIX "C:/Program Files (x86)/GNU Arm Embedded Toolchain/10 2021.10/bin") ``` **Linux/Mac**: 设置环境变量: ```bash export ARM_TOOLCHAIN_PATH=/usr/local/arm-gcc/bin ``` 或在 `cmake/toolchain-arm-none-eabi.cmake` 中修改默认路径。 **工具链要求**: - `arm-none-eabi-gcc` - C编译器 - `arm-none-eabi-g++` - C++编译器 - `arm-none-eabi-objcopy` - 用于生成 hex/bin 文件 - `arm-none-eabi-size` - 用于显示内存使用情况 ## 📚 目录说明 ### boards/ STM32Cube官方软件包(HAL驱动和中间件): - **`STM32CubeF1/`**: STM32CubeF1软件包(F1系列) - `Drivers/STM32F1xx_HAL_Driver/`: F1系列HAL底层驱动(所有F1芯片共享) - `Drivers/CMSIS/`: CMSIS核心文件 - `Middlewares/`: 中间件目录 - `Third_Party/FreeRTOS/`: FreeRTOS实时操作系统 - `Third_Party/FatFs/`: FatFS文件系统 - `Third_Party/LwIP/`: LWIP网络协议栈 - `ST/`: ST官方中间件(USB库等) **说明**: - **系列级别**:按芯片系列(F1、F4等)组织STM32Cube软件包 - **HAL驱动**:每个系列一个STM32Cube软件包,该系列所有芯片共享 - **中间件**:统一从对应系列的Middlewares目录引用,通过CMake选项启用 - **链接脚本**:由CubeMX在各应用项目的`cubemx/`目录中生成 - **不包含BSP**:板级工具函数已整合到drivers/system驱动中 ### app/ 应用层,每个项目一个目录: - `cubemx/`: CubeMX生成的初始化代码(项目特定) - `Src/`: 初始化函数、中断处理等 - `Inc/`: CubeMX生成的头文件 - `main.c`: 应用主程序和业务逻辑 **注意**:每个项目可以有独立的CubeMX配置,初始化代码在各自的`cubemx/`目录下。 ### drivers/ 外设驱动封装,提供统一的API接口: - `system/`: 系统驱动(延时、时钟获取等工具函数) - `gpio/`: GPIO驱动 - `uart/`: UART驱动 - `spi/`: SPI驱动 - `i2c/`: I2C驱动 - `timer/`: 定时器驱动 - `adc/`: ADC驱动 ### components/ 可复用的功能组件: - `led/`: LED组件 - `button/`: 按键组件 ### middleware配置 中间件从对应系列的STM32Cube软件包的Middlewares目录中引用: - **FreeRTOS**: `boards/STM32CubeF1/Middlewares/Third_Party/FreeRTOS/` - **FatFS**: `boards/STM32CubeF1/Middlewares/Third_Party/FatFs/` - **LWIP**: `boards/STM32CubeF1/Middlewares/Third_Party/LwIP/` **说明**: - 中间件统一从STM32Cube软件包中引用,无需单独的middleware目录 - 通过CMake选项启用:`cmake .. -DENABLE_FREERTOS=ON` - 框架会自动配置相应的包含目录和源文件 ## 💡 开发建议 1. **始终使用CubeMX生成初始化代码**:时钟、GPIO、外设配置等 2. **通过驱动层使用外设**:不要直接调用HAL函数,使用驱动层封装 3. **使用组件层实现功能**:提高代码复用性 4. **保持分层清晰**:应用层 → 组件层 → 驱动层 → HAL驱动层 5. **在项目目录下独立编译**:每个项目维护自己的 build 目录,便于管理 6. **启用所需 HAL 模块**:在 `cubemx/Inc/stm32f1xx_hal_conf.h` 中启用需要的 HAL 模块(如 `HAL_I2C_MODULE_ENABLED`、`HAL_SPI_MODULE_ENABLED` 等) ## ⚠️ 注意事项 1. **代码位置**: - **HAL底层驱动**:放在 `boards/STM32CubeF1/` 目录下,F1系列所有芯片共享 - **CubeMX初始化代码**:放在 `app/${PROJECT}/cubemx/` 目录下,每个项目独立 - **链接脚本**:由CubeMX生成,位于各项目的`cubemx/`目录或项目根目录 2. **架构设计**: - 框架按**芯片系列**组织HAL驱动(F1、F4等),而不是具体芯片型号 - BSP功能整合到`drivers/system/`驱动层,保持架构简洁 - 链接脚本由CubeMX管理,每个项目独立 3. **修改配置**: - 如果修改了某个项目的CubeMX配置,只需要重新生成该项目的代码 - HAL底层驱动按系列管理,同一系列内切换芯片无需更改HAL驱动 - 切换芯片系列时需要对应的STM32Cube软件包 4. **用户代码**: - 不要在CubeMX生成的代码中手动添加用户代码(USER CODE区域除外) - 应用业务逻辑应该放在各项目的 `main.c` 中 - 使用`System_DelayMs()`替代`Board_DelayMs()`,使用`System_GetClockFreq()`替代`Board_GetSysClockFreq()` 5. **链接脚本**: - 由CubeMX自动生成,位于各项目的`cubemx/`目录 - 框架会自动查找并使用链接脚本 - 如果链接脚本有语法错误,检查 `ORIGIN()`、`LENGTH()` 和内存区域声明 6. **HAL模块配置**: - 在 `cubemx/Inc/stm32f1xx_hal_conf.h` 中启用需要的 HAL 模块 - 例如:`#define HAL_I2C_MODULE_ENABLED`、`#define HAL_SPI_MODULE_ENABLED` 等 - 如果使用 FreeRTOS,需要在 CMakeLists.txt 中设置 `ENABLE_FREERTOS=ON` 7. **独立编译项目**: - 项目目录下的 `CMakeLists.txt` 会自动向上查找包含 `boards/` 和 `drivers/` 的根目录 - 确保项目目录结构正确,框架会自动定位依赖 - 生成的 hex 文件在项目自己的 `build/` 目录下 ## 🔍 常见问题 ### 1. 编译时找不到 arm-none-eabi-gcc **问题**:`CMake Error: Could not find CMAKE_C_COMPILER` **解决方案**: - 检查工具链是否已安装 - 在 `cmake/toolchain-arm-none-eabi.cmake` 中修改 `TOOLCHAIN_PREFIX` 路径 - 或设置环境变量 `ARM_TOOLCHAIN_PATH` ### 2. 找不到 HAL 头文件 **问题**:`fatal error: stm32f1xx_hal_conf.h: No such file or directory` **解决方案**: - 确保 CubeMX 已生成初始化代码到 `app/${PROJECT}/cubemx/` 目录 - 检查 `cubemx/Inc/stm32f1xx_hal_conf.h` 文件是否存在 - 在 `stm32f1xx_hal_conf.h` 开头添加 `#include "stm32f1xx.h"` ### 3. HAL 模块未启用 **问题**:`undefined reference to 'HAL_I2C_Init'` 或类似错误 **解决方案**: - 在 `cubemx/Inc/stm32f1xx_hal_conf.h` 中取消注释对应的模块定义 - 例如:`#define HAL_I2C_MODULE_ENABLED`、`#define HAL_SPI_MODULE_ENABLED` 等 ### 4. 链接脚本错误 **问题**:`linker script syntax error` 或 `undefined reference to `_estack'` **解决方案**: - 检查链接脚本中的内存区域定义 - 确保 `_estack = ORIGIN(RAM) + LENGTH(RAM);` 格式正确 - 确保 `.data`、`.bss` 等段正确映射到 RAM 和 FLASH ### 5. CMake 使用错误的编译器 **问题**:CMake 检测到 MinGW GCC 或 MSVC 而不是 arm-none-eabi-gcc **解决方案**: - 确保在 `project()` 命令之前包含工具链文件 - 使用 `-DCMAKE_TOOLCHAIN_FILE` 显式指定工具链文件 - 推荐使用 Ninja 或 MinGW Makefiles 生成器,而不是 Visual Studio ### 6. FreeRTOS 相关错误 **问题**:`cmsis_os.h: No such file or directory` 或 `SysTick undeclared` **解决方案**: - 在项目的 `CMakeLists.txt` 中设置 `set(ENABLE_FREERTOS ON)` - 确保 `FreeRTOSConfig.h` 在 `cubemx/Inc/` 目录下 - 检查 `cmake/middleware-config.cmake` 中的 FreeRTOS 配置 ### 7. 驱动层宏定义冲突 **问题**:`expected identifier before '(' token` 在 HAL 头文件中 **解决方案**: - 检查驱动层头文件中的宏定义是否与 HAL 库冲突 - 使用类型别名(`typedef`)而不是宏定义来避免冲突 - 参考 `drivers/gpio/gpio_driver.h` 的实现方式 ### 8. 找不到 hex 文件 **问题**:编译成功但找不到 `.hex` 文件 **解决方案**: - 检查 `arm-none-eabi-objcopy` 是否可用 - 检查 `CMakeLists.txt` 中的 `add_custom_command` 是否正确使用生成器表达式 - 确保使用 `$` 和 `$` ## 📄 许可证 [根据项目需求添加许可证信息] ## 🤝 贡献 欢迎提交Issue和Pull Request! ## 📞 技术支持 如有问题,请查看: 1. 常见问题章节 2. 项目 Issues 3. 框架文档