FreeRTOS基础(十三):队列集

     队列集(Queue Set)通常指的是一组队列,它们可以用于处理不同的任务或数据流。每个队列可以独立地处理自己的元素,但作为一个集群,它们可以协同工作来完成更复杂的任务。下面进行介绍。

目录

一、队列集简介

二、队列集相关API函数介绍

2.1 队列集使用流程

2.2 队列集相关API函数接口

2.2.1 创建队列集

2.2.2 向队列集中添加消息

2.2.3 从队列集中移除队列

2.2.4 获取队列集中有有效消息的队列

三、队列集操作实验


一、队列集简介

       一个队列只允许任务间传递的消息为同一种数据类型,如果需要在任务间传递不同数据类型的消息时,那么就可以使用队列集 !它的作用:用于对多个队列或信号量进行“监听”,其中不管哪一个消息到来,都可让任务退出阻塞状态。如下所示,假设:有个接收任务,使用到队列接收和信号量的获取,如下:

       队列集(Queue Set)是一个高级的同步机制,它允许一个任务同时等待多个队列或信号量的事件,并在任何一个队列或信号量变为可用时被唤醒。相比于单纯的队列,队列集具有以下几个优点:

  1. 集中管理多路事件: 队列集可以将多个队列和信号量集中在一起,任务只需等待一个队列集,就可以响应多个事件源。这大大简化了任务需要处理多个队列和信号量的情况。

  2. 减少任务切换: 如果一个任务需要从多个队列中接收数据,使用队列集可以避免任务在多个队列上阻塞和切换。任务只需阻塞在一个队列集上,当任何一个队列有数据时,任务就会被唤醒处理,减少了不必要的任务切换,提高了系统效率。

  3. 简化代码逻辑: 队列集简化了等待多个事件源的代码逻辑,避免了复杂的多重等待和查询操作。代码更加清晰和易于维护。

  4. 提高响应速度任务可以立即响应队列集中任意一个队列或信号量的变化,而不需要轮询多个队列或信号量,提升了系统的实时响应能力。

二、队列集相关API函数介绍

2.1 队列集使用流程

  1. 启用队列集功能需要将宏configUSE_ QUEUE SETS配置为1
  2. 创建队列集
  3. 创建队列或信号量
  4. 往队列集中添加队列或信号量
  5. 任务往队列发送信息或释放信号量
  6. 其他任务获取队列集任意一个的队列的消息或者信号量;

2.2 队列集相关API函数接口

函数

描述

xQueueCreateSet()

创建队列集

xQueueAddToSet()

队列添加到队列集中

xQueueRemoveFromSet()

从队列集中移除队列

xQueueSelectFromSet()

获取队列集中有有效消息的队列

xQueueSelectFromSetFromISR()

在中断中获取队列集中有有效消息的队列

2.2.1 创建队列集

QueueSetHandle_t    xQueueCreateSet( const UBaseType_t  uxEventQueueLength ); 

 

       从上面可以知道,利用此函数可以创建一个队列集,需要指定队列集可容纳的队列的数量,队列集创建成功,返回队列集句柄,因此,需要提前定义好队列集句柄!

2.2.2 向队列集中添加消息

BaseType_t xQueueAddToSet( QueueSetMemberHandle_t  xQueueOrSemaphore ,
					      QueueSetHandle_t   xQueueSet  ); 

       此函数用于往队列集中添加队列要注意的时,队列在被添加到队列集之前,队列中不能有有效的消息。

     从上面可以知道,利用此函数可以往队列集中添加队列,需要指定添加的队列句柄,以及队列集句柄。

2.2.3 从队列集中移除队列

BaseType_t   xQueueRemoveFromSet( QueueSetMemberHandle_t  	xQueueOrSemaphore ,						          QueueSetHandle_t   xQueueSet ); 

此函数用于从队列集中移除队列 要注意的是,队列在从队列集移除之前,必须没有有效的消息

从上面可以知道,利用此函数可以从队列集中移除队列,需要指定移除的队列句柄,以及队列集句柄。

2.2.4 获取队列集中有有效消息的队列

