1.动态创建任务函数
BaseType_t xTaskCreate
(
TaskFunction_t pxTaskCode, /* 指向任务函数的指针 */
const char * const pcName, /* 任务名字,最大长度
configMAX_TASK_NAME_LEN */
const configSTACK_DEPTH_TYPE usStackDepth, /* 任务堆栈大小,默认单位
4 字节 */
void * const pvParameters, /* 传递给任务函数的参数
*/
UBaseType_t uxPriority, /* 任务优先级,范围:0 ~
configMAX_PRIORITIES - 1 */
TaskHandle_t * const pxCreatedTask /* 任务句柄,就是任务的任
务控制块 */
)
返回值说明如下:
pdPASS:任务创建成功。
errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY:任务创建失败。
2.删除任务
void vTaskDelete( TaskHandle_t xTaskToDelete )2.1参数说明:xTaskToDelete 待删除任务的任务句柄。当传入的参数为 NULL,则代表删 除任务自身(当前正在运行的任务)。
3.延迟函数
vTaskDelay(pdMS_TO_TICKS(300));4.队列
头文件
#include "queue.h"队列生命周期
xQueueCreate — 创建队列
QueueHandle_t xQueueCreate(UBaseType_t uxQueueLength, UBaseType_t uxItemSize);示例:
QueueHandle_t xKeyQueue;
// 存储 10 个 uint8_t 的队列
xKeyQueue = xQueueCreate(10, sizeof(uint8_t));
// 或 xQueueCreate(10, 1);vQueueDelete — 删除队列
void vQueueDelete(QueueHandle_t xQueue);发送(入队)
xQueueSend — 任务中发送
BaseType_t xQueueSend(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait);xQueueSendFromISR — 中断中发送
BaseType_t xQueueSendFromISR(QueueHandle_t xQueue, const void *pvItemToQueue, BaseType_t *pxHigherPriorityTaskWoken);⚠️ 只能在 ISR 中调用,否则死锁。
接收(出队)
xQueueReceive — 任务中接收
BaseType_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait);xQueueReceiveFromISR — 中断中接收
BaseType_t xQueueReceiveFromISR(QueueHandle_t xQueue, void *pvBuffer, BaseType_t *pxHigherPriorityTaskWoken);5.临界区
作用:临界区是一段必须原子执行的代码、不能被任务切换打断、不能被中断打断
taskENTER_CRITICAL(); /* 进入临界区 */
taskEXIT_CRITICAL(); /* 退出临界区 */6.信号量
创建信号量
创建二值型号量
SemaphoreHandle_t xSemaphoreCreateBinary(void);创建计数信号量
SemaphoreHandle_t xSemaphoreCreateCounting(
UBaseType_t uxMaxCount, // 最大计数值
UBaseType_t uxInitialCount // 初始计数值
);
//中断里
BaseType_t xSemaphoreTakeFromISR(
SemaphoreHandle_t xSemaphore,
BaseType_t *pxHigherPriorityTaskWoken
);获取(take)信号量
BaseType_t xSemaphoreTake(
SemaphoreHandle_t xSemaphore, // 信号量句柄
TickType_t xTicksToWait // 等待时间(单位: tick)
);参数 xTicksToWait 填法
释放(give)信号量
BaseType_t xSemaphoreGive(SemaphoreHandle_t xSemaphore);
返回值 pdPASS(成功)或 pdFAIL(失败)
// 中断
BaseType_t xSemaphoreGiveFromISR(
SemaphoreHandle_t xSemaphore,
BaseType_t *pxHigherPriorityTaskWoken
);7.事件组
7.1 创建事件标记组
EventGroupHandle_t xEventGroupCreate(void);7.2 设置事件位(Set Bits)
EventBits_t xEventGroupSetBits(
EventGroupHandle_t xEventGroup, // 事件组句柄
const EventBits_t uxBitsToSet // 要设置的位掩码
);
//=========================================================
// 例子
#define BIT_CONNECTED (1 << 0) // 连接成功
#define BIT_DATA_READY (1 << 1) // 数据就绪
#define BIT_TIMEOUT (1 << 2) // 超时
// 设置 data_ready 位
xEventGroupSetBits(xEG, BIT_DATA_READY);
// 同时设置多个位
xEventGroupSetBits(xEG, BIT_DATA_READY | BIT_TIMEOUT);
//=========================================================参数 uxBitsToSet 填法
7.3 等待事件位(Wait Bits)
EventBits_t xEventGroupWaitBits(
EventGroupHandle_t xEventGroup, // 事件组句柄
const EventBits_t uxBitsToWaitFor, // 等待哪些位
const BaseType_t xClearOnExit, // 满足条件后是否自动清位
const BaseType_t xWaitForAllBits, // TRUE=AND模式 / FALSE=OR模式
TickType_t xTicksToWait // 超时(tick)
);参数填法详解
8. 任务通知
8.1代替二值信号量
发通知不带数值
// 方式 A:通知值 +1(最快的用法,只能发信号不能带值)
xTaskNotifyGive(xTask); // 任务中调用
xTaskNotifyGiveFromISR(xTask, &xWoken); // ISR 中调用接收通知不带数值
// 方式 A:取走通知值(减1或归零),返回旧值——适合当信号量
uint32_t ulTaskNotifyTake(xClearOnExit, xTicksToWait);8.2代替计数信号量
// 作为生产者
xTaskNotifyGive(xConsumer);
// 消费者
ulTaskNotifyTake(pdFALSE, xTicksToWait);
pdTRUE
清零模式(像二进制信号量)
pdFALSE
递减模式(像计数信号量 ✅)
8.3 代替事件标志组
#define EVENT_A (1 << 0)
#define EVENT_B (1 << 1)
xTaskNotify(
xConsumer,
EVENT_A | EVENT_B,
eSetBits
);
xTaskNotifyWait(
0x00000000, // ulBitsClearOnEntry: 进去时不清任何位(保留已有的事件)
0xFFFFFFFF, // ulBitsClearOnExit: 退出时清除所有位(消费完,下次重新累积)
&val, // 收到的通知值放在这
portMAX_DELAY); // 一直等
// 判断 val 里哪些 bit 被置位了
if (val & EVT_UART) vProcessUART();
if (val & EVT_BUTTON) vProcessButton();
if (val & EVT_TIMER) vProcessTimer();
}
//=================================================
BaseType_t xTaskNotifyWait(
uint32_t ulBitsClearOnEntry, // 进入时:清除通知值的哪些位
uint32_t ulBitsClearOnExit, // 退出时:清除通知值的哪些位
uint32_t *pulValue, // 传出:通知值的副本
TickType_t xTicksToWait // 最多等多久
);
拿不准就选第一种
(0, 0xFFFFFFFF)——醒来处理全部,简单可靠。
8.4 代替单值队列(邮箱)用
xTaskNotify(xDisplayTask, reading, eSetValueWithOverwrite);
//eSetValueWithOverwrite:覆盖模式:不管对方有没有未读数据,直接覆盖 xTaskNotifyWait(0xFFFFFFFF, 0xFFFFFFFF, &val, portMAX_DELAY);
// 第一个:0xFFFFFFFF清除旧的通知值 确保这次只接收“新来的”
// 第二个:0xFFFFFFFF:我已经消费了这个数据后清除