今天体验了一把augment确实好用,记录一下
STM32 开发笔记:从环境搭建到任务调度
🛠️ 环境准备
必需工具
- STM32CubeMX:图形化配置工具,用于初始化 MCU 外设和生成基础代码
- STM32CubeCLT:包含编译工具链(arm-none-eabi-gcc)和烧录工具(STM32_Programmer_CLI)
- CMake:跨平台构建系统,用于管理项目编译流程
- OpenOCD:开源调试器(可选,用于 DAPLink 等调试器连接)
验证环境
在 PowerShell 中执行以下命令检查工具链是否安装正确:
powershell
arm-none-eabi-gcc --version # 检查GCC编译器版本
cmake --version # 检查CMake版本
STM32_Programmer_CLI --version # 检查STM32烧录工具版本
openocd --version # 检查OpenOCD版本(可选)
🎯 CubeMX 项目创建
-
创建新项目
- 打开 STM32CubeMX,通过 "File > New Project" 选择目标 MCU 型号(如 STM32G474RE)
- 配置引脚功能、外设(如 GPIO、USART、ADC 等)及系统时钟(如配置为 72MHz)
- 在 "Project Manager > Toolchain/IDE" 中选择 "CMake" 作为工具链,点击 "GENERATE CODE" 生成项目
-
关键配置要点
- 确保时钟树配置正确,避免频率设置错误导致芯片异常
- 外设初始化参数(如 USART 波特率、GPIO 模式)需根据需求调整
⚙️ CMake 编译
1. 项目结构说明
plaintext
your_project/
├── CMakeLists.txt # 项目构建配置文件
├── Core/
│ ├── Inc/ # 核心头文件(如main.h、stm32g4xx_hal_conf.h)
│ └── Src/ # 核心源文件(如main.c、system_stm32g4xx.c)
├── Drivers/ # ST官方驱动文件(HAL库、LL库)
└── user/
├── inc/ # 用户自定义头文件
└── src/ # 用户自定义源文件
2. 配置项目
- 使用预设配置(推荐):
powershell
cmake --preset Debug # 生成Debug配置的编译文件
- 手动配置:
powershell
cmake -B build/Debug -DCMAKE_BUILD_TYPE=Debug # 在build/Debug目录生成编译文件
3. 编译项目
powershell
cmake --build --preset Debug # 编译项目,生成.elf可执行文件
4. 生成烧录文件
powershell
# 将.elf转换为HEX格式(适用于ST-Link烧录)
arm-none-eabi-objcopy -O ihex build/Debug/项目名.elf build/Debug/项目名.hex
🔥 烧录固件
方法 1:使用 ST-Link(推荐)
powershell
# 第一步:检查ST-Link连接
STM32_Programmer_CLI -l
# 第二步:烧录固件并验证(-w:写入,-v:验证,-rst:复位芯片)
STM32_Programmer_CLI -c port=SWD -w build/Debug/项目名.hex -v -rst
方法 2:使用 DAPLink(配合 OpenOCD)
powershell
openocd -f interface/cmsis-dap.cfg -f target/stm32g4x.cfg \
-c "adapter speed 1000" \ # 设置适配器速度为1000kHz
-c "init" \ # 初始化调试器
-c "reset halt" \ # 复位芯片并暂停
-c "flash write_image erase build/Debug/项目名.hex" \ # 擦除并写入固件
-c "reset run" \ # 复位并运行程序
-c "shutdown" # 关闭OpenOCD
📁 添加用户代码
1. 创建用户目录结构
powershell
mkdir user # 创建用户代码根目录
mkdir user/inc # 用户头文件目录
mkdir user/src # 用户源文件目录
2. 更新 CMakeLists.txt
在 CMakeLists.txt 中添加用户代码路径:
cmake
# 添加头文件路径
set(MX_Include_Dirs
${CMAKE_SOURCE_DIR}/Core/Inc
${CMAKE_SOURCE_DIR}/user/inc # 新增用户头文件路径
)
# 添加源文件路径
set(MX_Application_Src
${CMAKE_SOURCE_DIR}/user/src/user.c # 新增用户源文件
)
⏰ 调度器使用
1. 调度器头文件(user_scheduler.h)
c
运行
#ifndef __USER_SCHEDULER_H__
#define __USER_SCHEDULER_H__
#include "main.h"
#define MAX_TASKS 8 // 最大任务数,可根据需求调整
// 任务结构体定义
typedef struct {
void (*task_func)(void); // 任务函数指针
uint32_t period_ms; // 任务执行周期(毫秒)
uint32_t last_run; // 上次执行时间
uint8_t enabled; // 任务使能标志
} Task_t;
// 函数声明
void Scheduler_Init(void);
void Scheduler_AddTask(void (*task_func)(void), uint32_t period_ms);
void Scheduler_Run(void);
#endif
2. 调度器实现(user_scheduler.c)
c
运行
#include "user_scheduler.h"
static Task_t tasks[MAX_TASKS]; // 任务数组
static uint8_t task_count = 0; // 任务计数器
/**
* @brief 初始化调度器
*/
void Scheduler_Init(void) {
task_count = 0;
}
/**
* @brief 添加任务到调度器
* @param task_func 任务函数指针
* @param period_ms 任务执行周期(毫秒)
*/
void Scheduler_AddTask(void (*task_func)(void), uint32_t period_ms) {
if (task_count < MAX_TASKS && task_func) {
tasks[task_count].task_func = task_func;
tasks[task_count].period_ms = period_ms;
tasks[task_count].last_run = HAL_GetTick();
tasks[task_count].enabled = 1;
task_count++;
}
}
/**
* @brief 运行调度器,检查并执行到期任务
*/
void Scheduler_Run(void) {
uint32_t current_time = HAL_GetTick();
for (uint8_t i = 0; i < task_count; i++) {
if (tasks[i].enabled && (current_time - tasks[i].last_run) >= tasks[i].period_ms) {
tasks[i].task_func(); // 执行任务函数
tasks[i].last_run = current_time; // 更新上次执行时间
}
}
}
3. 在 main 函数中使用调度器
c
运行
int main(void) {
// 系统初始化...
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
// 初始化调度器
Scheduler_Init();
// 添加任务(示例:每100ms执行一次LED闪烁任务)
Scheduler_AddTask(LED_Toggle, 100);
Scheduler_AddTask(USART_SendData, 500); // 每500ms发送一次数据
// 主循环
while (1) {
Scheduler_Run(); // 调用调度器执行任务
// 其他非周期性任务...
}
}
🔧 常见问题及解决方法
问题描述 | 解决方法 |
---|---|
编译错误:“No such file or directory” | 检查 CMakeLists.txt 中头文件和源文件路径是否正确,确保用户目录(user/inc、user/src)已正确添加 |
烧录失败:“No ST-Link detected” | 1. 检查 ST-Link 与芯片的连接(SWD 线、电源线) 2. 尝试重启 ST-Link 或更换 USB 接口 3. 改用 DAPLink+OpenOCD 烧录 |
任务不执行或执行异常 | 1. 确保在 main 函数的 while 循环中调用了Scheduler_Run() 2. 检查任务周期设置是否合理,避免周期过短导致 CPU 负载过高 3. 确认任务函数中没有死循环或长时间阻塞操作 |
📝 完整开发流程总结
- 环境搭建:安装 STM32CubeMX、STM32CubeCLT、CMake,验证工具链版本
- 项目创建:使用 CubeMX 配置 MCU 和外设,生成 CMake 项目
- 代码组织:创建 user 目录,在 CMakeLists.txt 中添加用户代码路径
- 调度器实现:编写任务调度器,管理周期性任务
- 编译测试:使用
cmake --build --preset Debug
编译项目 - 固件烧录:通过 ST-Link 或 DAPLink 将 HEX 文件烧录到芯片
- 调试优化:根据运行结果修复问题,优化任务调度逻辑