IustitiaeのBlog
首页项目归档照片墙音乐说说笔记关于
封面
📓 笔记/📁 嵌入式/FreeRTOS入门——配置与任务管理

FreeRTOS入门——配置与任务管理

2026-06-27 16:00:00
# FreeRTOS
# STM32
# RTOS
# 任务管理

引言

当你的嵌入式项目从"点个灯"进化到"同时处理显示屏刷新、传感器数据采集、WiFi通信和用户交互"时,裸机编程的超级循环(Super Loop)就捉襟见肘了。

FreeRTOS 是一个轻量级的实时操作系统内核,它为单片机提供了多任务调度的能力——让多个任务看起来"同时运行"。而这一切的核心,就是任务管理。

一、为什么需要 RTOS?

裸机编程的痛点

while (1) {
    ReadSensor();      // 耗时 50ms
    UpdateDisplay();   // 耗时 100ms
    CheckButton();     // 必须快速响应,但被前面的任务阻塞了!
    SendDataToCloud(); // 传输不稳定
}

当 CheckButton() 需要实时响应,却因为前面的任务耗时太长而无法及时执行时,用户体验就变成了"按了键没反应"。

RTOS 的解决方案

FreeRTOS 通过任务调度器在多个任务之间快速切换(通常每 1ms 一次),让每个任务都能按时得到 CPU 时间。从宏观上看,所有任务在"同时"运行。

二、环境搭建与基础配置

CubeMX 配置步骤

  1. 在 Middleware → FREERTOS 中,Interface 选择 CMSIS_V1 或 CMSIS_V2
  2. 在 Tasks and Queues 选项卡中创建任务
  3. 在 Config parameters 中调整内核参数

关键配置宏(FreeRTOSConfig.h)

配置项说明推荐值configUSE_PREEMPTION启用抢占式调度1(启用)configTICK_RATE_HZ系统时钟节拍频率1000(1ms 一个 tick)configMAX_PRIORITIES最大优先级数5~7(视需求而定)configMINIMAL_STACK_SIZE最小任务栈大小128(字)configTOTAL_HEAP_SIZE系统堆总大小根据任务数量和栈大小计算configUSE_COUNTING_SEMAPHORES启用计数信号量1configUSE_MUTEXES启用互斥锁1

三、任务(Task)—— FreeRTOS 的核心

3.1 任务是什么?

任务是 FreeRTOS 中的基本执行单元。每个任务有自己的栈空间、优先级和任务控制块(TCB)。调度器根据优先级和状态决定哪个任务获得 CPU。

3.2 任务状态转换

         ┌──────────────────────┐
         │      就绪态          │ ← 任务准备好,等待 CPU
         │     (Ready)          │
         └──┬────────▲─────────┘
            │ 获得CPU │ 时间片耗尽
            ▼         │
         ┌────────────┴──────┐
         │      运行态        │ → 正在使用 CPU
         │    (Running)       │
         └────────┬──────────┘
                  │ 调用 vTaskDelay / 等待信号量 / 等待队列
                  ▼
         ┌──────────────────────┐
         │      阻塞态          │ → 等待某个事件(时间/信号量/队列)
         │    (Blocked)         │
         └──────────┬───────────┘
                    │ 事件发生(时间到/信号量获得/数据到达)
                    ▼
         ┌──────────────────────┐
         │      就绪态          │
         └──────────────────────┘

此外还有挂起态(Suspended)——任务被 vTaskSuspend() 挂起后,不参与调度,直到被 vTaskResume() 恢复。

3.3 创建任务

// 动态创建任务(推荐)
BaseType_t xTaskCreate(
    TaskFunction_t pvTaskCode,    // 任务函数指针
    const char *pcName,           // 任务名称(调试用)
    uint32_t usStackDepth,        // 栈大小(字,不是字节!)
    void *pvParameters,           // 传递给任务的参数
    UBaseType_t uxPriority,       // 优先级(数值越大优先级越高)
    TaskHandle_t *pxCreatedTask   // 任务句柄(可为 NULL)
);

// 任务函数模板
void MyTask(void *pvParameters) {
    for (;;) {  // 任务函数必须有死循环!不能 return!
        // 任务逻辑
        vTaskDelay(pdMS_TO_TICKS(1000));  // 延时 1000ms(以 tick 为单位)
    }
}

⚠️ 重要:vTaskDelay(pdMS_TO_TICKS(1000)) 让任务进入阻塞态 1000ms,释放 CPU 给其他任务。不要用 for 循环做忙等待!

3.4 完整示例

// 任务1:LED 闪烁
void TaskLED(void *pvParameters) {
    for (;;) {
        HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
        vTaskDelay(pdMS_TO_TICKS(500));  // 500ms 闪烁
    }
}

// 任务2:串口打印
void TaskPrint(void *pvParameters) {
    for (;;) {
        printf("Hello from FreeRTOS!\r\n");
        vTaskDelay(pdMS_TO_TICKS(2000));  // 每 2 秒打印一次
    }
}

// 主函数中创建任务
xTaskCreate(TaskLED,   "LED",   128, NULL, 1, NULL);
xTaskCreate(TaskPrint, "Print", 256, NULL, 2, NULL);

// 启动调度器
vTaskStartScheduler();

// 调度器启动后,以下代码永远不会执行
while (1) {}

四、任务优先级与调度

抢占式调度

  • 高优先级任务就绪时,立即抢占低优先级任务
  • 相同优先级的任务通过时间片轮转(每个 tick 切换一次)
  • 优先级数值越大,优先级越高(在 STM32 CubeMX 配置中)

优先级分配建议

任务类型推荐优先级说明时间关键(电机控制、PID)高(45)不能被长时间阻塞用户交互(按键、显示刷新)中(23)需要及时响应后台任务(日志、数据上报)低(0~1)空闲时处理

五、idle 任务与空闲钩子

FreeRTOS 会自动创建一个最低优先级的 idle 任务,当所有任务都阻塞时运行。

可以通过空闲钩子函数在 idle 任务中执行低优先级后台操作:

void vApplicationIdleHook(void) {
    // 进入低功耗模式
    // 清理资源
    // 注意:不能在此函数中调用阻塞 API!
}

总结

FreeRTOS 的任务管理是实时操作系统的基石。掌握任务创建、状态转换、优先级调度这三个核心概念,你就迈出了从裸机编程到 RTOS 编程最重要的一步。

下一篇文章我们将深入信号量与回调函数——任务间如何通信和同步。

分而治之,各司其职。 —— 计算机科学的古老智慧


avatar

Iustitiae

在代码、单片机,电机控制模拟间穿梭的普通人。近期正埋头于 freerots学习。

2026年6月

一
二
三
四
五
六
日
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

Recent Records

比较器基础——输出级、输入范围与颤振的解决之道

2026-08-03 12:00:00

MOS管基础——从电压控制的电子开关到电源开关与防反接

2026-08-03 12:00:00

三极管基础——从小电流撬动大电流的放大器到电子开关

2026-07-29 12:00:00