15.队列集

news2025/1/1 23:05:13

1.简介

在使用队列进行任务之间的“沟通交流”时,一个队列只允许任务间传递的消息为同一种数据类型,如果需要在任务间传递不同数据类型的消息时,那么就可以使用队列集。FreeRTOS提供的队列集功能可以对多个队列进行“监听”,只要被监听的队列中有一个队列有有效的消息,那么队列集的读取任务都可以读取到消息,如果读取任务因读取队列集而被阻塞,那么队列集将解除读取任务的阻塞。使用队列集的好处在于,队列集可以是的任务可以读取多个队列中的消息,而无需遍历所有待读取的队列,以确定具体读取哪一个队列。

使用队列集功能,需要在 FreeRTOSConfig.h 文件中将配置项 configUSE_QUEUE_SETS 配
置为 1,来启用队列集功能。
在这里插入图片描述

2.相关API函数

在这里插入图片描述

1. 函数 xQueueCreateSet()

此函数用于创建队列集,该函数在 queue.c 文件中有定义,函数的原型如下所示:

QueueSetHandle_t xQueueCreateSet(const UBaseType_t uxEventQueueLength);

在这里插入图片描述

QueueSetHandle_t xQueueCreateSet(const UBaseType_t uxEventQueueLength)
{
 QueueSetHandle_t pxQueue;
 
 /* 创建一个队列作为队列集
 * 队列长度为队列集可容纳的队列数量
 * 队列项目的大小为队列控制块的大小
 * 队列的类型为队列集
 */
 pxQueue = xQueueGenericCreate( uxEventQueueLength,
 ( UBaseType_t ) sizeof( Queue_t * ),
 queueQUEUE_TYPE_SET );
 
 return pxQueue;
}

2. 函数 xQueueAddToSet()

此函数用于往队列集中添加队列,要注意的时,队列在被添加到队列集之前,队列中不能
有有效的消息,该函数在 queue.c 文件中有定义,函数的原型如下所示:

BaseType_t xQueueAddToSet( QueueSetMemberHandle_t xQueueOrSemaphore,
 QueueSetHandle_t xQueueSet);

在这里插入图片描述
函数 xQueueAddToSet()的具体代码如下所示:

BaseType_t xQueueAddToSet( QueueSetMemberHandle_t xQueueOrSemaphore,
QueueSetHandle_t xQueueSet)
{
 BaseType_t xReturn;
 
 /* 进入临界区 */
 taskENTER_CRITICAL();
 {
 if( ( ( Queue_t * ) xQueueOrSemaphore )->pxQueueSetContainer != NULL )
 {
 xReturn = pdFAIL;
 }
 /* 队列中要求没有有效消息 */
 else if( ( ( Queue_t * ) xQueueOrSemaphore )->uxMessagesWaiting !=
 ( UBaseType_t ) 0 )
 {
 xReturn = pdFAIL;
 }
 else
 {
 /* 将队列所在队列集设为队列集 */
 ( ( Queue_t * ) xQueueOrSemaphore )->pxQueueSetContainer =
 xQueueSet;
 xReturn = pdPASS;
 }
 }
 /* 退出临界区 */
 taskEXIT_CRITICAL();
 
 return xReturn;
}

3. 函数 xQueueRemoveFromSet()

此函数用于从队列集中移除队列,要注意的时,队列在从队列集移除之前,必须没有有效
的消息,该函数在 queue.c 文件中有定义,函数的原型如下所示:

BaseType_t xQueueRemoveFromSet(QueueSetMemberHandle_t xQueueOrSemaphore,
 QueueSetHandle_t xQueueSet);

在这里插入图片描述
在这里插入图片描述
函数 xQueueRemoveFromSet()的具体代码如下所示:

BaseType_t xQueueRemoveFromSet(QueueSetMemberHandle_t xQueueOrSemaphore,
 QueueSetHandle_t xQueueSet)
{
 BaseType_t xReturn;
 Queue_t * const pxQueueOrSemaphore = ( Queue_t * ) xQueueOrSemaphore;
 
 /* 队列需在队列集中,才能移除 */
 if( pxQueueOrSemaphore->pxQueueSetContainer != xQueueSet )
 {
 xReturn = pdFAIL;
 }
 /* 队列中没有有效消息时,才能移除 */
 else if( pxQueueOrSemaphore->uxMessagesWaiting != ( UBaseType_t ) 0 )
 {
 xReturn = pdFAIL;
 }
 else
 {
 /* 进入临界区 */
 taskENTER_CRITICAL();
 {
 /* 将队列所在队列集设为空 */
 pxQueueOrSemaphore->pxQueueSetContainer = NULL;
 }
 /* 退出临界区 */
 taskEXIT_CRITICAL();
 xReturn = pdPASS;
 }
 
 return xReturn;
}

