2025最新超详细FreeRTOS入门教程:第二章 FreeRTOS任务创建

摘要

在完成第一章 FreeRTOS 移植到 STM32 后,我们已经能够运行一个最小任务。本章将带你深入理解 任务(Task) 的概念、创建方式、运行机制和调度策略。
任务是 FreeRTOS 的核心,掌握任务的创建和使用,意味着你已经正式踏入 RTOS 世界。
2025最新超详细FreeRTOS入门教程


一、任务的基本概念

📌 在 裸机系统 中,程序代码通常放在 while(1) 循环中顺序执行,而 FreeRTOS 将应用划分为 多个任务,每个任务都可以看作一个独立的线程,内核负责任务的调度和切换。

特点

  • 每个任务都有自己的 堆栈空间
  • 内核根据 优先级调度算法 切换任务
  • 每个任务都像一个无限循环,通常以 for(;;)while(1) 形式实现
裸机程序
单一循环
FreeRTOS程序
任务1: LED闪烁
任务2: 串口打印
任务3: 数据处理

二、任务创建 API

FreeRTOS 提供了 xTaskCreate()xTaskCreateStatic() 两种方式。

1. 动态创建任务

BaseType_t xTaskCreate(
   TaskFunction_t pvTaskCode,      // 任务函数
   const char * const pcName,      // 任务名字
   configSTACK_DEPTH_TYPE usStackDepth, // 栈深度
   void *pvParameters,             // 任务参数
   UBaseType_t uxPriority,         // 优先级
   TaskHandle_t *pxCreatedTask     // 任务句柄
);

参数说明:

参数 说明
pvTaskCode 任务入口函数
pcName 任务名(调试用)
usStackDepth 栈大小,以 word 计
pvParameters 传入参数
uxPriority 优先级(数值越大,优先级越高)
pxCreatedTask 任务句柄(可为空)

2. 静态创建任务

xTaskCreateStatic() 需要手动分配堆栈和任务控制块(TCB),常用于安全性要求高的系统:

TaskHandle_t xTaskCreateStatic(
   TaskFunction_t pvTaskCode,
   const char * const pcName,
   uint32_t ulStackDepth,
   void *pvParameters,
   UBaseType_t uxPriority,
   StackType_t *puxStackBuffer,
   StaticTask_t *pxTaskBuffer
);

静态任务不会依赖 FreeRTOS 的堆管理,更稳定,但更复杂


三、任务的优先级与调度

调度策略

  • 基于优先级:高优先级任务优先运行
  • 同优先级任务:采用时间片轮转

示例

000 001 002 003 004 LED任务 UART任务 LED任务 UART任务 高优先级任务 低优先级任务 FreeRTOS 调度示意

四、任务创建实战

示例:两个任务并发

#include "FreeRTOS.h"
#include "task.h"

void vTaskLED(void *pvParameters)
{
    while(1)
    {
        HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
        vTaskDelay(500); // 延时500ms
    }
}

void vTaskUART(void *pvParameters)
{
    while(1)
    {
        printf("Hello FreeRTOS!\n");
        vTaskDelay(1000);
    }
}

int main(void)
{
    HAL_Init();
    SystemClock_Config();

    // 创建两个任务
    xTaskCreate(vTaskLED, "LED", 128, NULL, 2, NULL);
    xTaskCreate(vTaskUART, "UART", 128, NULL, 1, NULL);

    // 启动调度器
    vTaskStartScheduler();

    while(1) {}
}

五、任务句柄的使用

获取任务信息

TaskHandle_t xHandleLED, xHandleUART;

xTaskCreate(vTaskLED, "LED", 128, NULL, 2, &xHandleLED);
xTaskCreate(vTaskUART, "UART", 128, NULL, 1, &xHandleUART);

任务句柄可用于:

  • 删除任务 vTaskDelete(xHandle)
  • 挂起/恢复任务 vTaskSuspend(xHandle) / vTaskResume(xHandle)
  • 动态修改优先级 vTaskPrioritySet(xHandle, newPriority)

六、任务生命周期

被调度
时间片用完
vTaskDelay / 等待资源
超时/资源可用
创建
就绪
运行
阻塞
删除

七、常见问题与解决方法

问题 可能原因 解决方法
任务未运行 调度器未启动 确认 vTaskStartScheduler()
栈溢出 栈设置过小 增大 usStackDepth
多任务不切换 SysTick 中断未配置 检查 SysTick_Handler
打印乱码 串口任务未同步 使用信号量/队列管理输出

八、经验分享

📌 开发建议

  1. 任务数量不要太多,模块化设计 更重要
  2. 建议使用 configCHECK_FOR_STACK_OVERFLOW 开启栈检测
  3. 调试时多用 uxTaskGetStackHighWaterMark() 观察剩余栈空间
  4. 使用 vTaskDelay() 而不是阻塞式 for 循环,保证调度公平

九、总结

通过本章学习,你应该掌握:

  • 使用 xTaskCreate() 创建任务
  • 理解任务的优先级和调度规则
  • 管理任务的生命周期(创建、挂起、恢复、删除)
  • 编写多任务并发程序

至此,你已经能够写出一个 多任务系统,并亲身感受到 RTOS 与裸机的差异。


🔗 FreeRTOS专栏👉 下一章:2025最新超详细FreeRTOS入门教程:第三章 FreeRTOS任务管理 —— 将深入讲解任务的挂起、删除、优先级动态调整等更高级操作。


Logo

欢迎加入西安开发者社区!我们致力于为西安地区的开发者提供学习、合作和成长的机会。参与我们的活动,与专家分享最新技术趋势,解决挑战,探索创新。加入我们,共同打造技术社区!

更多推荐