一、简介
基于 STM32CubeMX + CLion 的 STM32 开发环境,是一种融合了 "图形化配置效率" 与 "现代 IDE 开发体验" 的嵌入式开发方案。它以 STM32CubeMX 的硬件配置自动化为基础,搭配 CLion 的智能代码编辑、调试能力,解决了传统 STM32 开发(如 Keil MDK)中 "配置繁琐、代码提示弱、跨平台性差" 的痛点,尤其适合习惯现代 C/C++ 开发流程、追求高效调试的开发者。
1.1 核心工具定位与分工
该环境的核心是 "STM32CubeMX 负责 "硬件配置与代码生成",CLion 负责 "代码编写、编译与调试" ",两者通过标准化的工程文件联动,形成完整开发闭环:
工具 | 核心功能 | 解决的痛点 |
---|---|---|
STM32CubeMX | 1. 图形化选择芯片型号、配置引脚(GPIO、SPI、UART 等)、时钟树、外设参数;2. 自动生成初始化代码(基于 HAL/LL 库);3. 生成支持 CLion 的工程模板(如 Makefile/CMake)。 | 避免手动编写繁琐的外设初始化代码、时钟树计算,降低硬件配置出错率。 |
CLion | 1. 智能代码编辑(语法高亮、自动补全、重构、跳转);2. 集成编译工具链(ARM-GCC);3. 支持硬件调试(配合 OpenOCD/J-Link);4. 跨平台(Windows/macOS/Linux)。 | 解决传统 IDE(如 Keil)代码提示弱、不支持跨平台、调试界面不直观的问题。 |
1.2 环境搭建核心依赖
要让两者联动,需额外配置 "编译工具链" 和 "调试工具",形成完整链路:
-
编译工具链:ARM GNU Toolchain 用于将 C/C++ 代码编译为 STM32 可执行的二进制文件(.elf/.hex),需下载对应平台的工具链(如
arm-none-eabi-gcc
)并配置环境变量。 -
调试工具:OpenOCD + 调试器
- OpenOCD:开源调试工具,负责与硬件调试器(如 J-Link、ST-Link)通信,实现 "下载程序、断点调试、查看寄存器" 等功能;
- 硬件调试器:常用 ST 官方的 ST-Link(低成本,支持大部分 STM32)或 Segger 的 J-Link(兼容性更强,支持复杂调试)。
-
驱动支持安装调试器的 USB 驱动(如 ST-Link 驱动、J-Link 驱动),确保电脑能识别硬件。
1.3 典型开发流程(以 "GPIO 点亮 LED" 为例)
-
Step 1:STM32CubeMX 配置与代码生成
- 打开 STM32CubeMX,选择目标芯片(如 STM32F103C8T6);
- 配置硬件:
- 引脚:将 PA5(LED 引脚)设为 "GPIO_Output";
- 时钟树:将 HSE(外部高速时钟)设为 8MHz,系统时钟(SYSCLK)设为 72MHz;
- 工程配置:
- 选择 "Toolchain/IDE" 为 "Makefile"(CLion 支持 Makefile/CMake,Makefile 更简单);
- 勾选 "Generate peripheral initialization as a pair of .c/.h files per peripheral"(模块化代码);
- 点击 "Generate Code" 生成工程文件(包含 HAL 库、初始化代码、Makefile)。
-
Step 2:CLion 导入工程并编写业务代码
-
打开 CLion,选择 "Open" 导入 STM32CubeMX 生成的工程文件夹;
-
CLion 会自动识别 Makefile,无需额外配置编译规则;
-
在
main.c
的while(1)
循环中添加 LED 翻转代码:HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); // 翻转PA5电平 HAL_Delay(500); // 延时500ms
-
-
Step 3:编译与下载
- 点击 CLion 右上角的 "Build"(或快捷键
Ctrl+F9
),调用 ARM-GCC 编译工程,生成*.elf
文件; - 连接调试器(如 ST-Link)到 STM32 开发板,在 CLion 中配置调试:
- 进入 "Run> Edit Configurations",选择 "OpenOCD Download & Run";
- 选择对应芯片的 OpenOCD 配置文件(如
stm32f1x.cfg
,通常 OpenOCD 已自带);
- 点击 "Debug"(或快捷键
Shift+F9
),CLion 会通过 OpenOCD 将程序下载到 STM32,并进入调试模式。
- 点击 CLion 右上角的 "Build"(或快捷键
-
Step 4:调试与验证
- 在
HAL_GPIO_TogglePin
行设置断点,调试时程序会暂停在断点处; - 通过 CLion 的调试面板查看 "GPIO 寄存器状态""变量值",或单步执行(F8)观察 LED 翻转逻辑;
- 调试完成后,点击 "Run"(或快捷键
Shift+F10
)直接运行程序,LED 会以 500ms 周期闪烁。
- 在
1.4 该方案的优势与局限性
优势:
- 开发体验现代 :CLion 的智能补全(如输入
HAL_GPIO_
会自动提示所有 GPIO 相关函数)、代码跳转(点击函数名跳转到定义)大幅提升编码效率; - 跨平台自由:Windows/macOS/Linux 均可使用,解决了 Keil MDK 仅支持 Windows 的问题(尤其适合 Mac 用户);
- 开源生态友好:依赖的 ARM-GCC、OpenOCD 均为开源工具,无需付费(对比 Keil 需要 license);
- 代码可移植性强:STM32CubeMX 生成的 HAL 库代码标准化,切换芯片时只需重新配置生成,业务代码基本无需修改。
局限性:
- 调试功能不如 Keil 全面:对某些复杂调试需求(如 Trace 跟踪、功耗分析)支持较弱,Keil MDK 在 STM32 专属调试功能上更成熟;
- 入门门槛略高:需手动配置工具链、OpenOCD,对新手而言比 "一键安装 Keil" 更复杂;
- 部分老芯片支持有限:STM32CubeMX 对非常早期的 STM32 型号(如 STM32F100)支持不足,更适合近 5 年推出的芯片(如 F1/F4/F7/H7/L4 系列)。
1.5 适用人群
- 习惯现代 C/C++ 开发(如使用过 VS Code、Qt Creator)的开发者;
- 需要跨平台开发(如在 Mac 上开发 STM32)的用户;
- 追求开源工具链、避免商业软件依赖的团队或个人;
- 以 HAL 库为主要开发框架的 STM32 项目(若用标准库,STM32CubeMX 支持有限,需手动适配)。
综上,STM32CubeMX+CLion 是一套 "高效、现代、跨平台" 的 STM32 开发方案,尤其适合对开发体验有要求的中高级开发者,或需要摆脱 Keil 依赖的场景。
二、工程创建
2.1 使用STM32CubeMX创建工程cmake工程,其他的STM32工程的配置与keil的配置一样,主要是针对工程配置。

2.2 工程配置
选择cmake


2.3 导入工程,打开文件夹


取消勾选默认的Debug

勾选Debug预设

2.4 交换位置
# Core project settings
project(${CMAKE_PROJECT_NAME})
message("Build type: " ${CMAKE_BUILD_TYPE})
# Enable CMake support for ASM and C languages
enable_language(C ASM)


2.5 下载工具链
Arm GNU 工具链下载 -- Arm Developer





2.6 进入设置,配置工具链

2.7 配置OpenOCD




选择适合stm32f103c8t6的下载配置


2.8 先编译测试


三、编写、编译代码
3.1 测试烧写,注意下载STlink驱动,烧写成功
bash
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);
HAL_Delay(100);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);
HAL_Delay(100);
bash
D:\DevEnv\CLion_Toolchain\openocd-v0.12.0-i686-w64-mingw32\bin\openocd.exe -s D:\DevEnv\CLion_Toolchain\openocd-v0.12.0-i686-w64-mingw32\share\openocd\scripts -f D:\DevEnv\CLion_Toolchain\stm32f1_stlink.cfg -c "tcl_port disabled" -c "gdb_port disabled" -c "tcl_port disabled" -c "program \"E:/MDK_Projects/STM32CubeMX_Projects/STM32MX_Examples_Workspaces/clion_test/build/Debug/clion_test.elf\"" -c reset -c shutdown
[0m[0mOpen On-Chip Debugger 0.12.0 (2023-01-14-23:37)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Info : auto-selecting first available session transport "hla_swd". To override u
se 'transport select <transport>'.
Info : The selected transport took over low-level target control. The results mi
ght differ compared to plain JTAG/SWD
none separate
Info : clock speed 1000 kHz
Info : STLINK V2J45S7 (API v2) VID:PID 0483:3748
Info : Target voltage: 3.225841
Info : [stm32f1x.cpu] Cortex-M3 r1p1 processor detected
Info : [stm32f1x.cpu] target has 6 breakpoints, 4 watchpoints
Info : gdb port disabled
[stm32f1x.cpu] halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x08000188 msp: 0x20000dc0
** Programming Started **
Info : device id = 0x20036410
Info : flash size = 64 KiB
Warn : Adding extra erase range, 0x0800123c .. 0x080013ff
** Programming Finished **
shutdown command invoked

3.2 添加mycode文件夹和bsp_led组件


bash
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "../../mycode/bsp_led/bsp_led.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
led_change();
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
bash
//
// Created by zky on 2025/10/2.
//
#include "bsp_led.h"
void led_change(void)
{
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);
HAL_Delay(50);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);
HAL_Delay(50);
}
3.3 添加cmake路径