4. 函数 xQueueSelectFromSet()

此函数用于在任务中获取队列集中有有效消息的队列,该函数在 queue.c 文件中有定义,函
数的原型如下所示:

QueueSetMemberHandle_t xQueueSelectFromSet(
 QueueSetHandle_t xQueueSet,
 TickType_t const xTicksToWait);

在这里插入图片描述
在这里插入图片描述
函数 xQueueSelectFromSet()的具体代码如下所示:

QueueSetMemberHandle_t xQueueSelectFromSet(
 QueueSetHandle_t xQueueSet,
 TickType_t const xTicksToWait)
{
 QueueSetMemberHandle_t xReturn = NULL;
 
 /* 读取队列集的消息
 * 读取到的消息,
 * 即为队列集中有空闲消息的队列
 */
 ( void ) xQueueReceive( ( QueueHandle_t ) xQueueSet,
 &xReturn,
 xTicksToWait);
 return xReturn;
}

5. 函数 xQueueSelectFromSetFromISR()

此函数用于在中断中获取队列集中有有效消息的队列,该函数在 queue.c 文件中有定义,函
数的原型如下所示:

QueueSetMemberHandle_t xQueueSelectFromSetFromISR(
 QueueSetHandle_t xQueueSet );

在这里插入图片描述

QueueSetMemberHandle_t xQueueSelectFromSetFromISR(
 QueueSetHandle_t xQueueSet )
{
 QueueSetMemberHandle_t xReturn = NULL;
 /* 在中断中读取队列集的消息
 * 读取到的消息,
 * 即为队列集中有空闲消息的队列
 */
 ( void ) xQueueReceiveFromISR( ( QueueHandle_t ) xQueueSet,
 &xReturn,
 NULL);
 return xReturn;
}

3.相关实验

在这里插入图片描述

#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./SYSTEM/delay/delay.h"
#include "./MALLOC/malloc.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
/******************************************************************************************************/
/*FreeRTOS配置*/

/* START_TASK 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define START_TASK_PRIO         1
#define START_TASK_STACK_SIZE   128
TaskHandle_t    start_task_handler;
void start_task( void * pvParameters );

/* TASK1 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK1_PRIO         2
#define TASK1_STACK_SIZE   128
TaskHandle_t    task1_handler;
void task1( void * pvParameters );


/* TASK2 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK2_PRIO         3
#define TASK2_STACK_SIZE   128
TaskHandle_t    task2_handler;
void task2( void * pvParameters );

/******************************************************************************************************/
QueueSetHandle_t queueset_handle;
QueueHandle_t    queue_handle;
QueueHandle_t    semphr_handle;
/**
 * @brief       FreeRTOS例程入口函数
 * @param       无
 * @retval      无
 */
void freertos_demo(void)
{    
    xTaskCreate((TaskFunction_t         )   start_task,
                (char *                 )   "start_task",
                (configSTACK_DEPTH_TYPE )   START_TASK_STACK_SIZE,
                (void *                 )   NULL,
                (UBaseType_t            )   START_TASK_PRIO,
                (TaskHandle_t *         )   &start_task_handler );
    vTaskStartScheduler();
}


void start_task( void * pvParameters )
{
    taskENTER_CRITICAL();                               /* 进入临界区 */
    queueset_handle = xQueueCreateSet( 2 );             /* 创建队列集,可以存放2个队列 */
    if(queueset_handle != NULL)
    {
        printf("队列集创建成功!!\r\n");
    }
    
    queue_handle = xQueueCreate( 1, sizeof(uint8_t) );  /* 创建队列 */ 
    semphr_handle = xSemaphoreCreateBinary();           /* 创建二值信号量 */
    
    xQueueAddToSet( queue_handle,queueset_handle);
    xQueueAddToSet( semphr_handle,queueset_handle);
    
    xTaskCreate((TaskFunction_t         )   task1,
                (char *                 )   "task1",
                (configSTACK_DEPTH_TYPE )   TASK1_STACK_SIZE,
                (void *                 )   NULL,
                (UBaseType_t            )   TASK1_PRIO,
                (TaskHandle_t *         )   &task1_handler );
                
    xTaskCreate((TaskFunction_t         )   task2,
                (char *                 )   "task2",
                (configSTACK_DEPTH_TYPE )   TASK2_STACK_SIZE,
                (void *                 )   NULL,
                (UBaseType_t            )   TASK2_PRIO,
                (TaskHandle_t *         )   &task2_handler );
                             
    vTaskDelete(NULL);
    taskEXIT_CRITICAL();                /* 退出临界区 */
}

