11,FreeRTOS队列理论知识
一、什么是队列?
队列是任务到任务、任务到中断、中断到任务数据交流的一种机制(消息传递)。类似全局变量。
全局变量在两个任务中操作时,由于没有临界区代码保护,容易产生bug,导致运算出错。
队列在多任务中操作时,每次入队、出队都会进入代码保护,并且根据任务优先级、等待时间依次入队、出队。保证数据质量安全。
在队列中可以存储数量有限、大小固定的数据。队列中的每一个数据叫做“队列项目”,队列能够存储“队列项目”的最大数量称为队列的长度。
二、队列的特点?
1.数据入队出队方式。
FreeRTOS可以配置队列入队出队方式为:“先入先出(默认FIFO)”、“后入先出(LIFO)”。
2.数据传递方式。
实际值传输:将数据实际值复制到队列中,小变量时使用。
地址指针传输:将数据的存储地址复制到队列中,大数据时使用,提高效率。
3.多任务访问。
队列不属于某个任务,任何任务、中断都可以访问。
4.入队、出队堵塞。
可以设置堵塞时间,作为满队列(入队)、空队列(出队)时的缓冲。
阻塞时间为0:直接返回不等待;
阻塞时间为0-port_MAX_DELAY(最大等待时间):在阻塞时间内等待,满足条件入队、出队。
阻塞时间为port_MAX_DELAY(最大等待时间):死等,直到完成入队、出队操作。
三、队列结构体介绍?
队列结构体主要分为两部分:队列结构体存储区、队列项(消息)存储区。
1.队列结构体存储区主要存储队列创建时的属性信息。
pcHead:队列项首地址。指向第一个队列项的首地址。
pcWriteTo:下一个写入队列项地址。指向下一个要写入队列项的首地址。
xQueue.pcTail:队列末地址。指向最后一个队列项末尾地址。
xQueue.pcReadFrom:下一个读出队列项地址。指向下一个要读出队列项的首地址。
xTaskWaitingToSend:等待发送列表。
xTaskWaitingToReceive:等待接收列表。
uxMEssagesWaiting:已经写入数据的列表项个数,最大值为队列长度。
uxLength:队列长队。
uxItemSize:列表项大小,单位为字节。
cTxLock/cRxLock:发送阻塞/接收阻塞信号。使能后不阻塞发送/接收。
2.队列项(消息)存储区主要存储队列项。
该存储区域大小固定为:uxLength*uxItemSize(字节)。
四、队列相关API函数。
1.创建队列相关API函数
动态和静态创建队列之间的区别:队列所需的内存空间由FreeRTOS从FreeRTOS管理的堆中分配,而静态创建需要用户自行分配内存。
1.1动态创建队列函数xQueueCreate()
输入值:uxQueueLength 队列长度、uxItemSize 队列项目的大小。
返回值:NULL队列创建失败、其他值队列创建成功,返回队列的起始地址。
#define xQueueCreate( uxQueueLength, uxItemSize ) xQueueGenericCreate( ( uxQueueLength ), ( uxItemSize ), ( queueQUEUE_TYPE_BASE ))
1.2静态创建队列函数xQueueCreateStatic()
输入值:uxQueueLength 队列长度、uxItemSize 队列项目的大小。pucQueueStorage 队列存储区域的起始地址、pxQueueBuffer 静态队列结构体。
返回值:NULL队列创建失败、其他值队列创建成功,返回队列的起始地址。
#define xQueueCreateStatic( uxQueueLength, uxItemSize, pucQueueStorage, pxQueueBuffer) xQueueGenericCreateStatic( ( uxQueueLength ), ( uxItemSize ), ( pucQueueStorage ), ( pxQueueBuffer ), ( queueQUEUE_TYPE_BASE ))
2.入队(写入消息)相关API函数
2.1队列写入消息函数xQueueSend()
输入值:xQueue待写入的队列、pvItemToQueue 待写入消息、xTicksToWait 阻塞超时时间。
返回值:pdTRUE队列写入成功、errQUEUE_FULL队列写入失败 。
#define xQueueSend( xQueue, pvItemToQueue, xTicksToWait)xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ),queueSEND_TO_BACK)
xQueueSendFromISR()用法一样,仅在中断中使用。pxHigherPriorityTaskWoken 需要任务切换标记。
#define xQueueSendFromISR( xQueue, pvItemToQueue, pxHigherPriorityTaskWoken) xQueueGenericSendFromISR( ( xQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueSEND_TO_BACK)
2.2队列尾部写入消息函数xQueueSendToBack()
输入值:xQueue待写入的队列、pvItemToQueue 待写入消息、xTicksToWait 阻塞超时时间。
返回值:pdTRUE队列写入成功、errQUEUE_FULL队列写入失败 。
#define xQueueSendToBack( xQueue, pvItemToQueue, xTicksToWait) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK)
xQueueSendToBackFromISR()用法一样,仅在中断中使用。pxHigherPriorityTaskWoken 需要任务切换标记。
2.3队列头部写入消息函数xQueueSendToFront()
输入值:xQueue待写入的队列、pvItemToQueue 待写入消息、xTicksToWait 阻塞超时时间。
返回值:pdTRUE队列写入成功、errQUEUE_FULL队列写入失败 。
#define xQueueSendToFront( xQueue, pvItemToQueue, xTicksToWait) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_FRONT)
xQueueSendToFrontFromISR()用法一样,仅在中断中使用。pxHigherPriorityTaskWoken 需要任务切换标记。
2.4队列覆盖消息函数xQueueOverwrite()
注意:此函数只能在队列长度为1时使用,使用后覆盖队列项内容。
输入值:xQueue待写入的队列、pvItemToQueue 待写入消息。
返回值:pdTRUE队列写入成功、errQUEUE_FULL队列写入失败 。
#define xQueueOverwrite( xQueue, pvItemToQueue)
xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), 0, queueOVERWRITE)
xQueueOverwriteFromISR()用法一样,仅在中断中使用。pxHigherPriorityTaskWoken 需要任务切换标记。
3.出队(读出消息)相关API函数
3.1队列读消息并删除函数xQueueReceive()
输入值:xQueue待写入的队列、pvBuffer 信息读取缓冲区、xTicksToWait 阻塞超时时间。
返回值:pdTRUE读取成功、pdFALSE读取失败。
BaseType_t xQueueReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait);
xQueueReceiveFromISR()用于中断中,pxHigherPriorityTaskWoken 需要任务切换标记。
3.2队列读消息函数xQueuePeek()
输入值:xQueue待写入的队列、pvBuffer 信息读取缓冲区、xTicksToWait 阻塞超时时间。
返回值:pdTRUE读取成功、pdFALSE读取失败。
BaseType_t xQueuePeek( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait);
xQueuePeekFromISR()用于中断中,pxHigherPriorityTaskWoken 需要任务切换标记。