FreeRtos学习--7、队列

1、队列简介

       队列是任务到任务、任务到中断、中断到任务数据交流的一种机制(消息传递),FreeRTOS基于队列, 实现了多种功能,其中包括队列集、互斥信号量、计数型信号量、二值信号量、 递归互斥信号量,因此很有必要深入了解 FreeRTOS 的队列 。 

1.1 队列与全局变量的区别

全局变量:数据五保户,导致数据不安全,当多个任务同时对该变量进行操作时,数据容易损坏;

队列:读写队列做好了保护,防止多任务同时访问冲突,使用只需要直接调用API函数。

1.2 队列的特点

数据入队出队方式:队列通常采用**“先进先出”(FIFO)的数据存储缓冲机制,即先入队的数据会先从队列中被读取,FreeRTOS中也可以配置为“后进先出”LIFO**方式;

数据传递方式:FreeRTOS中队列采用实际值传递,即将数据拷贝到队列中进行传递, FreeRTOS采用拷贝数据传递,也可以传递指针,所以在传递较大的数据的时候采用指针传递

多任务访问:队列不属于某个任务,任何任务和中断都可以向队列发送/读取消息

出队、入队阻塞:当任务向一个队列发送消息时,可以指定一个阻塞时间,假设此时当队列已满无法入队,可以设置0~port_MAX_DELAY阻塞时间用于等待入列。

1.3  队列属性

在队列中可以存储数量有限、大小固定的数据。队列中的每一个数据叫做“队列项目”,队列能够存储“队列项目”的最大数量称为队列的长度 。在创建队列时,就要指定队列长度以及队列项目的大小。

当多个任务写入消息给一个“满队列”时,这些任务都会进入阻塞状态,也就是说有多个任务 在等待同一 个队列的空间。当队列中有空间时,哪个任务会进入就绪态?
1、优先级最高的任务
2、如果大家的优先级相同,那等待时间最久的任务会进入就绪态

 2、队列的结构体

typedef struct QueueDefinition 
{
    int8_t * 				pcHead							/* 存储区域的起始地址 */
    int8_t * 				pcWriteTo;        				/* 下一个写入的位置 */
    union
    {
        QueuePointers_t     xQueue; 
		SemaphoreData_t  	xSemaphore; 
    } u ;
    List_t 					xTasksWaitingToSend; 			/* 等待发送列表 */
    List_t 					xTasksWaitingToReceive;			/* 等待接收列表 */
    volatile 				UBaseType_t uxMessagesWaiting; 	/* 非空闲队列项目的数量 */
    UBaseType_t 			uxLength;						/* 队列长度 */
    UBaseType_t 			uxItemSize;                		/* 队列项目的大小 */
    volatile int8_t 		cRxLock; 						/* 读取上锁计数器 */
    volatile int8_t 		cTxLock;						/* 写入上锁计数器 */
   /* 其他的一些条件编译 */
} xQUEUE;

//当用于队列使用时:
typedef struct QueuePointers
{
     int8_t * 				pcTail; 						/* 存储区的结束地址 */
     int8_t * 				pcReadFrom;						/* 最后一个读取队列的地址 */
} QueuePointers_t;
//当用于互斥信号量和递归互斥信号量时 :
typedef struct SemaphoreData
{
    TaskHandle_t 			xMutexHolder;					/* 互斥信号量持有者 */
    UBaseType_t 			uxRecursiveCallCount;			/* 递归互斥信号量的获取计数器 */
} SemaphoreData_t;

 

3、队列相关的API函数

使用队列的主要流程:创建队列 ---- 写队列 ---- 读队列。

3.1 创建队列

动态方式创建队列:xQueueCreate()

静态方式创建队列:xQueueCreateStatic()

两者区别:队列所需的内存空间由 FreeRTOS 从 FreeRTOS 管理的堆中分配,而静态创建需要用户自行分配内存

#define xQueueCreate(uxQueueLength, uxItemSize)	
		xQueueGenericCreate((uxQueueLength), (uxItemSize),(queueQUEUE_TYPE_BASE ))
