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

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

  • 31
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

未来可期,静待花开~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值