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);    //删除开始任务自身,传参NULLtaskEXIT_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.mzph.cn/bicheng/25213.shtml

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

相关文章

详解 Flink 的 ProcessFunction API

一、Flink 不同级别的 API Flink 拥有易于使用的不同级别分层 API 使得它是一个非常易于开发的框架最底层的 API 仅仅提供了有状态流处理,它将处理函数(Process Function )嵌入到了 DataStream API 中。底层处理函数(Process Func…

HarmonyOS开发-鸿蒙UiAbility 组件间跳转

前言 随着春节假期结束各行各业复产复工,一年一度的春招也持续火热起来。最近,有招聘平台发布了《2024年春招市场行情周报(第一期)》。总体来说今年的就业市场还是人才饱和的状态,竞争会比较激烈。 但是,…

Unity编辑器扩展,快捷键的使用

代码部分 编辑器界面 使用方法: 使用方法和如图1一样,只需要在Menuitem的路径后面加上标识符号就行。 "#"对应的是shift "&"对应的是Alt "%"对应的是ctrl 比如我图中的是,%#s对应的是CtrlShifts&…

基于51单片机的串口乒乓球小游戏

基于51单片机的乒乓球小游戏 (仿真+程序) 功能介绍 具体功能: 1.用两块单片机串口进行通信; 2.一排LED模拟乒乓球运动(哪里亮表示运动到哪); 3.当最左边LED亮,表示球…

【java、lucene、python】互联网搜索引擎课程报告二:建立搜索引擎

一、项目要求 建立并实现文本搜索功能 对经过预处理后的500个英文和中文文档/网页建立搜索并实现搜索功能对文档建立索引,然后通过前台界面或者已提供的界面,输入关键字,展示搜索结果前台可通过网页形式、应用程序形式、或者利用已有的界面…

Databricks Data Warehouse

Warehouse features 原来的data warehouse痛点: 用例不兼容的支持模型的安全和管理不兼容不相交和重复的数据 ETL workloads Streaming Architecture Data Science and ML

matplotlib 动态显示训练过程中的数据和模型的决策边界

文章目录 Github官网文档简介动态显示训练过程中的数据和模型的决策边界安装源码 Github https://github.com/matplotlib/matplotlib 官网 https://matplotlib.org/stable/ 文档 https://matplotlib.org/stable/api/index.html 简介 matplotlib 是 Python 中最常用的绘图…

js理解异步编程和回调

什么是异步 计算机在设计上是异步的。 异步意味着事情可以独立于主程序流发生。 当你打开一个网页,网页载入的过程,你又打开了编译器,那么你在网页载入时启动了编译器的行为就是计算机的异步, 可以看出计算机时一个超大的异步…

华为防火墙 1

华为防火墙1 实验拓扑: 实验步骤: 1.完成终端基本IP信息配置 2.配置防火墙: 2.1配置IP地址 sys Enter system view, return user view with CtrlZ. [USG6000V1]undo in e Info: Saving log files… Info: Information center is disabled. […

基于小波脊线的一维时间序列信号分解方法(MATLAB R2018A)

信号分解技术是把一个复杂信号分解为若干含有时频信息的简单信号,研可通过分解后的简单信号来读取和分析复杂信号的有效特征。因此,信号分解技术对分析结果的影响是不言而喻的。 傅里叶分解是早期常用的信号分解方法,最初被用于分析热过程&a…

JavaScript基础(十二)

截取字符串 //对象名.toLowerCase();将字符串转为小写 var strLAOWANG; strstr.toLowerCase(); console.log(str); //对象名.toUpperCase();将字符串转为大写 var str1laowang str1str1.toUpperCase(); console.log(str1); 截取字符串 //方法1:对象名.substr(a,b); …

Unity世界坐标下UI始终朝向摄像机

Unity世界坐标下UI始终朝向摄像机 1、第一种方法UI会反过来 void Update(){this.transform.LookAt(Camera.main.transform.position);}2、第二种方法 Transform m_Camera;void Start(){m_Camera Camera.main.transform;}void LateUpdate(){transform.rotation Quaternion.Lo…

kafka-生产者事务-数据传递语义事务介绍事务消息发送(SpringBoot整合Kafka)

文章目录 1、kafka数据传递语义2、kafka生产者事务3、事务消息发送3.1、application.yml配置3.2、创建生产者监听器3.3、创建生产者拦截器3.4、发送消息测试3.5、使用Java代码创建主题分区副本3.6、屏蔽 kafka debug 日志 logback.xml3.7、引入spring-kafka依赖3.8、控制台日志…

关于烫烫烫和屯屯屯

微较的msvc编译器,调试模式下为了方便检测内存的非法访问,对于不同的内存做了初始化, 未初始化栈: 0xCCCCCCCC 未初始化堆: 0xCDCDCDCD 已释放的堆: 0xDDDDDDDD 0xCCCC解释为GB2312字符即是烫&#xff…

Django 鸡与蛋问题

"Django 的鸡与蛋问题"通常指的是在开始 Django 项目时,你可能会遇到的一个困境:是先设计数据库模型还是先编写视图和控制器(即视图函数)? 这个问题的实质是在于,Django 的核心部分是由数据库模…

Qt5/6使用SqlServer用户连接操作SqlServer数据库

网上下载SQLServer2022express版数据库,这里没啥可说的,随你喜欢,也可以下载Develop版本。安装完后,我们可以直接连接尝试, 不过一般来说,还是下载SQLServer管理工具来连接数据更加方便。 所以直接下载ssms, 我在用的时候,一开始只能用Windows身份登录。 所以首先,我…

入门matlab

常识 如何建一个新文件 创建新文件,点击新建,我们就可以开始写代码了 为什么要在代码开头加入clear 假如我们有2个文件,第一个文件里面给x赋值100,第二个文件为输出x 依次运行: 结果输出100,这是因为它们…

ChatGPT Prompt技术全攻略-精通篇:Prompt工程技术的高级应用

系列篇章💥 No.文章1ChatGPT Prompt技术全攻略-入门篇:AI提示工程基础2ChatGPT Prompt技术全攻略-进阶篇:深入Prompt工程技术3ChatGPT Prompt技术全攻略-高级篇:掌握高级Prompt工程技术4ChatGPT Prompt技术全攻略-应用篇&#xf…

电脑缺失msvcp110.dll文件的解决方法,总结5种靠谱的方法

在计算机使用过程中,我们可能会遇到一些错误提示,其中之一就是“找不到msvcp110.dll”。这个错误提示通常出现在运行某些软件时,那么,它究竟会造成哪些问题呢? 一,msvcp110.dll文件概述 msvcp110.dll是Mic…

推荐云盘哪个好,各有各的优势

选择合适的云盘服务是确保数据安全、便捷分享和高效协作的关键。下面将从多个维度对目前主流的云盘服务进行详细的对比和分析: 速度性能 百度网盘青春版:根据测试,其上传和下载确实不限速,但主要定位是办公人群,适用于…