/* 任务一,实现队列发送以及信号量释放 */
void task1( void * pvParameters )
{
    uint8_t key = 0;
    BaseType_t err = 0;
    while(1) 
    {
        key = key_scan(0);
        if(key == KEY0_PRES)
        {
            err = xQueueSend( queue_handle, &key, portMAX_DELAY );
            if(err == pdPASS)
            {
                printf("往队列queue_handle写入数据成功!!\r\n");
            }
        }else if(key == KEY1_PRES)
        {
            err = xSemaphoreGive(semphr_handle);
            if(err == pdPASS)
            {
                printf("释放信号量成功!!\r\n");
            }
        }
        vTaskDelay(10);
    }
}

/* 任务二,获取队列集的消息 */
void task2( void * pvParameters )
{
    QueueSetMemberHandle_t member_handle;
    uint8_t key;
    while(1)
    {
        member_handle = xQueueSelectFromSet( queueset_handle,portMAX_DELAY);
        if(member_handle == queue_handle)
        {
            xQueueReceive( member_handle,&key,portMAX_DELAY);
            printf("获取到的队列数据为:%d\r\n",key);
        }else if(member_handle == semphr_handle)
        {
            xSemaphoreTake( member_handle, portMAX_DELAY );
            printf("获取信号量成功!!\r\n");
        }
    }
}


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1580706.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis高级-分布式缓存

分布式缓存 – 基于Redis集群解决单机Redis存在的问题 单机的Redis存在四大问题: 0.目标 1.Redis持久化 Redis有两种持久化方案: RDB持久化AOF持久化 1.1.RDB持久化 RDB全称Redis Database Backup file(Redis数据备份文件)…

QT drawPixmap和drawImage处理图片模糊问题

drawPixmap和drawImage显示图片时,如果图片存在缩放时,会出现模糊现象,例如将一个100x100 的图片显示到30x30的区域,这个时候就会出现模糊。如下: 实际图片: 这个问题就是大图显示成小图造成的像素失真。 当…

FPGA(Verilog)实现按键消抖