QueueSetMemberHandle_t     xQueueSelectFromSet( QueueSetHandle_t 		xQueueSet,
                                            TickType_t const  xTicksToWait )

此函数用于在任务中获取队列集中有有效消息的队列。

      这个函数,用于从队列集中选择一个有数据或可用的队列或信号量。它允许任务阻塞等待,直到队列集中的任意一个队列或信号量变为可用,从而简化了任务需要同时等待多个队列或信号量的情况。 返回队列集中的一个成员(队列或信号量)的句柄,该成员已变为可用。如果在指定时间内没有任何队列或信号量变为可用,则返回 NULL

      当一个任务需要同时等待多个队列或信号量时,使用 xQueueSelectFromSet 可以简化代码逻辑并提高效率。任务不需要分别等待每个队列或信号量,而是可以统一等待队列集。

三、队列集操作实验

任务创建文件

#include "stm32f4xx.h"                  // Device header
#include "stdio.h"
#include "FreeRTOS.h"
#include "task.h"
#include "dynamic.h"
#include "mydelay.h"
#include "mykey.h"
#include "queue.h"
#include "semphr.h"


/**********************START_TASK任务配置******************************/
/***********包括任务堆栈大小、任务优先级、任务句柄、创建任务***********/

#define        START_TASK_STACK_SIZE  128   //定义堆栈大小为128字(1字等于4字节)
#define        START_TASK_PRIO         1    //定义任务优先级,0-31根据任务需求
TaskHandle_t   start_task_handler;    //定义任务句柄(结构体指针)
void start_task(void* args);




/**********************TASK1任务配置******************************/
/***********包括任务堆栈大小、任务优先级、任务句柄、创建任务***********/
#define  TASK1_STACK_SIZE  128            //定义堆栈大小为128字(1字等于4字节)
#define  TASK1_PRIO         2             //定义任务优先级,0-31根据任务需求
TaskHandle_t   task1_handler;           //定义任务句柄(结构体指针)
void task1(void* args);




/**********************TASK2任务配置******************************/
/***********包括任务堆栈大小、任务优先级、任务句柄、创建任务***********/
#define  TASK2_STACK_SIZE  128            //定义堆栈大小为128字(1字等于4字节)
#define  TASK2_PRIO         3             //定义任务优先级,0-31根据任务需求
TaskHandle_t   task2_handler;           //定义任务句柄(结构体指针)
void task2(void* args);


QueueSetHandle_t queueset_handle;        //队列集句柄
QueueHandle_t  queue_handle;             //队列句柄
QueueHandle_t  semphr_handle;             //信号量句柄


/*********开始任务用来创建一个任务,只创建一次,不能是死循环,创建完这个任务后删除开始任务本身***********/
void start_task(void* args)
{
	taskENTER_CRITICAL();        /*进入临界区*/
	queueset_handle = xQueueCreateSet(2);              //创建队列集,可以存放两个队列,一个是队列,一个是信号量
	if(queueset_handle!=NULL)
	{
		printf("队列集创建成功!\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);    //删除开始任务自身,传参NULL
							
	taskEXIT_CRITICAL();   /*退出临界区*/
		

    //临界区内不会进行任务的调度切换,出了临界区才会进行任务调度,抢占式						
}




/********任务1的任务函数,无返回值且是死循环***********/

/*****任务1:实现队列发送消息以及信号量的释放*******/
void task1(void* args)
{
	uint8_t  key=0;	
	BaseType_t xReturn;
	while(1)
	{
		 key= KEY_Scan(0);
		 if(key==KEY0_PRES)
		 {
			 xReturn=xQueueSend(queue_handle,&key,portMAX_DELAY);    //按键1按下,向队列写入消息
			 if(xReturn==pdPASS)
			 {
				 printf("往队列queue_handle写入数据成功!!\n");
			 }
			 
		 }
		 else if(key==KEY1_PRES)
		 {
			 xSemaphoreGive(semphr_handle);                  //按键0按下,释放二值信号量
			 if(xReturn==pdPASS)
			 {
				 printf("释放信号量成功!!\n");
			 }
		 }
         vTaskDelay(10);       //FreeRTOS自带的延时函数,延时10毫秒
	
	}	
}



/********任务2的任务函数,无返回值且是死循环***********/

/***任务2:获取队列集的消息*******/
void task2(void* args)
{
	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\n",key);
			
		}
		else if(member_handle==semphr_handle)
		{
			xSemaphoreTake(member_handle,portMAX_DELAY);
			printf("获取信号量成功!\n");
		}
	}	
}



