一、什么是消息队列
队列是不同任务、中断中数据传递的一种机制,又称消息队列。就类似于全局变量,将数据传输到不同的任务中。但全局变量没有写保护,容易造成数据受损。而消息队列中加入了进入临界区的写保护。
队列类似于数组,可以存储数量有限,大小固定的数据。队列中的每个数据叫做队列项目,能存储最大队列项目的数量交队列的长度。
二、队列的特点
1、入队出对的方式通常为先进先出,也可配置为后进先出;
2、数据的传递可以采用值传递,也可以是传递指针;
3、入队出队阻塞:当队列满了无法入队或队列空了无法出队时,称为入队和出队阻塞。可在任务向队列发送消息的时候设置阻塞时间。
如果阻塞时间为0,直接继续执行下面代码,不等待;
如果阻塞时间为0~FFFFFFFF,等待设定的时间,如果在这段时间内还无法入队/出队,则不等待;
如果阻塞时间为FFFFFFFF,一直等到可以入队/出队为止。
4、在等待(即阻塞)过程中,该任务的状态列表项被挂在到阻塞列表中(pxDelayedTaskLits),事件列表项被挂在在等待接收(xTasksWaitingToReceive)/发送列表(xTasksWaitingToSend)中;
5、多个任务写入满队列时,优先级高的优先写入,如果优先级相同,等待久的优先写入。
三、队列的相关API函数
1、队列结构体
typedef struct QueueDefinition
{int8_t *pcHead;						/*< 指向队列存储区的开头。 */int8_t *pcTail;						/*< 指向队列存储区的末尾字节。比实际需要的队列项多分配一个字节,用作标记。 */int8_t *pcWriteTo;					/*< 指向存储区的下一个可用位置。 */union								/* 使用联合体是为了确保两个互斥的结构成员不会同时出现(浪费 RAM)。 */{int8_t *pcReadFrom;				/*< 当结构用作队列时,指向最后读取的队列项的位置。 */UBaseType_t uxRecursiveCallCount;/*< 当结构用作递归互斥锁时,维护互斥锁递归“获取”的次数。 */} u;List_t xTasksWaitingToSend;			/*< 阻塞在此队列上等待发送的任务列表。按优先级排序。 */List_t xTasksWaitingToReceive;		/*< 阻塞在此队列上等待读取的任务列表。按优先级排序。 */volatile UBaseType_t uxMessagesWaiting;	/*< 当前队列中的项数。 */UBaseType_t uxLength;				/*< 队列的长度,定义为它可以容纳的项数,而不是字节数。 */UBaseType_t uxItemSize;				/*< 队列将容纳的每个项的大小。 */volatile int8_t cRxLock;			/*< 存储在队列被锁定时从队列接收的项数(从队列中移除)。当队列未被锁定时,设置为 queueUNLOCKED。 */volatile int8_t cTxLock;			/*< 存储在队列被锁定时传输到队列的项数(添加到队列中)。当队列未被锁定时,设置为 queueUNLOCKED。 */#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )uint8_t ucStaticallyAllocated;	/*< 如果队列的内存是静态分配的,则设置为 pdTRUE,以确保不会尝试释放内存。 */#endif#if ( configUSE_QUEUE_SETS == 1 )struct QueueDefinition *pxQueueSetContainer;#endif#if ( configUSE_TRACE_FACILITY == 1 )UBaseType_t uxQueueNumber;uint8_t ucQueueType;#endif} xQUEUE;
2、创建队列
| 函数 | 描述 | 
| xQueueCreate() | 动态方式创建队列 | 
| xQueueCreateStatic() | 静态方式创建队列 | 
#define xQueueCreate( uxQueueLength, uxItemSize ) xQueueGenericCreate( ( uxQueueLength ), ( uxItemSize ), ( queueQUEUE_TYPE_BASE ) )创建的函数使用宏定义,返回值是成功返队列句柄,失败返回NULL。
创建的函数一共有三个参数。第一个是队列的长度,第二个是队列项目的大小,第三个是队列的类型,队列有如下类型:
#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 )    /*< 递归互斥锁队列类型。 */
3、写入消息
前四个为任务级,后四个为中断级。
| 函数 | 描述 | 
| xQueueSend() | 往队列的尾部写入消息 | 
| xQueueSendToBack() | 同xQueueSend() | 
| xQueueSendToFront() | 往队列的头部写入消息 | 
| xQueueOverwrite() | 覆盖队列消息(只用于队列长度为1的情况) | 
| xQueueSendFromISR() | 在中断中往队列的尾部写入消息 | 
| xQueueSendToBackFromISR() | 同xQueueSendFromISR() | 
| xQueueSendToFrontFromISR() | 在中断中往队列的头部写入消息 | 
| xQueueOverwriteFromISR() | 在中断中覆盖队列消息(只用于队列长度为1的情况) | 
#define xQueueSend( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )队列写入消息都调用的是此函数,只是第四个参数不同。
函数写入成功返回pdTRUE,写入失败返回errQUEUE_FULL。
第一个参数表示要写入的队列,第二个参数表示要写入的消息,第三个参数表示阻塞时间,第四个参数是写入方式,有下面三种:
#define queueSEND_TO_BACK		( ( BaseType_t ) 0 )   /*< 将项目发送到队列的后面。 */
#define queueSEND_TO_FRONT		( ( BaseType_t ) 1 )   /*< 将项目发送到队列的前面。 */
#define queueOVERWRITE			( ( BaseType_t ) 2 )   /*< 覆盖队列中已有的项目。 */
4、读取消息
前两个为任务级,后两个为中断级。
| 函数 | 描述 | 
| xQueueReceive() | 从队列头部读取消息,删除消息 | 
| xQueuePeek() | 从队列头部读取消息 | 
| xQueueReceiveFromISR() | 在中断中从队列头部读取消息,删除消息 | 
| xQueuePeekFromISR() | 在中断中从队列头部读取消息 | 
#define xQueueReceive( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdFALSE )
该函数有三个参数,分别是待读取的队列,信息读取缓冲区,阻塞时间。
读取成功返回pdTRUE,失败返回pdFALSE