FreeRTOS任务管理与通信机制详解
1 任务的创建与管理
任务创建
使用 xTaskCreate()
创建任务:
BaseType_t xTaskCreate(
TaskFunction_t pxTaskCode, // 任务函数(入口)
const char * const pcName, // 任务名称(调试用)
configSTACK_DEPTH_TYPE usStackDepth, // 堆栈大小(单位为字)
void * const pvParameters, // 任务参数
UBaseType_t uxPriority, // 优先级(0~configMAX_PRIORITIES-1)
TaskHandle_t * const pxCreatedTask // 任务句柄(可为NULL)
);
注意:任务函数必须符合
void (*TaskFunction_t)(void *)
的原型。
任务删除
vTaskDelete(TaskHandle_t xTaskToDelete);
可删除任意任务,包括自身(传入 NULL
)。
任务挂起与唤醒
-
挂起任务:
vTaskSuspend(TaskHandle_t xTask);
-
唤醒任务:
vTaskResume(TaskHandle_t xTask);
用于控制任务的执行时机,但需要避免任务永久挂起导致系统资源浪费。
2 队列(Queue)
定义
队列是典型的FIFO(先进先出)数据结构,用于任务间或中断与任务之间的数据通信。
创建队列
QueueHandle_t xQueueCreate(UBaseType_t uxQueueLength, UBaseType_t uxItemSize);
-
uxQueueLength
:队列能容纳的最大项目数 -
uxItemSize
:每个项目的大小(字节)
发送数据到队列
xQueueSend(xQueue, pvItemToQueue, xTicksToWait);
-
xTicksToWait = 0
:非阻塞发送 -
portMAX_DELAY
:阻塞直到成功(需要开启阻塞API支持)
从队列接收数据
xQueueReceive(xQueue, pvBuffer, xTicksToWait);
3 信号量(Semaphore)
信号量用于任务之间的同步与资源访问控制。FreeRTOS 提供多种类型的信号量:
1. 二值信号量
用于同步事件或中断信号(如“电话亭”模型)。
-
创建:
xSemaphoreCreateBinary();
-
获取:
xSemaphoreTake(xSemaphore, xBlockTime);
-
释放:
xSemaphoreGive(xSemaphore);
特点:同一任务在未释放时无法再次获取。
2. 互斥信号量(Mutex)
适用于保护共享资源的访问(如外设、内存等),防止资源冲突。
-
创建:
xSemaphoreCreateMutex();
特性:只有获得互斥锁的任务才能释放,错误释放会引发死锁。
3. 计数型信号量
用于资源计数或控制并发数量(如“停车位”模型)。
-
创建:
xSemaphoreCreateCounting(uxMaxCount, uxInitialCount);
-
当前剩余资源数:
uxSemaphoreGetCount(xSemaphore);
4. 递归互斥信号量
允许任务在同一段逻辑中多次获取锁,每次获取必须匹配对应释放。
-
创建:
xSemaphoreCreateRecursiveMutex();
-
获取:
xSemaphoreTakeRecursive(xMutex, xBlockTime);
-
释放:
xSemaphoreGiveRecursive(xMutex);
1.4.4 软件定时器(Software Timer)
软件定时器用于延迟或周期性执行某些任务函数,非阻塞式。
创建软件定时器
TimerHandle_t xTimerCreate(
const char * const pcTimerName,
TickType_t xTimerPeriodInTicks,
UBaseType_t uxAutoReload, // pdTRUE: 周期性;pdFALSE: 单次
void * const pvTimerID,
TimerCallbackFunction_t pxCallbackFunction // 定时器回调
);
定时器启动需要调用
xTimerStart()
。系统时间片通过configTICK_RATE_HZ
定义(常设为 1000,即1ms一tick)。
5 事件标志组(Event Group)
事件标志组提供位操作机制,适用于多事件同步(例如 KEY1 & KEY2 -> LED1_ON
)。
创建与设置
-
创建:
xEventGroupCreate();
-
设置标志位:
xEventGroupSetBits(xEventGroup, uxBitsToSet);
等待事件位满足
xEventGroupWaitBits( xEventGroup, uxBitsToWaitFor, xClearOnExit, // 是否在退出时清除标志位 xWaitForAllBits, // 全部满足 vs 任一满足 xTicksToWait );
1.4.6 任务通知(Task Notification)
任务通知是一种轻量级的通信机制,比队列和信号量更高效(最多支持32位通知值)。
发送通知(中断中)
xTaskNotifyFromISR(xTaskToNotify, ulValue, eAction, pxHigherPriorityTaskWoken);
-
ulValue
:通知值 -
eAction
:通知模式(如覆盖、累加) -
pxHigherPriorityTaskWoken
:用于中断上下文切换判断
等待通知
xTaskNotifyWait( ulBitsToClearOnEntry, ulBitsToClearOnExit, pulNotificationValue, xTicksToWait );
使用任务通知可高效地替代传统信号量、事件等机制。
附:常用FreeRTOS配置参数说明
宏定义 | 含义 |
---|---|
configMAX_PRIORITIES | 最大优先级数(通常为5或更高) |
configMINIMAL_STACK_SIZE | 任务最小栈大小(128即为512字节) |
configMAX_TASK_NAME_LEN | 任务名最大长度(常为16) |
configTICK_RATE_HZ |
下面是一个完整、结构清晰的 FreeRTOS Demo 示例代码,包含了任务创建、启动任务调度的基本流程,适合初学者参考:
✅ 示例:FreeRTOS任务创建与调度启动(主函数中)
#include "FreeRTOS.h" #include "task.h" #include <stdio.h>// 任务句柄(可选) TaskHandle_t Task1Handle = NULL; TaskHandle_t Task2Handle = NULL;// 任务函数定义 void Task1(void *pvParameters) {while (1){printf("Task 1 is running...\n");vTaskDelay(pdMS_TO_TICKS(1000)); // 延时1000ms} }void Task2(void *pvParameters) {while (1){printf("Task 2 is running...\n");vTaskDelay(pdMS_TO_TICKS(500)); // 延时500ms} }// 主函数 int main(void) {// 创建任务1xTaskCreate(Task1, // 任务函数"Task1", // 任务名(调试用)128, // 堆栈大小(单位为字,128 x 4 = 512字节)NULL, // 参数2, // 优先级(范围:0 ~ configMAX_PRIORITIES-1)&Task1Handle // 任务句柄);// 创建任务2xTaskCreate(Task2,"Task2",128,NULL,1, // 优先级低于Task1&Task2Handle);// 启动任务调度器vTaskStartScheduler();// 永远不会运行到这里,除非堆栈不足或调度器启动失败while (1); }
🔍 说明
-
xTaskCreate()
:注册任务并准备调度,必须在vTaskStartScheduler()
前调用。 -
vTaskDelay()
:实现任务延时,使用pdMS_TO_TICKS()
宏可避免硬编码。 -
vTaskStartScheduler()
:启动调度器,之后 FreeRTOS 会自动管理任务切换。