//FreeRTO入口例程函数,无参数,无返回值
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();  //开启任务调度器
	
}




主函数调用文件

#include "stm32f4xx.h"                  // Device header
#include "stdio.h"
#include "myled.h"
#include "myusart.h"


#include "FreeRTOS.h"
#include "task.h"
#include "dynamic.h"

extern TaskHandle_t Start_Handle;

int main(void)
{
    //硬件初始化
     My_UsartInit();
    
	
	
	
	 //调用入口函数
     freertos_demo();
	 
}

至此,已经讲解完毕!初次学习,循序渐进,一步步掌握即可!以上就是全部内容!请务必掌握,创作不易,欢迎大家点赞加关注评论,您的支持是我前进最大的动力!下期再见!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【JS】理解闭包及其应用

历史小剧场 明朝灭亡,并非是简单的政治问题,事实上,这是世界经济史上的一个重要案例。 所谓没钱,就是没有白银。----《明朝那些事儿》 什么是闭包? 闭包就是指有权访问另一个函数作用域中变量的函数 闭包变量存储位置&…

六、【源码】SQL执行器的定义和实现

源码地址:https://github.com/mybatis/mybatis-3/ 仓库地址:https://gitcode.net/qq_42665745/mybatis/-/tree/06-sql-executor SQL执行器的定义和实现 之前的Sql执行都是耦合在SqlSession里的,现在要对这部分进行解耦和重构,引…

1奇函数偶函数

文章目录 自变量有理化奇偶性周期性初等函数 自变量 自变量是x,这个还挺奇怪,记住就好 y f ( e x 1 ) yf(e^x1) yf(ex1) 里面 e x e^x ex 只算中间变量,自变量是x 做这些题,想到了以前高中的时候做数学题,不够扎实…

Java 18 的主要新特性和代码演示

默认 UTF-8 从 JDK8 开始,UTF-8 就是 Java SE API 的默认字符集。java.nio.charset.Charset#defaultCharset() 现在默认返回 UTF-8 。现在 Java 的标准 API 都默认使用 UTF-8 编码,目的是让 Java 程序可预测和可移植。在之前, 读取同一个文件…

从《千脑智能》看大模型

千脑智能与大模型 千脑智能介绍 世界模型千脑智能理论——对大脑的全新理解旧大脑:演化的历史烙印新大脑:智慧的创新引擎新旧大脑的互动与争斗启示与借鉴 大脑对信息的处理和建模六根六尘六识 新脑:智能的创新中枢旧脑:生存的本能…

数据结构笔记 4 树和二叉树

二叉树和完全二叉树的区别? 二叉树和完全二叉树的主要区别在于它们的结构特性和节点排列方式: 1. **二叉树**: - 是一种数据结构,其中每个节点最多有两个子节点,通常称为左子节点和右子节点。 - 节点的子节点数量…

用爬虫实现---模拟填志愿

先来说实现逻辑,首先我要获取到这个网站上所有的信息,那么我们就可以开始对元素进行检查 我们发现他的每一个学校信息都有一个对应的属性,并且是相同的,那么我们就可以遍历这个网页中的所有属性一样的开始爬取 在来分析&#xff0…

探索智慧商场的功能架构与应用

在数字化和智能化的浪潮下,智慧商场已经成为零售业的重要发展方向之一。智慧商场系统的功能架构设计与应用,结合了现代信息技术和零售业的实际需求,为商场的管理和运营提供了全新的解决方案。本文将深入探讨智慧商场的功能架构与应用&#xf…

