今天主要来讲讲消息队列相关的API。
1、函数xQueueCreate()
该函数本质上是一个宏,用来动态创建队列,该宏最终调用的是函数xQueueGenericCreate(),函数原型如下:
xQueueCreate( uxQueueLength, uxItemSize )
参数 | 描述 |
---|---|
uxQueueLength | 要创建的队列的队列长度,这里是队列的项目数。 |
uxItemSize | 队列中每个项目(消息)的长度,单位为字节 |
返回值 | 队列创捷成功以后返回的队列句柄! |
2、函数xQueueCreateStatic()
此函数也是用于创建队列的,但是使用的静态方法创建队列,队列所需要的内存由用户自行分配,此函数本质上也是一个宏,此宏最终调用的是函数xQueueGenericCreateStatic(),函数原型如下:
QueueHandle_t xQueueCreateStatic(
UBaseType_t uxQueueLength,
uxUBaseType_t uxItemSize,
uint8_t* pucQueueStorageBuffer,
StaticQueue_t* pxQueueBuffer)
参数 | 描述 |
---|---|
uxQueueLength | 要创建的队列的队列长度,这里是队列的项目数 |
uxItemSize | 队列中每个项目(消息)的长度,单位为字节 |
pucQueueStorageBuffer | 指向队列项目的存储区,也就是消息的存储区,这个存储区需要用户自行分配。此参数必须指向一个uint8_t类型的数组。这个存储区要大于等于(uxQueueLength*uxItemsSize)字节 |
pxQueueBuffer | 此参数指向一个StaticQueue_t类型的变量,用来保存队列结构体 |
返回值 | 创建成功返回队列句柄 |
3、函数xQueueGenericCreate()
函数xQueueGenericCreate()用于动态创建队列,创建队列过程中需要的内存均通过FreeRTOS中的动态内存管理函数pvPortMalloc()分配,函数原型如下:
QueueHandle_t xQueueGenericCreate(
const UBaseType_t uxQueueLength,
const UBaseType_t uxItemSize,
const uint8_t ucQueueType)
参数 | 描述 |
---|---|
uxQueueLength | 要创建的队列的队列长度,这里是队列的项目数。 |
uxItemSize | 队列中每个项目(消息)的长度,单位为字节。 |
ucQueueType | 队列类型,由于FreeRTOS中的信号量等也是通过队列来实现的,创建信号量的函数最终也是使用此函数的,因此在创建的时候需要指定此队列的用途,也就是队列类型,一共有六种类型 |
返回值 | 创建成功返回队列句柄,NULL表示创建失败 |
其中六种类型为:
函数xQueueCreate()创建队列的时候此参数默认选择的就是queueQUEUE_TYPE_BASE。
4、函数xQueueGenericCreateStatic()
此函数用于动态创建队列,创建队列过程中需要的内存需要由用户自行分配好,函数原型如下:
QueueHandle_t xQueueGenericCreateStatic(
const UBaseType_t uxQueueLength,
const UBaseType_t uxItemSize,
uint8_t* pucQueueStorage,
StaticQueue_t* pxStaticQueue,
const uint8_t ucQueueType)
参数 | 描述 |
---|---|
uxQueueLength | 要创建的队列的队列长度,这里是队列的项目数。 |
uxItemSize | 队列中每个项目(消息)的长度,单位为字节。 |
pucQueueStorage | 指向队列项目的存储区,也就是消息的存储区,这个存储区需要用户自行分配。此参数必须指向一个uint8_t类型的数组。这个存储区要大于等于(uxQueueLength*uxItemsSize)字节。 |
pxStaticQueue | 此参数指向一个StaticQueue_t类型的变量,用来保存队列结构体。 |
ucQueueType | 队列类型。 |
返回值 | 创建成功返回队列句柄,NULL表示创建失败 |
1、队列创建函数详解
最终完成队列创建的函数有两个,一个是静态方法的xQueueGenericCreateStatic(),另外一个就是动态方法的xQueueGenericCreate()。现在来详细的分析一下动态创建函数xQueueGenericCreate(),静态方法大同小异,可以自行分析一下。
函数xQueueGenericCreate()在文件queue.c中有如下定义:
QueueHandle_t xQueueGenericCreate(
const UBaseType_t uxQueueLength,
const UBaseType_t uxItemSize,
const uint8_t ucQueueType )
{
Queue_t *pxNewQueue;
size_t xQueueSizeInBytes;
uint8_t *pucQueueStorage;
configASSERT( uxQueueLength > ( UBaseType_t ) 0 );
if( uxItemSize == ( UBaseType_t ) 0 )
{
//队列项大小为0,就不需要存储区
xQueueSizeInBytes = ( size_t ) 0;
}
else
{
//分配足够的存储区,确保随时随地可以保存所有消息
xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ); (1)
}
pxNewQueue = ( Queue_t * ) pvPortMalloc( sizeof( Queue_t ) + xQueueSizeInBytes ); (2)
//内存分配成功
if( pxNewQueue != NULL )
{
pucQueueStorage = ( ( uint8_t * ) pxNewQueue ) + sizeof( Queue_t ); (3)
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
{
//队列是使用动态方法创建的,所以队列字段ucStaticallyAllocated标记为pdFALSE
pxNewQueue->ucStaticallyAllocated = pdFALSE;
}
#endif
prvInitialiseNewQueue( uxQueueLength, uxItemSize, pucQueueStorage, ucQueueType, pxNewQueue ); (4)
}
return pxNewQueue;
}
2、队列初始化函数详解
队列初始化函数prvInitialiseNewQueue() 用于队列的初始化,此函数在文件queue.c中有定义,函数代码如下:
static void prvInitialiseNewQueue(
const UBaseType_t uxQueueLength,
const UBaseType_t uxItemSize,
uint8_t *pucQueueStorage,
const uint8_t ucQueueType,
Queue_t *pxNewQueue )
{
//防止编译器报错
( void ) ucQueueType;
if( uxItemSize == ( UBaseType_t ) 0 )
{
//队列项(消息)长度为0,说明没有队列存储区,这里将pcHead指向队列开始地址
pxNewQueue->pcHead = ( int8_t * ) pxNewQueue;
}
else
{
//设置pcHead指向队列项存储区首地址
pxNewQueue->pcHead = ( int8_t * ) pucQueueStorage;(1)
}
//初始化队列结构体相关成员变量
pxNewQueue->uxLength = uxQueueLength;(2)
pxNewQueue->uxItemSize = uxItemSize;
( void ) xQueueGenericReset( pxNewQueue, pdTRUE );(3)
#if ( configUSE_TRACE_FACILITY == 1 )//跟踪调试相关字段初始化
{
pxNewQueue->ucQueueType = ucQueueType;
}
#endif
#if( configUSE_QUEUE_SETS == 1 )//队列集相关字段初始化
{
pxNewQueue->pxQueueSetContainer = NULL;
}
#endif
traceQUEUE_CREATE( pxNewQueue );
}
3、队列复位函数详解
队列初始化函数 prvInitialiseNewQueue()中调用了函数xQueueGenericReset()来复位队列,函数xQueueGenericReset()代码如下:
BaseType_t xQueueGenericReset(
QueueHandle_t xQueue,
BaseType_t xNewQueue )
{
Queue_t * const pxQueue = ( Queue_t * ) xQueue;
configASSERT( pxQueue );
taskENTER_CRITICAL();
{
//初始化队列相关成员变量
pxQueue->pcTail = pxQueue->pcHead + ( pxQueue->uxLength * pxQueue->uxItemSize );(1)
pxQueue->uxMessagesWaiting = ( UBaseType_t ) 0U;
pxQueue->pcWriteTo = pxQueue->pcHead;
pxQueue->u.pcReadFrom = pxQueue->pcHead + ( ( pxQueue->uxLength - ( UBaseType_t ) 1U ) * pxQueue->uxItemSize );
pxQueue->cRxLock = queueUNLOCKED;
pxQueue->cTxLock = queueUNLOCKED;
if( xNewQueue == pdFALSE )(2)
{
/* 由于复位队列以后队列依旧是空的,所以对于那些由于出队(从队列中读取消息)而阻塞的任务就依旧保持阻塞状态。但是对于那些由于入队(向队列中发送消息)而阻塞的任务就不一样。这些任务要解除阻塞状态,从队列的相应列表中移除 */
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
{
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
{
queueYIELD_IF_USING_PREEMPTION();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
//初始化队列中的列表
vListInitialise( &( pxQueue->xTasksWaitingToSend ) );(3)
vListInitialise( &( pxQueue->xTasksWaitingToReceive ) );
}
}
taskEXIT_CRITICAL();
/* A value is returned for calling semantic consistency with previous
versions. */
return pdPASS;
}