#define queueQUEUE_TYPE_BASE                  	( ( uint8_t ) 0U )	/* 队列 */
#define queueQUEUE_TYPE_SET                  	( ( uint8_t ) 0U )	/* 队列集 */
#define queueQUEUE_TYPE_MUTEX                 	( ( uint8_t ) 1U )	/* 互斥信号量 */
#define queueQUEUE_TYPE_COUNTING_SEMAPHORE    	( ( uint8_t ) 2U )	/* 计数型信号量 */
#define queueQUEUE_TYPE_BINARY_SEMAPHORE     	( ( uint8_t ) 3U )	/* 二值信号量 */
#define queueQUEUE_TYPE_RECURSIVE_MUTEX       	( ( uint8_t ) 4U )	/* 递归互斥信号量 */	
  • 形参uxQueueLength:队列长度
  • 形参uxItemSize:队列项目的大小
  • queueQUEUE_TYPE_BASE:宏定义,创建队列的类型,本文是队列
  • 返回值:NULL ,队列创建失败;其他值, 队列创建成功,返回队列句柄【句柄也即是队列的首地址】

3.2 写队列

xQueueSend() :往队列的尾部写入消息
xQueueSendToBack(): 同 xQueueSend()
xQueueSendToFront(): 往队列的头部写入消息
xQueueOverwrite(): 覆写队列消息(只用于队列长度为 1 的情况)
xQueueSendFromISR(): 在中断中往队列的尾部写入消息
xQueueSendToBackFromISR(): 同 xQueueSendFromISR()
xQueueSendToFrontFromISR(): 在中断中往队列的头部写入消息
xQueueOverwriteFromISR(): 在中断中覆写队列消息(只用于队列长度为 1 的情况)

这几个写入函数调用的是同一个函数xQueueGenericSend( ),只是指定了不同的写入位置。

#define queueSEND_TO_BACK                     ( ( BaseType_t ) 0 )		/* 写入队列尾部 */
#define queueSEND_TO_FRONT                    ( ( BaseType_t ) 1 )		/* 写入队列头部 */
#define queueOVERWRITE                        ( ( BaseType_t ) 2 )		/* 覆写队列*/

#define  	xQueueSend(  xQueue,   pvItemToQueue,   xTicksToWait  )	 					\    
	    	xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )
#define  	xQueueSendToBack(  xQueue,   pvItemToQueue,   xTicksToWait  )					 \    
	    	xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )
#define  	xQueueSendToFront(  xQueue,   pvItemToQueue,   xTicksToWait  ) 					\   
	    	xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_FRONT )
#define  	xQueueOverwrite(  xQueue,   pvItemToQueue  ) 								\    
	    	xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), 0, queueOVERWRITE )
BaseType_t	xQueueGenericSend(	QueueHandle_t 			xQueue, 
								const void * const 		pvItemToQueue, 
								TickType_t 				xTicksToWait,
								const BaseType_t 		xCopyPosition);
  • 参数xQueue:待写入的队列
  • 参数pvItemToQueue:待写入消息
  • 参数xTicksToWait:阻塞超时时间
  • 参数xCopyPosition:写入的位置
  • 返回值:pdTRUE,队列写入成功;errQUEUE_FULL ,队列写入失败

const void * const 表示一个不可修改的指针,它指向不可修改的 void 类型数据。void 指针通常用于表示未知类型的数据,而 const 修饰符确保无论是指针本身还是指向的数据都不会被修改。
无论是写入数字还是地址,都只需要把变量的地址传入即可,函数会自动赋值。

3.3 读队列

  • xQueueReceive() :从队列头部读取消息,并删除消息
  • xQueuePeek():从队列头部读取消息
  • xQueueReceiveFromISR() :在中断中从队列头部读取消息,并删除消息
  • xQueuePeekFromISR() :在中断中从队列头部读取消息
BaseType_t	xQueueReceive(	QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait )
BaseType_t  xQueuePeek( 	QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait )
  • 形参xQueue:待读取的队列
  • 形参pvBuffer:信息读取缓冲区
  • 形参xTicksToWait:阻塞超时时间
  • 返回值:pdTRUE,读取成功;pdFALSE,读取失败

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值