目录
[二、通过 STM32CubeMX 配置 FreeRTOS](#二、通过 STM32CubeMX 配置 FreeRTOS)
[1. 新建工程并选择芯片](#1. 新建工程并选择芯片)
[2. 配置基础外设](#2. 配置基础外设)
[3. 启用并配置 FreeRTOS](#3. 启用并配置 FreeRTOS)
[4. 生成工程代码](#4. 生成工程代码)
[1. 基本任务示例(LED 闪烁 + UART 打印)](#1. 基本任务示例(LED 闪烁 + UART 打印))
[步骤 1:在 CubeMX 中添加任务(或手动创建)](#步骤 1:在 CubeMX 中添加任务(或手动创建))
[步骤 2:实现任务函数](#步骤 2:实现任务函数)
[步骤 3:启动 FreeRTOS 调度器](#步骤 3:启动 FreeRTOS 调度器)
[2. 任务间通信示例(队列 / 信号量)](#2. 任务间通信示例(队列 / 信号量))
在 STM32 上使用 FreeRTOS 主要分为环境搭建 、移植 / 配置 、代码开发 和调试几个步骤。以下是详细的实操指南,以 STM32CubeMX + Keil MDK 为例(也适用于 STM32CubeIDE):
一、环境准备
- 硬件:任意 STM32 开发板(如 STM32F103、STM32F407、STM32L431 等)。
- 软件 :
- STM32CubeMX(用于配置芯片和 FreeRTOS);
- Keil MDK/STM32CubeIDE(用于代码编写和编译);
- FreeRTOS 源码(CubeMX 可自动集成,无需手动下载)。
二、通过 STM32CubeMX 配置 FreeRTOS
STM32CubeMX 已内置 FreeRTOS 适配层,可一键配置,无需手动移植,大幅简化流程。
1. 新建工程并选择芯片
- 打开 STM32CubeMX,选择 "New Project",搜索并选择目标 STM32 型号(如 STM32F407ZG)。
- 选择启动模式(默认即可),进入配置界面。
2. 配置基础外设
- 启用时钟:配置 HSE(外部晶振)或 HSI(内部晶振),设置系统时钟(如 F407 设为 168MHz)。
- 启用调试接口:配置 SWD/JTAG(如 "Serial Wire"),用于后续调试。
- 可选:启用 GPIO、UART 等外设(如 UART1 用于打印日志)。
3. 启用并配置 FreeRTOS
- 在 "Middleware" 中选择FreeRTOS ,点击 "Enabled" 启用。
- 注意:FreeRTOS 有两个版本可选:
FreeRTOSv10(标准版)和FreeRTOS-Kernel(最新版),按需选择。
- 注意:FreeRTOS 有两个版本可选:
- 配置 FreeRTOS 核心参数:
- Task and Queue Settings :可直接创建任务(如
StartDefaultTask),设置任务名称、优先级、堆栈大小、入口函数。 - Config Parameters :关键配置(建议保持默认,或按需修改):
configUSE_PREEMPTION:启用抢占式调度(必选,设为1);configMAX_PRIORITIES:最大优先级数(如设为5);configTICK_RATE_HZ:系统节拍频率(默认 1000Hz,即 1ms/tick);configMINIMAL_STACK_SIZE:空闲任务堆栈大小(默认即可);configUSE_IDLE_HOOK/configUSE_TICK_HOOK:是否启用空闲 / 节拍钩子函数(按需开启)。
- Task and Queue Settings :可直接创建任务(如
4. 生成工程代码
- 点击 "Project Manager",设置工程名称、路径、编译器(如
MDK-ARM)。 - 点击 "Generate Code",CubeMX 会自动生成包含 FreeRTOS 的工程框架(已完成底层移植,无需手动修改启动文件或中断向量)。
三、代码开发:创建任务与功能实现
打开生成的工程(如 Keil MDK),核心开发围绕任务创建 、任务通信 和外设操作展开。
1. 基本任务示例(LED 闪烁 + UART 打印)
假设已配置 LED(PA5)和 UART1(用于日志输出),创建两个任务:
LED_Task:控制 LED 周期性闪烁;UART_Task:周期性打印日志。
步骤 1:在 CubeMX 中添加任务(或手动创建)
- 回到 CubeMX 的 FreeRTOS 配置界面,添加新任务:
- 任务 1:名称
LED_Task,优先级2,堆栈大小128,入口函数LED_Task_Func; - 任务 2:名称
UART_Task,优先级1,堆栈大小256,入口函数UART_Task_Func;
- 任务 1:名称
- 重新生成代码,CubeMX 会自动在
freertos.c中生成任务声明。
步骤 2:实现任务函数
在freertos.c中找到任务入口函数,编写业务逻辑:
c
运行
/* LED任务:每隔500ms翻转LED */
void LED_Task_Func(void *argument)
{
for(;;)
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); // 翻转LED引脚
osDelay(500); // FreeRTOS延时函数(单位:ms)
}
}
/* UART任务:每隔1s打印日志 */
void UART_Task_Func(void *argument)
{
uint32_t count = 0;
for(;;)
{
HAL_UART_Transmit(&huart1, (uint8_t*)("UART Task: Count = %d\r\n", count), strlen("UART Task: Count = %d\r\n"), 100);
count++;
osDelay(1000);
}
}
步骤 3:启动 FreeRTOS 调度器
CubeMX 已自动在main.c中生成启动代码,无需手动修改:
c
运行
int main(void)
{
/* 初始化硬件:HAL库初始化、时钟、外设等 */
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
/* 创建任务并启动调度器 */
osKernelInitialize(); // 初始化FreeRTOS内核
osThreadNew(LED_Task_Func, NULL, &LED_Task_attributes); // 创建LED任务
osThreadNew(UART_Task_Func, NULL, &UART_Task_attributes); // 创建UART任务
osKernelStart(); // 启动调度器(从此开始任务调度)
/* 调度器启动后,main函数不会执行到这里 */
while (1)
{
}
}
2. 任务间通信示例(队列 / 信号量)
如果需要任务间交互(如 UART 接收数据后通知 LED 任务),可使用 FreeRTOS 的队列或信号量。
示例:队列传递数据
-
在
freertos.c中定义队列句柄:c
运行
osMessageQueueId_t dataQueueHandle; // 队列句柄 -
在 CubeMX 中配置队列(或手动创建): c
运行
// 在osKernelInitialize()后创建队列(可存储5个uint32_t数据) dataQueueHandle = osMessageQueueNew(5, sizeof(uint32_t), NULL); -
UART 任务发送数据到队列,LED 任务接收数据: c
运行
// UART任务发送数据 void UART_Task_Func(void *argument) { uint32_t sendData = 123; for(;;) { osMessageQueuePut(dataQueueHandle, &sendData, 0, osWaitForever); // 发送数据 sendData++; osDelay(1000); } } // LED任务接收数据 void LED_Task_Func(void *argument) { uint32_t recvData; for(;;) { if(osMessageQueueGet(dataQueueHandle, &recvData, NULL, osWaitForever) == osOK) { HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); // 打印接收的数据(需实现UART打印) printf("Received data: %d\r\n", recvData); } } }
四、编译与调试
- 编译工程:在 Keil MDK 中点击 "Build",确保无错误(若提示堆栈不足,可增大任务堆栈或 Heap 大小)。
- 下载程序:连接开发板,点击 "Download" 将程序烧录到 STM32。
- 调试 :
- 启用调试模式(Keil 中点击 "Debug"),可查看任务状态、堆栈使用、变量值等;
- 通过 UART 助手查看日志输出,或观察 LED 闪烁是否符合预期。
五、关键注意事项
-
中断与 FreeRTOS 兼容:
- 若使用 HAL 库中断(如 UART 接收中断),需在中断服务函数中使用 FreeRTOS 的中断安全 API(如
xQueueSendFromISR、xSemaphoreGiveFromISR)。 - 配置中断优先级:确保 FreeRTOS 的 SysTick 中断优先级低于其他外设中断(通过
NVIC_PriorityGroupConfig设置,如分组 4,抢占优先级 0~15)。
- 若使用 HAL 库中断(如 UART 接收中断),需在中断服务函数中使用 FreeRTOS 的中断安全 API(如
-
内存管理:
- CubeMX 默认使用
heap_4内存分配策略(适合大多数场景),可在FreeRTOSConfig.h中修改configTOTAL_HEAP_SIZE调整堆大小。
- CubeMX 默认使用
-
低功耗优化:
- 若需低功耗,启用
configUSE_TICKLESS_IDLE(在 FreeRTOSConfig.h 中设为 1),结合 STM32 的低功耗模式(如 STOP 模式)。
- 若需低功耗,启用
六、常见问题排查
- 任务无法启动 :检查
osKernelStart()是否调用,任务优先级是否合理(空闲任务优先级最低)。 - 串口打印乱码:检查 UART 波特率配置,确保时钟树正确。
- 堆栈溢出 :通过
vTaskList()或vTaskGetRunTimeStats()查看堆栈使用,增大堆栈大小。
通过以上步骤,即可在 STM32 上快速实现 FreeRTOS 的基础应用。如需更复杂的功能(如软件定时器、事件组、互斥锁),可参考 FreeRTOS 官方文档或 STM32CubeMX 的配置选项。