(1)添加自定义的头文件路径和源文件路径

bash
cmake_minimum_required(VERSION 3.22)
#
# This file is generated only once,
# and is not re-generated if converter is called multiple times.
#
# User is free to modify the file as much as necessary
#
# Setup compiler settings
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS ON)
# Define the build type
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Debug")
endif()
# Set the project name
set(CMAKE_PROJECT_NAME clion_test)
# Include toolchain file
include("cmake/gcc-arm-none-eabi.cmake")
# Enable compile command to ease indexing with e.g. clangd
set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)
# Core project settings
project(${CMAKE_PROJECT_NAME})
message("Build type: " ${CMAKE_BUILD_TYPE})
# Enable CMake support for ASM and C languages
enable_language(C ASM)
# Create an executable object type
add_executable(${CMAKE_PROJECT_NAME}
mycode/bsp_led/bsp_led.h
mycode/bsp_led/bsp_led.c)
# Add STM32CubeMX generated sources
add_subdirectory(cmake/stm32cubemx)
# Link directories setup
target_link_directories(${CMAKE_PROJECT_NAME} PRIVATE
# Add user defined library search paths
)
# Add sources to executable
target_sources(${CMAKE_PROJECT_NAME} PRIVATE
# Add user sources here
mycode/bsp_led/bsp_led.c
)
# Add include paths
target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE
# Add user defined include paths
mycode/bsp_led
)
# Add project symbols (macros)
target_compile_definitions(${CMAKE_PROJECT_NAME} PRIVATE
# Add user defined symbols
)
# Add linked libraries
target_link_libraries(${CMAKE_PROJECT_NAME}
stm32cubemx
# Add user defined libraries
)
(2)编译成功,已经识别

四、实验效果
