第12章 队列集QueueSet
约 1061 字大约 4 分钟
2026-01-19
12.1 核心知识点
队列集概述:
队列集(Queue Set)是 FreeRTOS 中的一种数据结构,用于管理多个队列。
集中管理多个队列:队列集允许你将多个相关联的队列组织在一起,方便集中管理。
单一API调用:通过单一的 API 调用,任务可以同时操作多个队列,而无需分别处理每个队列。相关宏
configUSE_QUEUE_SETS相关类型:
QueueSetHandle_t
QueueSetMemberHandle_t相关函数
xQueueCreateSet() 创建队列集
xQueueAddToSet() 队列添加到队列集中
xQueueRemoveFromSet() 从队列集中移除队列
xQueueSelectFromSet() 获取队列集中有有效消息的队列
xQueueSelectFromSetFromISR() 在中断中获取队列集中有有效消息的队列12.2 案例
① 需求
创建1个队列,创建1个二进制信号量,将二者添加到队列集
task1:当按键 SW3 按下,往队列写入数据,当按键 SW4 按下,释放二进制信号量。
task2:读取队列集中的消息,并打印。② 代码
FreeRTOSConfig.h
添加配置项:
// 启用队列集
#define configUSE_QUEUE_SETS 1App_Task.c
#include "App_Task.h"
// 任务1 ------------------------------------
// 任务1函数的原型
void task1_callback(void *pvParameters);
// 任务1名称
#define TASK1_NAME "task1"
// 任务1堆栈大小
#define TASK1_STACK_SIZE 128
// 任务1的优先级
#define TASK1_PRIORITY 1
// 任务1的句柄
TaskHandle_t task1_handle;
// 任务2 ------------------------------------
// 任务2函数的原型
void task2_callback(void *pvParameters);
// 任务2名称
#define TASK2_NAME "task2"
// 任务2堆栈大小
#define TASK2_STACK_SIZE 128
// 任务2的优先级
#define TASK2_PRIORITY 2
// 任务2的句柄
TaskHandle_t task2_handle;
// 定义队列的句柄
QueueHandle_t queue_handle;
// 定义二进制信号量的句柄
SemaphoreHandle_t binary_semaphore_handle;
// 定义对列集的句柄
QueueSetHandle_t queue_set_handle;
/**
* @brief 启动 FreeRTOS 任务管理
*
*/
void App_Task_Start(void)
{
// 进入临界区
taskENTER_CRITICAL();
// 创建任务1
xTaskCreate(task1_callback, TASK1_NAME, TASK1_STACK_SIZE, NULL, TASK1_PRIORITY, &task1_handle) == pdPASS ? printf("任务1创建成功! \n") : printf("任务1穿件失败! \n");
// 创建任务2
xTaskCreate(task2_callback, TASK2_NAME, TASK2_STACK_SIZE, NULL, TASK2_PRIORITY, &task2_handle) == pdPASS ? printf("任务2创建成功! \n") : printf("任务2穿件失败! \n");
// 创建队列
queue_handle = xQueueCreate(1, 1);
queue_handle != NULL ? printf("队列创建成功! \n") : printf("队列创建失败! \n");
// 创建二进制信号量
binary_semaphore_handle = xSemaphoreCreateBinary();
binary_semaphore_handle != NULL ? printf("二进制信号量创建成功! \n") : printf("二进制信号量创建失败! \n");
// 创建队列集
queue_set_handle = xQueueCreateSet(2);
queue_set_handle != NULL ? printf("队列集创建成功! \n") : printf("队列集创建失败! \n");
// 将队列添加到队列集
xQueueAddToSet(queue_handle, queue_set_handle) == pdPASS ? printf("队列添加到队列集成功! \n") : printf("队列添加到队列集失败! \n");
// 将二进制信号量添加到队列集
xQueueAddToSet(binary_semaphore_handle, queue_set_handle) == pdPASS ? printf("二进制信号量添加到队列集成功! \n") : printf("二进制信号量添加到队列集失败! \n");
// 退出临界区
taskEXIT_CRITICAL();
// 启动任务调度器 ( vTaskStartScheduler() 后面的代码不会被执行)
printf("任务调度器启动... \n");
vTaskStartScheduler();
}
// 任务1函数的实现
void task1_callback(void *pvParameters)
{
printf("任务1启动... \n");
uint8_t tx_queue_value = 'A';
while (1)
{
// 检测按键
switch (Int_Key_IsDetect())
{
case 3:
// 按键3被按下,向队列发送数据
printf("任务1: 按键3被按下, 向队列发送数据 '%c' \n", tx_queue_value);
xQueueSend(queue_handle, &tx_queue_value, 0);
break;
case 4:
// 按键4被按下,释放二进制信号量
printf("任务1: 按键4被按下, 释放二进制信号量 \n");
xSemaphoreGive(binary_semaphore_handle);
break;
default:
break;
}
}
}
// 任务2函数的实现
void task2_callback(void *pvParameters)
{
printf("任务2启动... \n");
// 定义变量,用于保存获取到的有效队列句柄
QueueSetMemberHandle_t received_queue_handle;
// 定义变量,保存从队列中接收的数据
uint8_t rx_queue_value;
while (1)
{
// 从队列集中获取有效队列,获取不到一直阻塞
printf("任务2: 等待从队列集中获取有效队列... \n");
received_queue_handle = xQueueSelectFromSet(queue_set_handle, portMAX_DELAY);
// 判断获取到时队列还是二进制信号量 如果获取到的是队列
if (received_queue_handle == queue_handle)
{
// 从队列中接收数据
xQueueReceive(received_queue_handle, &rx_queue_value, portMAX_DELAY);
printf("任务2: 从队列中接收数据 '%c' \n", rx_queue_value);
}
// 如果获取到的是二进制信号量
else if (received_queue_handle == binary_semaphore_handle)
{
// 获取二进制信号量
xSemaphoreTake(received_queue_handle, portMAX_DELAY);
printf("任务2: 获取到二进制信号量 \n");
}
}
}