14.1.1 队列基础知识
在FreeRTOS中,队列可以存储有限的、大小固定的数据项目。队列所能保存的最大数据项目的数量叫作队列的长度,创建队列的时候会指定数据项目的大小和队列的长度。队列是用来实现任务间消息传递的,所以也被称为消息队列。
1.队列的数据存储
在FreeRTOS中,队列采用先进先出(First Input First Output,FIFO)的存储缓冲机制。往队列中存放数据叫入队,从队列中取数据叫出队。队列也可以使用后进先出(Last Input First Output,LIFO)的存储缓冲机制。
数据存放到队列中会导致值复制,也就是存放数据到队列中,而不是采用数据指针(这种方法叫值传递)。采用值传递,当消息存放到队列中后,就可以删除原始的数据缓冲区,缓冲区就可以重复使用。FreeRTOS使用的是值复制,也可以采用值传递,直接往队列中放入发送消息缓冲区的地址的指针。
创建队列时,FreeRTOS会先给队列分配一块内存空间,这块内存的大小等于队列控制块大小加上单个队列空间大小与队列长度的乘积,再初始化消息队列,此时消息队列为空。
2.队列访问
在FreeRTOS中,队列不属于某个特定的任务,任何任务或中断都可以向队列发送消息,或者从队列中提取消息。
3.队列阻塞机制发送消息
队列是一种公共资源,任何任务或中断都可以对其进行读写操作,某个任务对它进行读写操作的时候,必须保证该任务能正常完成读写操作,而不受后来的任务干扰。FreeRTOS的阻塞机制可以用来实现这一过程。
(1)当任务或中断发送消息时,如果队列未满或允许覆盖入队,FreeRTOS会将消息复制到队列队尾,否则会根据用户指定的阻塞超时时间进行阻塞。在这段时间中,如果队列一直不允许入队,该任务将保持阻塞态以等待队列允许入队。
(2)当其他任务从其等待的队列中读取出了数据(队列未满)时,该任务将自动由阻塞态转换为就绪态。
(3)当等待的时间超过了指定的阻塞时间时,即使队列中还不允许入队,任务也会自动从阻塞态转换为就绪态,此时发送消息的任务或中断程序会收到一个错误码errQUEUE_FULL。
(4)发送紧急消息的过程与发送消息几乎一样,唯一的不同是当发送紧急消息时,发送的位置是队列队头而非队尾,这样接收者就能够优先接收到紧急消息,从而及时处理消息。
(5)假如有多个任务阻塞在一个队列中,那么这些阻塞的任务将按照任务优先级进行排序,优先级高的任务进入就绪态。若优先级相同,则等待时间最久的任务进入就绪态。(https://www.daowen.com)
4.队列阻塞机制接收消息
(1)队列接收消息就是从队列中提取消息。当任务读队列时,若队列有数据,则依次读取;若队列没有数据,则该任务可以进入阻塞态,还可以指定阻塞时间。若在阻塞时间内队列有数据,则该阻塞的任务会转换为就绪态。若队列一直都没有数据,则阻塞时间到了后,该阻塞任务也会进入就绪态。
(2)读取队列的任务个数没有限制,当多个任务读取空队列时,这些任务都会进入阻塞状态。当队列中有数据时,优先级最高的任务先获得数据;如果优先级相同,那么等待时间最久的任务会进入就绪态。
5.队列操作过程
(1)创建一个队列,如图14.1所示。任务TaskA和任务TaskB之间进行通信,队列数据项目的长度为5,数据类型为整型。

图14.1 创建队列
(2)任务TaskA往队列中发送第一个消息,值为10。任务TaskA往队列中再发送一个消息,值为50,这时队列剩余空间大小为3。写数据到队列过程如图14.2所示。

图14.2 写数据到队列过程
(3)从队列中取一个消息。任务TaskB从队列中取一个消息,从队列头开始取(值为10),队列中剩下一个消息,剩余空间大小为4。从队列读数据过程如图14.3所示。

图14.3 从队列读数据过程