1. 创建第一个RTOS任务
任务目标
在STM32裸机工程基础上集成FreeRTOS,创建第一个LED闪烁任务。通过该任务掌握三个核心概念:任务创建(xTaskCreate)、任务调度(vTaskStartScheduler)和任务延时(vTaskDelay)。任务运行后,开发板上的LED以500ms周期翻转,证明RTOS调度器已正常启动并运行用户任务。
环境与依赖
- 硬件:任意STM32开发板(以STM32F103C8T6为例),板载LED接PC13(高电平熄灭,低电平点亮)
- 软件:STM32CubeIDE 或 Keil MDK,已移植FreeRTOS V10.x(通过CubeMX生成或手动移植均可)
- 前提:系统时钟已配置(如72MHz),
HAL_Init()和SystemClock_Config()已在main()中完成
完整实现
以下代码是任务的全部核心逻辑,可直接放入main.c中对应的用户代码区。若使用CubeMX生成工程,需在main()函数中调用MX_FREERTOS_Init()之前,先完成硬件初始化和任务创建。
/* 头文件包含 */
#include "FreeRTOS.h"
#include "task.h"
/* LED引脚定义(以PC13为例) */
#define LED_GPIO_PORT GPIOC
#define LED_PIN GPIO_PIN_13
/* 任务函数声明 */
void vLEDTask(void *pvParameters);
/* 在main()函数中,完成HAL初始化和时钟配置后添加: */
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init(); /* 若使用CubeMX生成的GPIO初始化 */
/* 创建LED闪烁任务 */
xTaskCreate(vLEDTask, "LED", 128, NULL, 1, NULL);
/* 启动调度器(此函数不会返回) */
vTaskStartScheduler();
/* 正常情况下不会执行到这里 */
while (1) {}
}
/* LED任务函数 */
void vLEDTask(void *pvParameters)
{
/* 将PC13配置为推挽输出(若未在MX_GPIO_Init中配置) */
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitStruct.Pin = LED_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(LED_GPIO_PORT, &GPIO_InitStruct);
/* 初始状态:点亮LED(PC13低电平有效) */
HAL_GPIO_WritePin(LED_GPIO_PORT, LED_PIN, GPIO_PIN_RESET);
for (;;)
{
/* 翻转LED状态 */
HAL_GPIO_TogglePin(LED_GPIO_PORT, LED_PIN);
/* 延时500ms(1个tick = 1ms,需在FreeRTOSConfig.h中配置configTICK_RATE_HZ为1000) */
vTaskDelay(pdMS_TO_TICKS(500));
}
}
关键配置说明
- 任务栈大小:128字(512字节),足以容纳HAL_GPIO调用链,若使用更复杂的驱动需适当增大
- 任务优先级:设为1(最低优先级),单任务场景下不影响运行
- 系统节拍:确保
FreeRTOSConfig.h中configTICK_RATE_HZ为1000,否则pdMS_TO_TICKS(500)换算会不准确 - 内存管理:需在工程中包含
heap_4.c(或任意heap实现文件),否则链接报错
运行与验证
- 编译工程并烧录到开发板
- 观察板载LED:应看到LED以约1Hz频率闪烁(亮500ms,灭500ms)
- 若LED不闪烁,按以下顺序排查:
- 检查
vTaskStartScheduler()是否被调用——调度器未启动时任务不会执行 - 检查
xTaskCreate返回值是否为pdPASS(可在调试器中查看) - 确认
HAL_GPIO_TogglePin操作的引脚与硬件连接一致 - 检查FreeRTOS的
configMINIMAL_STACK_SIZE是否足够(当前128字通常安全)
- 检查
通过标准:LED持续以500ms间隔翻转,且系统不进入HardFault。在调试器中暂停时,可看到当前执行位置在vLEDTask的vTaskDelay调用处,证明任务被调度器正常管理。
常见问题
- 编译报错“undefined reference to vTaskStartScheduler”:未将FreeRTOS源码(tasks.c、queue.c、list.c、port.c、heap_x.c)加入工程
- 任务不执行但系统无异常:检查
xTaskCreate是否在vTaskStartScheduler之前调用,且参数NULL作为任务参数时,任务函数内不得解引用该指针 - LED常亮或常灭:确认
HAL_GPIO_TogglePin确实在循环内被执行——若任务因栈溢出而崩溃,可启用configCHECK_FOR_STACK_OVERFLOW钩子函数定位