如何将 Windows图片查看器的背景颜色改成浅色(灰白色)?

现在大家基本都在使用Win10系统,我们在双击查看图片时,系统默认使用系统自带的图片(照片)查看器去打开图片。图片查看器的背景色默认是黑色的,如下所示:(因为大家可能会遇到同样的问题&#xff…

ctfshow-web入门-命令执行(web29)五种解法绕过文件名检测

命令执行,需要严格的过滤 进入 php 代码审计了: 第一题代码很简单,就是对 preg_match 绕过,只要提交的参数值不出现 flag 就行 先看一下当前目录下的文件,构造 payload: ?csystem(ls); 可以看到 flag 就…

MSP432E401Y Launchpad硬件电路

MSP432E401Y是一款32位Arm Cortex-M4F内核的MCU,主频120MHz、256KB SRAM、1MB Flash、6KB EEPROM,具有丰富的通信外设,例如支持以太网、2个CAN、8个UART、4个QSSI(SPI)、10 个I2C; 同时还有2个12 位SAR的ADC模块,每个模块支持高…

【Java】解决Java报错:NullPointerException

文章目录 引言1. 错误详解2. 常见的出错场景2.1 调用 null 对象的实例方法2.2 访问 null 对象的属性2.3 自动拆箱引起的 NullPointerException 3. 解决方案3.1 使用条件判断防止 NullPointerException3.2 优先使用Optional类 4. 预防措施4.1 在方法入口进行校验4.2 使用注解提高…

Elastic 8.14:用于简化分析的 Elasticsearch 查询语言 (ES|QL) 正式发布

作者:来自 Elastic Brian Bergholm 今天,我们很高兴地宣布 Elastic 8.14 正式发布。 什么是新的? 8.14 版本最重要的标题是 ES|QL 的正式发布(GA),它是从头开始设计和专门构建的,可大大简化数据调查。在新的查询引擎的…

【CTF MISC】XCTF GFSJ0290 reverseMe Writeup(图像处理)

reverseMe 暂无 解法 导入 Photoshop。 水平翻转,得到 flag。 Flag flag{4f7548f93c7bef1dc6a0542cf04e796e}声明 本博客上发布的所有关于网络攻防技术的文章,仅用于教育和研究目的。所有涉及到的实验操作都在虚拟机或者专门设计的靶机上进行&#xf…

实战项目《负载均衡在线OJ系统》

一、项目灵感来源 在日常做题的过程中,我们总会去力扣和牛客网上去做题,但是从来没有想过网站是如何加载给用户的,以及在提交代码时,是如何得知我们的代码是否正确。基于这样的原因,也是学习到一定程度的知识后&#x…

2024真机项目

项目需求: 1. 172.25.250.101 主机上的 Web 服务要求提供 www.exam.com 加密站点,该站点在任何路由可达 的主机上被访问,页面内容显示为 "Hello,Welcome to www.exam.com !",并提供 content.exam.com/yum/A…

【C语言】文件操作(终卷)

前言 我们在上一卷中了解了顺序读写的函数,现在就让我们从随机读写的函数开始吧。 什么是随机读写? 就是想在哪个位置读或写都行,比较自由。文件打开时光标默认在起始位置。想从后面的某个部分读或写,就得让文件指针来到那个位…

【C语言】宏详解(上卷)

前言 紧接着预处理详解(上卷),接下来我们来讲宏(隶属于预处理详解系列)。 #define定义宏 #define机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro&#xff…

图解 Python 编程(12) | 文件和编码方式

🌞欢迎来到Python 的世界 🌈博客主页:卿云阁 💌欢迎关注🎉点赞👍收藏⭐️留言📝 🌟本文由卿云阁原创! 📆首发时间:🌹2024年6月9日&am…

使用 Scapy 库编写 TCP 劫持攻击脚本

一、介绍 TCP劫持攻击(TCP Hijacking),也称为会话劫持,是一种攻击方式,攻击者在合法用户与服务器之间的通信过程中插入或劫持数据包,从而控制通信会话。通过TCP劫持,攻击者可以获取敏感信息、执…