任务与任务之间、任务与中断之间经常需要进行一些信息交互和消息传递。FreeRTOS利用队列来实现任务间的通信,队列可以用于在任务与任务之间、任务与中断之间传递消息,所以又被称为消息队列。另外,用于资源共享和访问的二值信号量、计数信号量、互斥信号量和递归互斥信号量也都是通过队列来实现的,这个我们后面在细说。
1 FreeRTOS队列及其结构
队列是一种特殊的数据结构,可以保存有限个具有确定长度的数据单元。队列可以保存的最大单元数目被称为队列的深度,在创建队列时需要设定其深度和每个单元的大小。
2 FreeRTOS队列特性
2.1 存储数据
通常情况下,队列作为FIFO(先进先出)结构使用,即数据从队列尾写入,从队列读出,当然,从队列首写入也是可以的。FreeRTOS向队列写入数据是通过字节复制把据复制存储到队列中的,而不是通过数据引用(只传递数据指针)的方式实现的。从队中读出数据将删除队列中复制的数据。
2.2 多任务访问
队列不属于某个任务,所有任务都可以操作队列,向队列发送消息,或者从队列中获
息,前提是队列要在操作之前创建好。
2.3 读队列时阻塞
当某个任务试图读一个队列时,可以指定一个阻塞超时时间,在这段时间中,如果队列为空,那么该任务将保持阻塞态以等待队列数据有效。如果其他任务或中断服务示例程序向其等待的队列中写入了数据,那么该任务将自动由阻塞态转为就绪态。当等待的时间超过了指定的阻塞超时时间时,即使队列中尚无有效数据,任务也会自动从阻塞态转为就绪态。
由于队列可以被多个任务读取,所以对单个队列而言,也可能有多个任务处于阻塞态以等待队列数据有效。在这种情况下,一旦队列数 据有效,只会有一个任务被解除阻塞态,这个任务就是所有等待任务中优先级最高的任务。如果所有等待任务的优先级相同,那么被解除阻塞态的任务将是等待最久的任务。
2.4 写队列时阻塞
同读队列一样,任务也可以在写队列时指定一个阻塞超时时间,这个时间是当被写队列已满时,任务进入阻塞态以等待队列空间有效的最长时间。
由于队列可以被多个任务写入,所以对单个队列而言,也可能有多个任务处于阻塞态以等待队列空间有效。在这种情况下,一旦队列空间有效,只会有一个任务被解除阻塞态,这个任务就是所有等待任务中优先级最高的任务。如果所有等待任务的优先级相同,那么被解除阻塞态的任务将是等待最久的任务。
2.5 队列读写过程4
创建一个队列Queue用于进行任务1和任务2之间的通信,此队列最多可以保存5个字符。队列在刚创建好时是空的,不包含任务数据单元。
任务1将一个本地变量的值写入队列(入队),由于队列之前是空的,所以写入的值目前是队列中唯一的数据单元,队列尾和队列首同是这个值。
任务1改变本地变量的值并再次写入队列,由于之前队列首已经有数值了,新写入的值被插入队列尾,紧跟在第一个值之后,现在队列中还有3个空的数据单元。
任务2从队列读取(接受)数据到本地变量,读取的值是队列首的数值,即任务1第一次写入的值。
任务2已经读走了一个数据单元,现在队列中只剩下任务1第二次写入的值,这个值将在任务2下一次读队列时被读走,目前队列中空数据单元变为4个。
3 队列结构体
FreeRTOS用结构体Queue_t描述队列,在queue.c文件中定义,旧版本类型名为xQUEUE,新版本类项名为Queue_t,省略部分条件编译代码的定义为:
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; /*队列中每个队列项的最大长度,单位为B*/
volatile int8_t cRxLock; /*队列上锁后,存储从队列中接收到的队列项数*/
volatile int8_t cTxLock; /*队列上锁后,存储发送到队列的队列项数量*/
#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the memory used by the queue was statically allocated to ensure no attempt is made to free the memory. */
#endif
#if ( configUSE_QUEUE_SETS == 1 )
struct QueueDefinition *pxQueueSetContainer;
#endif
#if ( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxQueueNumber;
uint8_t ucQueueType;
#endif
} xQUEUE;
/*新版本队列类项名*/
typedef xQUEUE Queue_t
队列结构体类型中定义了队列长度,队列项大小,操作队列的指针,以及入队阻塞任务列表和出队阻塞列表等成员。