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);

参数

含义

uxQueueLength

队列最大元素个数

uxItemSize

每个元素的大小(字节)

返回值

成功 → 队列句柄 失败 → NULL

示例:

 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);

参数

含义

xQueue

队列句柄

pvItemToQueue

指向要发送的数据的指针(复制数据,非引用)

xTicksToWait

队列满时的等待时间

返回值

pdPASS → 成功;errQUEUE_FULL → 失败

xQueueSendFromISR — 中断中发送

 BaseType_t xQueueSendFromISR(QueueHandle_t xQueue, const void *pvItemToQueue, BaseType_t *pxHigherPriorityTaskWoken);

参数

含义

xQueue

队列句柄

pvItemToQueue

指向要发送的数据

pxHigherPriorityTaskWoken

传 NULL 或 BaseType_t 变量地址

返回值

pdPASS / errQUEUE_FULL

⚠️ 只能在 ISR 中调用,否则死锁。

接收(出队)

xQueueReceive — 任务中接收

 BaseType_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait);

参数

含义

xQueue

队列句柄

pvBuffer

接收缓冲区指针(队列数据会复制到这里)

xTicksToWait

队列空时的等待时间

返回值

pdPASS → 成功;pdFALSE → 超时/失败

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 填法

填值

含义

典型使用场景

portMAX_DELAY

无限等待,直到获取到信号量

任务同步,信号量一定会来的场景

0

不等待,立即返回

轮询检查资源是否可用,不可用就做其他事

pdMS_TO_TICKS(100)

等 100ms,超时返回

带超时的资源获取,避免死锁

pdMS_TO_TICKS(5000)

等 5 秒,超时返回

等待外设回应,超时报错

释放(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);

项目

说明

参数

返回值

成功 → 非 NULL 句柄;失败 → NULL(堆不足)

初始值

所有位为 0

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 填法

写法

含义

0x01(1 << 0)

设置 bit 0

(1 << 3)

设置 bit 3

0x05(1 << 0) | (1 << 2)

同时设置 bit 0 和 bit 2

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)
 );

参数填法详解

参数

pdTRUE

pdFALSE

xClearOnExit

条件满足时,自动清除 uxBitsToWaitFor 指定的位

不清除,其他任务也可以读到

xWaitForAllBits

AND 模式:所有指定位都置 1 才唤醒

OR 模式:任意指定位置 1 就唤醒

xTicksToWait

同信号量:portMAX_DELAY 无限等 / 0 不等 / pdMS_TO_TICKS(n) 超时

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         // 最多等多久

);

参数

含义

ulBitsClearOnEntry

进入函数时,通知值中哪些位要清 0。通常设 0(不清旧值)或 0xFFFFFFFF(抛弃旧值)

ulBitsClearOnExit

退出函数时,通知值中哪些位要清 0。通常设 0xFFFFFFFF(消费完,重新累积)或 你本次处理了的位

pulValue

传出参数,收到通知后通知值的副本(不管出口清了什么,你拿到的都是清位前的快照)

xTicksToWait

ulTaskNotifyTake

场景

Entry

Exit

效果

一次性处理所有事件

0

0xFFFFFFFF

退出时通知值全清,重新累积

分批处理不同事件

0

本次消费的位

只清已处理的,没处理的保留

抛弃旧值重头开始

0xFFFFFFFF

0

进去就清旧值,只关心新事件

拿不准就选第一种 (0, 0xFFFFFFFF)——醒来处理全部,简单可靠。

8.4 代替单值队列(邮箱)用

   xTaskNotify(xDisplayTask, reading, eSetValueWithOverwrite);
//eSetValueWithOverwrite:覆盖模式:不管对方有没有未读数据,直接覆盖
 xTaskNotifyWait(0xFFFFFFFF, 0xFFFFFFFF, &val, portMAX_DELAY);
// 第一个:0xFFFFFFFF清除旧的通知值 确保这次只接收“新来的”
// 第二个:0xFFFFFFFF:我已经消费了这个数据后清除