消息队列可以应用于发送不定长消息的场合,包括任务与任务间的消息交换,队列是
FreeRTOS
主要的任务间通讯方式,可以在任务与任务间、中断和任务间传送信息,发送到
队列的消息是通过拷贝方式实现的,这意味着队列存储的数据是原数据,而不是原数据的
引用。
-
消息队列控制块
typedef struct QueueDefinition
{
int8_t *pcHead; //pcHead 指向队列消息存储区起始位置,即第一个消息空间
int8_t *pcWriteTo; //pcWriteTo 指向队列消息存储区下一个可用消息空间
union
{
QueuePointers_t xQueue; /*结构体,包含pcTail指向队列消息存储区结束位置地址;
pcReadFrom指向出队消息空间的最后一个*/
SemaphoreData_t xSemaphore; /*作为信号量时,用的结构体*/
} u;
List_t xTasksWaitingToSend; //是一个发送消息阻塞列表,如果队列满了想发送消息的任务会阻塞
List_t xTasksWaitingToReceive;//是一个接收消息阻塞列表如果队列为空想接收消息的任务会阻塞
volatile UBaseType_t uxMessagesWaiting;//用于记录当前消息队列的消息个数
UBaseType_t uxLength; //表示队列的长度,Item的数量
UBaseType_t uxItemSize; //表示单元消息的大小,Item的大小
volatile int8_t cRxLock; //队列上锁后,储存从队列收到的列表项数目,也就是出队的数量
volatile int8_t cTxLock; //队列上锁后,储存发送到队列的列表项数目,也就是入队的数量
#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;
3.1动态创建队列xQueueCreate()
3.1.1函数原型
![](https://i-blog.csdnimg.cn/blog_migrate/a6631c33e61b9989ecca3703fd620146.png)
3.1.2函数框架
xQueueCreate()就是调用xQueueGenericCreate()实现的。
3.2动态创建队列xQueueGenericCreate()
3.2.1函数原型
- uxQueueLength:队列长度,Item的数量;
- uxItemSize:消息单元的大小。
- ucQueueType:消息队列类型:
- 返回值:队列句柄。
3.2.2函数框架
3.3静态创建队列xQueueCreateStatic()
3.3.1函数原型
3.3.2函数框架
xQueueCreateStatic()由xQueueGenericCreateStatic()函数实现。
3.4静态创建队列xQueueGenericCreateStatic()
3.4.1函数原型
- uxQueueLength:队列能够存储的最大单元数目,即队列深度;
- uxItemSize:消息单元的大小;
- pucQueueStorage:指向自己分配的队列消息存储空间起始地址;
- pxStaticQueue:指向自己分配的队列起始地址;
- ucQueueType:消息队列类型;
- 返回值:队列句柄。
3.4.2函数框架
静态创建队列与动态创建队列的区别就是,静态创建时的队列控制块和队列消息存储空间需要自己预先分配好,再传递起始地址给静态创建函数,类似于任务的动态创建与静态创建的区别。
3.5删除队列vQueueDelete()
3.5.1函数原型
void vQueueDelete( QueueHandle_t xQueue )
- xQueue :队列句柄。
3.5.2函数框架
3.6队列发送消息xQueueSend()
3.6.1函数原型
-
xQueue:队列句柄;
-
pvItemToQueue:指针,指向要发送到队列尾部的队列消息;
- xTicksToWait:阻塞时间,如果队列满了,任务就会阻塞 xTicksToWait时间。
- 返回值:消息发送成功成功返回 pdTRUE,否则返回 errQUEUE_FULL。
3.6.2函数框架
xQueueSend()是一个宏,宏展开是调用函数 xQueueGenericSend()。
xQueueSend()用于向队列尾部发送一个队列消息。消息以拷贝的形式入队,而不是以引用的形式。该函数绝对不能在中断服务程序里面被调用,中断中必须使用带有中断保护功能的 xQueueSendFromISR()来代替。
3.7队列发送消息xQueueGenericSend()
3.7.1函数原型
- xQueue:队列句柄;
-
pvItemToQueue:指针,指向要发送到队列尾部的队列消息;
- xTicksToWait:阻塞时间,如果队列满了,任务就会阻塞 xTicksToWait时间。
- xCopyPosition:发送数据到消息队列的位置:
- 返回值:消息发送成功成功返回 pdTRUE,否则返回 errQUEUE_FULL。
3.7.2函数框架
- prvAddCurrentTaskToDelayedList()函数
static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, const BaseType_t xCanBlockIndefinitely )
{
TickType_t xTimeToWake;
const TickType_t xConstTickCount = xTickCount;
/* 在将任务添加到阻止列表之前,将其从就绪列表中删除因为两个列表使用相同的列表项。*/
if( uxListRemove( &( pxCurrentTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
{
portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
#if ( INCLUDE_vTaskSuspend == 1 )
{
if( ( xTicksToWait == portMAX_DELAY ) && ( xCanBlockIndefinitely != pdFALSE ) )
{
/* 将任务添加到挂起任务列表,而不是延迟任务列表,以确保它不会被定时事件唤醒。它会阻塞下去。*/
vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xStateListItem ) );
}
else
{
/*任务被唤醒的时间=系统时基计数器值+任务阻塞时间*/
xTimeToWake = xConstTickCount + xTicksToWait;
/*设置状态列表项中的value值*/
listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake );
if( xTimeToWake < xConstTickCount )
{
/* 唤醒溢出,添加到溢出阻塞任务列表中 */
vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
}
else
{
/* 唤醒时间没有溢出,添加到阻塞任务列表中 */
vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
/* 更新下一个任务解锁时刻变量 xNextTaskUnblockTime 的值 */
if( xTimeToWake < xNextTaskUnblockTime )
{
xNextTaskUnblockTime = xTimeToWake;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
}
}
3.8队列发送消息xQueueSendFromISR()
3.8.1函数原型
3.8.2函数框架
xQueueSendFromISR也是一个宏,宏展开是调用函数 xQueueGenericSendFromISR()。该宏是 xQueueSend()的中断保护版本,用于在中断服务程序中向队列尾部发送一个队列消息。
3.9队列发送消息xQueueGenericSendFromISR()
3.9.1函数原型
- xQueue:队列句柄;
-
pvItemToQueue:指针,指向要发送到队列尾部的队列消息;
- pxHigherPriorityTaskWoken:如果入队导致一个任务解锁,并且解锁的任务优先级高于当前被中断的任务,则将*pxHigherPriorityTaskWoken设置成 pdTRUE,然后在中断退出前需要进行一次上下文切换, 去 执行被唤醒的优先级更高的任务 。
- 返回值:消息发送成功成功返回 pdTRUE,否则返回 errQUEUE_FULL。
3.9.2函数框架
3.10队列接收消息xQueueReceive()
3.10.1函数原型
- xQueue:队列句柄;
-
pvBuffer:指针,指向要保存接收消息的空间;
-
xTicksToWait:等待时间。
-
返回值:队列项接收成功返回 pdTRUE ,否则返回 pdFALSE 。
3.10.2函数框架
3.11队列接收消息xQueueReceiveFromISR()
3.11.1函数原型
- xQueue:队列句柄;
-
pvBuffer:指针,指向要保存接收消息的空间;
-
pxHigherPriorityTaskWoken:如果有任务因队列满了阻塞发送,现在调用接收函数导致任务恢复,且恢复的任务优先级高于当前被中断的任务,则将*pxHigherPriorityTaskWoken设置成 pdTRUE,这个过程是在 xQueueReceiveFromISR函数里完成的,然后在中断退出前需要进行一次上下文切换, 去执行被唤醒的优先级更高的任务。如果设置成NULL的话,函数就不会*pxHigherPriorityTaskWoken = pdTRUE;
-
队列项接收成功返回 pdTRUE ,否则返回 pdFALSE 。