14.1.2 队列的函数解析
1.队列结构体
队列采用队列结构体来进行管理,包括消息的存储位置、头指针pcHead、尾指针pcTail、消息大小uxItemSize,以及队列长度uxLength等。每个队列都与消息空间在同一段连续的内存空间中,在创建成功的时候,这些内存就被占用了,只有删除队列,这段内存才会被释放掉。每个消息空间可以存放不大于消息大小uxItemSize的任意类型的数据,所有队列中的消息空间总数即队列的长度,这个长度可在队列创建时指定。
FreeRTOS队列的控制块为Queue_t,该结构体在文件“queue.c”中定义,原型如下。


2.队列创建
在应用队列之前,要先创建一个队列。创建队列有动态创建和静态创建两种方法,其对应的函数为xQueueCreate()和xQueueCreateStatic()。这两个函数本质上都是宏,真正完成队列创建的函数是xQueueGenericCreate()和xQueueGenericCreateStatic(),这两个函数在文件“queue.c”中定义。下面以xQueueGenericCreate()函数为例进行分析。
函数xQueueGenericCreate()在文件“queue.c”中定义,函数原型如下。


函数的输入参数如下。
①uxQueueLength:要创建的队列长度。
②uxItemSize:单个队列项的大小,单位为字节。
③ucQueueType:类型,可以为以下值。
•queueQUEUE_TYPE_BASE:表示队列。
•queueQUEUE_TYPE_SET:表示队列集合。
•queueQUEUE_TYPE_MUTEX:表示互斥信号量。
•queueQUEUE_TYPE_COUNTING_SEMAPHORE:表示计数信号量。
•queueQUEUE_TYPE_BINARY_SEMAPHORE:表示二值信号量。
•queueQUEUE_TYPE_RECURSIVE_MUTEX:表示递归互斥信号量。
函数的返回值如下。
pxNewQueue:消息队列控制块,一个结构体指针(QueueHandle_t句柄,实际是void*),即队列在内存中的地址。

函数xQueueGenericCreate()最主要的作用就是给队列分配内存,当内存分配成功以后,调用函数prvInitialiseNewQueue()来初始化队列。
队列初始化函数prvInitialiseNewQueue()在文件“queue.c”中定义,函数原型如下。

队列初始化完成后,还要调用队列复位函数xQueueGenericReset()来完成最终的初始化工作,该函数会调用vListInitialise()函数构建列表结构。函数原型如下。


以创建一个有4个队列项、每个队列项长度为32个字节的队列TestQueue为例,创建成功的初始队列结构如图14.4所示。

图14.4 初始队列结构
3.队列发送消息
创建好队列以后,就可以向队列发送消息了,这一过程被称为入队。FreeRTOS提供了8个向队列发送消息的API函数(队列入队函数),分为任务级队列的发送函数和中断级队列的发送函数,相关函数请读者参见第12章的表12.4。(https://www.daowen.com)
任务级队列的发送函数有前向入队、后向入队、覆写入队等函数,可以适应不同的应用需求,它们均是使用xQueueGenericSend()函数来实现的。
中断级队列的发送函数有前向入队、后向入队、覆写入队等函数,可以适应不同的应用需求,它们均是使用xQueueGenericSendFromISR()函数来实现的。
下面以任务级队列的发送函数xQueueSend()和中断级队列的发送函数xQueueSendFromISR()为例进行分析,均是发到队列尾部,其他函数请读者自行分析。
(1)任务级队列发送函数xQueueSend()。
任务级队列发送函数xQueueSend()的原型如下。


该函数返回pdPASS表示向队列发送消息成功,否则表示不成功。
xQueueSend()函数实际是通过xQueueGenericSend()函数完成发送的,该函数的原型如下。

(2)中断级队列发送函数xQueueSendFromISR()。
中断级队列发送函数xQueueSendFromISR()的原型如下。
![]()
①输入参数如下。
•xQueue:队列句柄,表明要向哪个队列发送数据。
•pvItemToQueue:指向要发送的消息,发送的过程中会将这个消息复制到队列中。
•pxHigherPriorityTaskWoken:标记退出此函数后是否进行任务切换,为pdTRUE表示切换。
②返回参数。该函数无返回参数。
该函数宏定义如下。

4.队列接收消息
队列接收消息即从消息队列中接收一组数据,这一过程被称为出队。FreeRTOS有4个队列接收函数(队列出队函数),参见第12章的表12.4,分为任务级队列接收函数和中断级队列接收函数。
任务级队列接收函数有读取完后删除函数xQueueReceive(),读取完后不删除函数xQueuePeek()两种。
中断级队列接收函数有读取完后删除函数xQueueReceiveFromISR(),读取完后不删除函数xQueuePeekFromISR()两种。
下面主要分析函数xQueueReceive()和xQueueReceiveFromISR(),其他函数请读者自行分析。
(1)任务级队列接收函数。
xQueueReceive()函数用于从队列中读取一条(请求)消息,读取成功以后就会将队列中的这条数据删除,此函数的本质是一个宏,真正执行的函数是xQueueGenericReceive()。此函数在读取消息的时候是采用复制方式的,所以用户需要提供一个数组或缓冲区来保存读取到的数据,所读取的数据长度是创建队列的时候所设定的每个队列项长度,函数原型如下。


该函数返回pdTRUE表示从队列中读取数据成功,返回pdFALSE表示从队列中读取数据失败。
(2)中断级队列接收函数。
xQueueReceiveFromISR()函数原型如下。

综上所述,任务获取队列中的消息采用xQueueReceive()函数,在中断服程序中获取队列中的消息采用xQueueReceiveFromISR()函数。这两个函数不能混合使用,注意应用场合。