实现按键消抖功能: 1.滤除按键按下时的噪声和松开时的噪声信号。 2.获取已消抖的按键按下的标志信号。 3.实现已消抖的按键的连续功能。 Verilog实现 模块端口 key_filter(input wire clk ,input wire rst_n ,input wire key_in , //按下按键时为0output …

[NKCTF2024]-PWN:leak解析(中国剩余定理泄露libc地址,汇编覆盖返回地址)

查看保护 查看ida 先放exp 完整exp: from pwn import* from sympy.ntheory.modular import crt context(log_leveldebug,archamd64)while True:pprocess(./leak)ps[101,103,107,109,113,127]p.sendafter(bsecret\n,bytes(ps))cs[0]*6for i in range(6):cs[i]u32(p…

6.模板初阶(函数模板、类模板、类模板声明与定义分离)

1. 泛型编程 如何实现一个通用的交换函数呢? 使用函数重载虽然可以实现,但是有一下几个不好的地方: 重载的函数仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增加对应的函数代码的…

线性、逻辑回归算法学习

1、什么是一元线性回归 线性:两个变量之间的关系是一次函数,也是数据与数据之间的关系。 回归:人们在测试事物的时候因为客观条件所限,求的都是测试值,而不是真实值,为了无限接近真实值,无限次的…

HarmonyOS开发实例:【状态管理】

状态管理 ArkUI开发框架提供了多维度的状态管理机制,和UI相关联的数据,不仅可以在组件内使用,还可以在不同组件层级间传递,比如父子组件之间,爷孙组件之间等,也可以是全局范围内的传递,还可以是…

【考研数学】1800还是660还是880?

关于这几本习题册如何选择,肯定是根据他们的不同特点以及我们的需求结合选择,给大家的建议如下: 1800适合初期,可以帮助你熟悉数学公式和基础定义,迅速上手用。刚开始觉得难很正常,存在一个上手的过程&…

VRRP虚拟路由实验(思科)

一,技术简介 VRRP(Virtual Router Redundancy Protocol)是一种网络协议,用于实现路由器冗余,提高网络可靠性和容错能力。VRRP允许多台路由器共享一个虚拟IP地址,其中一台路由器被选为Master,负…

【Erlang】【RabbitMQ】Linux(CentOS7)安装Erlang和RabbitMQ

一、系统环境 查版本对应,CentOS-7,选择Erlang 23.3.4,RabbitMQ 3.9.16 二、操作步骤 安装 Erlang repository curl -s https://packagecloud.io/install/repositories/rabbitmq/erlang/script.rpm.sh | sudo bash安装 Erlang package s…

扫描IP开放端口该脚本用于对特定目标主机进行常见端口扫描(加载端口字典)或者指定端口扫描,判断目标主机开

扫描IP开放端口该脚本用于对特定目标主机进行常见端口扫描(加载端口字典)或者指定端口扫描,判断目标主机开 #/bin/bash #该脚本用于对特定目标主机进行常见端口扫描(加载端口字典)或者指定端口扫描,判断目标主机开放来哪些端口 #用telnet方式 IP$1 #IP119.254.3.28 #获得IP的前…

【STL】顺序容器与容器适配器

文章目录 1顺序容器概述1.1array1.2forward_list1.3deque 2.如何确定使用哪种顺序容器呢?3.容器适配器的概念4.如何定义适配器呢? 1顺序容器概述 给出以下顺序容器表: 顺序容器类型作用vector可变大小的数组,支持快速访问&#…

UML学习

UML(Unified Modeling Language):统一建模语言,提供了一套符号和规则来帮助分析师和设计师表达系统的架构、行为和交互 类图:描绘类、接口之间的关系(继承、实现、关联、依赖等)以及类的内部结构(属性和方法),直观展现系统的静态…

2024年3月电子学会青少年软件编程 中小学生Python编程等级考试一级真题解析(判断题)

2024年3月Python编程等级考试一级真题解析 判断题(共10题,每题2分,共20分) 26、turtle 画布的坐标系原点是在画布的左上角 答案:错 考点分析:考查turtle相关知识,turtle画布坐标系是在画布的…

c# wpf LiveCharts 饼图 简单试验

1.概要 c# wpf LiveCharts 饼图 简单试验 2.代码 <Window x:Class"WpfApp3.Window5"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d"http://schem…

openharmony launcher 调研笔记(03)UI 数据装配

最近在看launcher&#xff0c;把自己调研的点做个笔记&#xff0c;持续修改更新中&#xff0c;个人笔记酌情参考。 桌面上半部分包含父子逻辑&#xff1a; Column() { PageDesktopLayout(); } PageDesktopLayout->GridSwiper->Swiper->SwiperPage 1.PageDe…

即插即用篇 | RTDETR引入Haar小波下采样 | 一种简单而有效的语义分割下采样模块

本改进已集成到 RT-DETR-Magic 框架。 下采样操作如最大池化或步幅卷积在卷积神经网络(CNNs)中被广泛应用,用于聚合局部特征、扩大感受野并减少计算负担。然而,对于语义分割任务,对局部邻域的特征进行池化可能导致重要的空间信息丢失,这有助于逐像素预测。为了解决这个问…

Collection与数据结构 二叉树(一):二叉树的性质与基本操作

1. 树形结构 1.1 概念1 (了解) 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。它具有以下的特点&#…

已解决:windows 下无法加载文件 xxx.ps1,因为在此系统上禁止运行脚本

目录 1&#xff0c;问题描述2&#xff0c;问题解决 1&#xff0c;问题描述 当通过 npm 全局安装依赖后&#xff08;比如 ts 对应的 tsc 命令&#xff0c;还有 pnpm&#xff09;&#xff0c;想直接使用安装的命令&#xff0c;就会报错&#xff1a; 2&#xff0c;问题解决 以管…

《QT实用小工具·二十二》多种样式导航按钮控件

1、概述 源码放在文章末尾 该项目实现了多种样式的导航按钮控件 可设置文字的左侧、右侧、顶部、底部间隔。 可设置文字对齐方式。 可设置显示倒三角、倒三角边长、倒三角位置、倒三角颜色。 可设置显示图标、图标间隔、图标尺寸、正常状态图标、悬停状态图标、选中状态图标…