FreeRTOS 队列API函数
文章由 FreeRTOS 系列博客整理而来,仅为学习记录,如有不妥,请告知。
FreeRTOS 队列API函数
FreeRTOS 为操作队列提供了非常丰富的 API 函数,包括队列的创建、删除,灵活的入队和出队方式、带中断保护的入队和出队等等。下面就来详细讲述这些 API 函数。
获取队列入队信息数目
函数描述
UBaseType_t uxQueueMessagesWaiting( QueueHandle_t xQueue );
返回队列中存储的信息数目。具有中断保护的版本为 uxQueueMessagesWaitingFromISR()
,原型为:UBaseType_t uxQueueMessagesWaitingFromISR( const QueueHandle_t xQueue )
。
参数描述
- xQueue:队列句柄
获取队列的空闲数目
函数描述
UBaseType_t uxQueueSpacesAvailable( QueueHandle_t xQueue );
返回队列的空闲数目。
参数描述
- xQueue:队列句柄
删除队列
函数描述
void vQueueDelete( QueueHandle_t xQueue );
删除队列并释放所有分配给队列的内存。
参数描述
- xQueue:队列句柄
复位队列
函数描述
BaseType_t xQueueReset( QueueHandle_t xQueue );
将队列复位到初始状态。
参数描述
- xQueue:队列句柄
返回值
FreeRTOSV7.2.0以及以后的版本总是返回pdPASS。
创建队列
函数描述
QueueHandle_t xQueueCreate (UBaseType_t uxQueueLength, UBaseType_t uxItemSize);
创建新队列。为新队列分配指定的存储空间并返回队列句柄。
参数描述
- usQueueLength:队列项数目
- uxItemSize:每个队列项大小,单位是字节。队列项通过拷贝入队而不是通过引用入队,因此需要队列项的大小。每个队列项的大小必须相同。
返回值
成功创建队列返回队列句柄,否自返回0。
用法举例
struct AMessage
{
portCHAR ucMessageID;
portCHAR ucData[ 20 ];
};
void vATask( void*pvParameters )
{
xQueueHandle xQueue1, xQueue2;
// 创建一个队列,队列能包含10个unsigned long类型的值。
xQueue1 = xQueueCreate( 10, sizeof( unsigned portLONG ));
if( xQueue1 ==0 )
{
// 队列创建失败,不可以使用
}
// 创建一个队列,队列能包含10个 Amessage结构体指针类型的值。
// 这样可以通过传递指针变量来包含大量数据。
xQueue2 =xQueueCreate( 10, sizeof( struct AMessage * ) );
if( xQueue2 ==0 )
{
// 队列创建失败,不可以使用
}
// ... 任务的其它代码.
}
向队列投递队列项
函数描述
BaseType_t xQueueSend(QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait );
其实是一个宏,真正被调用的函数是 xQueueGenericSend()
。定义这个宏是为了向后兼容那些不包含函数 xQueueSendToFront()
和 xQueueSendToBack()
宏的 FreeRTOS 版本。它与 xQueueSendToBack()
等同。
这个宏向队列尾部投递一个队列项。项目以拷贝的形式入队,而不是引用形式入队。绝不可以在中断服务例程中调用这个宏,使用带有中断保护的版本 xQueueSendFromISR()
来完成相同的功能。
参数描述
- xQueue:队列句柄。
- pvItemToQueue:指针,指向要入队的项目。要保存到队列中的项目字节数在队列创建时就已确定。因此要从指针 pvItemToQueue 指向的区域拷贝到队列存储区域的字节数,也已确定。
- xTicksToWait:如果队列满,任务等待队列空闲的最大时间。如果队列满并且 xTicksToWait 被设置成 0,函数立刻返回。时间单位为系统节拍时钟周期,因此宏
portTICK_PERIOD_MS
可以用来辅助计算真实延时值。如果INCLUDE_vTaskSuspend
设置成1,并且指定延时为portMAX_DELAY
将引起任务无限阻塞(没有超时)。
返回值
队列项入队成功返回pdTRUE,否则返回errQUEUE_FULL。
用法举例
struct AMessage
{
portCHAR ucMessageID;
portCHAR ucData[ 20 ];
}xMessage;
unsigned portLONG ulVar = 10UL;
void vATask( void *pvParameters )
{
xQueueHandle xQueue1, xQueue2;
struct AMessage *pxMessage;
/*创建一个队列,队列能包含10个unsigned long类型的值。*/
xQueue1 = xQueueCreate( 10, sizeof( unsigned portLONG ) );
/* 创建一个队列,队列能包含10个 Amessage结构体指针类型的值。
这样可以通过传递指针变量来包含大量数据。*/
xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
// ...
if( xQueue1 != 0 )
{
/*1个unsigned long型数据入队.如果需要等待队列空间变的有效,
会最多等待10个系统节拍周期*/
if( xQueueSend( xQueue1, ( void * ) &ulVar, ( portTickType ) 10 ) !=pdPASS )
{
/*消息入队失败*/
}
}
if( xQueue2 != 0 )
{
/* 发送一个指向结构体Amessage的对象,如果队列满也不等待 */
pxMessage = & xMessage;
xQueueSend( xQueue2, ( void * ) &pxMessage, ( portTickType ) 0 );
}
//... 任务其余代码.
}
向队列投递队列项(带中断保护)
函数描述
BaseType_t xQueueSendFromISR (QueueHandle_t xQueue, const void *pvItemToQueue, BaseType_t *pxHigherPriorityTaskWoken);
其实是一个宏,真正被调用的函数是 xQueueGenericSendFromISR()
。这个宏是 xQueueSend()
的中断保护版本,用于中断服务程序,等价于 xQueueSendToBackFromISR()
。
在中断服务例程中向队列尾部投递一个队列项。
参数描述
- xQueue:队列句柄。
- pvItemToQueue:指针,指向要入队的项目。要保存到队列中的项目字节数在队列创建时就已确定。因此要从指针pvItemToQueue指向的区域拷贝到队列存储区域的字节数,也已确定。
- pxHigherPriorityTaskWoken:如果入队导致一个任务解锁,并且解锁的任务优先级高于当前运行的任务,则该函数将*pxHigherPriorityTaskWoken 设置成 pdTRUE。如果
xQueueSendFromISR()
设置这个值为pdTRUE,则中断退出前需要一次上下文切换。从FreeRTOS V7.3.0起,pxHigherPriorityTaskWoken 称为一个可选参数,并可以设置为NULL。
返回值
列项入队成功返回pdTRUE,否则返回errQUEUE_FULL。
用法举例
void vBufferISR( void )
{
portCHARcIn;
portBASE_TYPE xHigherPriorityTaskWoken;
/* 初始化,没有唤醒任务*/
xHigherPriorityTaskWoken = pdFALSE;
/* 直到缓冲区为空 */
do
{
/* 从缓冲区获得一个字节数据 */
cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
/* 投递这个数据 */
xQueueSendFromISR( xRxQueue, &cIn, &xHigherPriorityTaskWoken );
}while( portINPUT_BYTE( BUFFER_COUNT ) );
/* 这里缓冲区已空,如果需要进行一个上下文切换*/
/*根据不同移植平台,这个函数也不同*/
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
向队列尾部投递队列项
函数描述
BaseType_t xQueueSendToBack(QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait );
其实是一个宏,真正被调用的函数是 xQueueGenericSend()
。这个宏等价于 xQueueSend()
。
向队列尾投递一个队列项。绝不可以在中断中调用这个宏,可以使用带有中断保护的版本 xQueueSendToBackFromISR ()
来完成相同功能。
参数描述
同 xQueueSend()
。
返回值
同 xQueueSend()
。
用法举例
同 xQueueSend()
。
向队列尾部投递队列项(带中断保护)
函数描述
BaseType_t xQueueSendToBackFromISR (QueueHandle_t xQueue, const void *pvItemToQueue, BaseType_t *pxHigherPriorityTaskWoken );
其实是一个宏,真正被调用的函数是 xQueueGenericSendFromISR()
。这个宏是 xQueueSendToBack()
的中断保护版本,用于中断服务程序,等价于 xQueueSendFromISR()
。
在中断服务例程中向队列尾部投递一个队列项。
参数描述
同 QueueSendFromISR()
。
返回值
同 QueueSendFromISR()
。
用法举例
同 QueueSendFromISR()
。
向队列首部投递队列项
函数描述
BaseType_t xQueueSendToFront(QueueHandle_t xQueue, const void * pvItemToQueue,TickType_t xTicksToWait);
其实是一个宏,真正被调用的函数是 xQueueGenericSend()
。
这个宏向队列首部投递一个队列项。绝不可以在中断服务例程中调用这个宏,可以使用带有中断保护的版本 xQueueSendToFrontFromISR()
来完成相同功能。
参数描述
- xQueue:队列句柄。
- pvItemToQueue:指针,指向要入队的项目。要保存到队列中的项目字节数在队列创建时就已确定。因此要从指针pvItemToQueue指向的区域拷贝到队列存储区域的字节数,也已确定。
- xTicksToWait:如果队列满,任务等待队列空闲的最大时间。如果队列满并且 xTicksToWait 被设置成0,函数立刻返回。时间单位为系统节拍时钟周期,因此宏
portTICK_PERIOD_MS
可以用来辅助计算真实延时值。如果INCLUDE_vTaskSuspend
设置成1,并且指定延时为portMAX_DELAY
将引起任务无限阻塞(没有超时)。
返回值
队列项入队成功返回pdTRUE,否则返回errQUEUE_FULL。
向队列首部投递队列项(带中断保护)
函数描述
BaseType_t xQueueSendToFrontFromISR (QueueHandle_t xQueue, const void *pvItemToQueue,BaseType_t *pxHigherPriorityTaskWoken);
其实是一个宏,真正被调用的函数是 xQueueGenericSendFromISR()
。这个宏是 xQueueSendToFront ()
的中断保护版本,用于中断服务程序。
参数描述
- xQueue:队列句柄。
- pvItemToQueue:指针,指向要入队的项目。要保存到队列中的项目字节数在队列创建时就已确定。因此要从指针pvItemToQueue指向的区域拷贝到队列存储区域的字节数,也已确定。
- pxHigherPriorityTaskWoken:如果入队导致一个任务解锁,并且解锁的任务优先级高于当前运行的任务,则该函数将 *pxHigherPriorityTaskWoken 设置成pdTRUE。如果
xQueueSendFromISR()
设置这个值为 pdTRUE,则中断退出前需要一次上下文切换。从FreeRTOS V7.3.0起,pxHigherPriorityTaskWoken 称为一个可选参数,并可以设置为 NULL。
返回值
列项入队成功返回pdTRUE,否则返回errQUEUE_FULL。
读取并移除队列项
函数描述
BaseType_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer,TickType_t xTicksToWait);
其实是一个宏,真正被调用的函数是 xQueueGenericReceive()
。
这个宏从队列中读取一个队列项并把该队列项从队列中删除。读取队列项是以拷贝的形式完成,而不是以引用的形式,因此必须提供足够大的缓冲区以便容纳队列项。参数 pvBuffer 指向这个缓冲区。
绝不可以在中断服务例程中调用这个宏,可以使用使用带有中断保护的版本 xQueueReceiveFromISR
来完成相同功能。
参数描述
- pxQueue:队列句柄。
- pvBuffer:指向一个缓冲区,用于拷贝接收到的列表项。
- xTicksToWait:要接收的项目队列为空时,允许任务最大阻塞时间。如果设置该参数为 0,则表示即队列为空也立即返回。阻塞时间的单位是系统节拍周期,宏
portTICK_RATE_MS
可辅助计算真实阻塞时间。如果INCLUDE_vTaskSuspend
设置成 1,并且阻塞时间设置成portMAX_DELAY
,将会引起任务无限阻塞(不会有超时)。
返回值
成功接收到列表项返回pdTRUE,否则返回pdFALSE。
用法举例
struct AMessage
{
portCHAR ucMessageID;
portCHAR ucData[ 20 ];
} xMessage;
xQueueHandle xQueue;
// 创建一个队列并投递一个值
void vATask( void *pvParameters )
{
struct AMessage *pxMessage;
// 创建一个队列,队列能包含10个 Amessage结构体指针类型的值。
// 这样可以通过传递指针变量来包含大量数据。
xQueue =xQueueCreate( 10, sizeof( struct AMessage * ) );
if( xQueue == 0)
{
// 创建队列失败
}
// ...
// 向队列发送一个指向结构体对象Amessage的指针,如果队列满不等待
pxMessage = & xMessage;
xQueueSend(xQueue, ( void * ) &pxMessage, ( portTickType ) 0 );
// ... 其它代码
}
// 该任务从队列中接收一个队列项
voidvADifferentTask( void *pvParameters )
{
struct AMessage *pxRxedMessage;
if( xQueue != 0)
{
// 从创建的队列中接收一个消息,如果消息无效,最多阻塞10个系统节拍周期
if(xQueueReceive( xQueue, &( pxRxedMessage ), ( portTickType ) 10 ) )
{
// 现在pcRxedMessage 指向由vATask任务投递进来的结构体Amessage变量
}
}
// ... 其它代码
}
读取并移除队列项(带中断保护)
函数描述
BaseType_t xQueueReceiveFromISR (QueueHandle_t xQueue, void *pvBuffer, BaseType_t *pxHigherPriorityTaskWoken);
从队列中读取一个队列项并把该队列项从队列中删除。功能与 xQueueReceive()
相同,用于中断服务函数。
参数描述
- pxQueue:队列句柄。
- pvBuffer:指向一个缓冲区,用于拷贝接收到的列表项。
- pxHigherPriorityTaskWoken:如果入队导致一个任务解锁,并且解锁的任务优先级高于当前运行的任务,则该函数将*pxHigherPriorityTaskWoken设置成pdTRUE。如果
xQueueSendFromISR()
设置这个值为 pdTRUE,则中断退出前需要一次上下文切换。从FreeRTOS V7.3.0起,pxHigherPriorityTaskWoken
称为一个可选参数,并可以设置为NULL。
返回值
成功接收到列表项返回pdTRUE,否则返回pdFALSE。
用法举例
xQueueHandle xQueue;
/* 该函数创建一个队列并投递一些值 */
voidvAFunction( void *pvParameters )
{
portCHAR cValueToPost;
const portTickType xBlockTime = (portTickType )0xff;
/*创建一个队列,可以容纳10个portCHAR型变量 */
xQueue = xQueueCreate( 10, sizeof( portCHAR ) );
if( xQueue == 0 )
{
/* 队列创建失败 */
}
/*…... */
/* 投递一些字符,在ISR中使用。如果队列满,任务将会阻塞xBlockTime 个系统节拍周期 */
cValueToPost = 'a';
xQueueSend( xQueue, ( void * ) &cValueToPost, xBlockTime );
cValueToPost = 'b';
xQueueSend( xQueue, ( void * ) &cValueToPost, xBlockTime );
/*... 继续投递字符 ... 当队列满时,这个任务会阻塞*/
cValueToPost = 'c';
xQueueSend( xQueue, ( void * ) &cValueToPost, xBlockTime );
}
/* ISR:输出从队列接收到的所有字符 */
voidvISR_Routine( void )
{
portBASE_TYPE xTaskWokenByReceive = pdFALSE;
portCHAR cRxedChar;
while( xQueueReceiveFromISR( xQueue, ( void *) &cRxedChar, &xTaskWokenByReceive) )
{
/* 接收到一个字符串,输出.*/
vOutputCharacter( cRxedChar );
/* 如果从队列移除一个字符串后唤醒了向此队列投递字符的任务,那么参数xTaskWokenByReceive将会设置成pdTRUE,这个循环无论重复多少次,仅会
有一个任务被唤醒。*/
}
/*这里缓冲区已空,如果需要进行一个上下文切换根据不同移植平台,这个函数也不同 */
portYIELD_FROM_ISR(xTaskWokenByReceive);
}
读取但不移除队列项
函数描述
BaseType_t xQueuePeek(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait);
其实是一个宏,真正被调用的函数是 xQueueGenericReceive()
。
这个宏从队列中读取一个队列项,但不会把该队列项从队列中移除。这个宏绝不可以用在中断服务例程中,可以使用使用带有中断保护的版本 xQueuePeekFromIS()
来完成相同功能。
参数描述
同 xQueueReceive()
。
返回值
同 xQueueReceive()
。
用法举例
同 xQueueReceive()
。
读取但不移除队列项(带中断保护)
函数描述
BaseType_t xQueuePeekFromISR(QueueHandle_t xQueue, void *pvBuffer,);
功能与 xQueuePeek()
相同,用于中断服务程序。
参数描述
- pxQueue:队列句柄。
- pvBuffer:指向一个缓冲区,用于拷贝接收到的列表项。
返回值
成功接收到列表项返回 pdTRUE,否则返回 pdFALSE。
队列注册
函数描述
void vQueueAddToRegistry(QueueHandle_t xQueue, char *pcQueueName,);
为队列分配名字并进行注册。
参数描述
- xQueue:队列句柄
- pcQueueName:分配给队列的名字。这仅是一个有助于调试的字符串。队列注册仅存储指向队列名字符串的指针,因此这个字符串必须是静态的(全局变量活着存储在 ROM/Flash 中),不可以定义到堆栈中。
队列注册有两个目的,这两个目的都是为了调试 RTOS 内核:
- 它允许队列具有一个相关的文本名字,在 GUI 调试中可以容易的标识队列;
- 包含调试器用于定位每一个已经注册的队列和信号量时所需的信息。
队列注册仅用于调试器。
宏 configQUEUE_REGISTRY_SIZE
定义了可以注册的队列和信号量的最大数量。仅当你想使用可视化调试内核时,才进行队列和信号量注册。
用法举例
void vAFunction( void )
{
xQueueHandle xQueue;
/*创建一个队列,可以容纳10个char类型数值 */
xQueue = xQueueCreate( 10, sizeof( portCHAR ) );
/* 我们想可视化调试,所以注册它*/
vQueueAddToRegistry( xQueue, "AMeaningfulName" );
}
解除注册
函数描述
void vQueueUnregisterQueue(QueueHandle_t xQueue);
从队列注册表中移除指定的队列。
参数描述
- xQueue:队列句柄
查询队列是否为空(仅用于中断服务程序)
函数描述
BaseType_t xQueueIsQueueEmptyFromISR( const QueueHandle_t xQueue );
查询队列是否为空。这个函数仅用于ISR。
参数描述
- xQueue:队列句柄
返回值
队列非空返回 pdFALSE,其它值表示队列为空。
查询队列是否满(仅用于中断服务程序)
函数描述
BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue );
查询队列是否满,仅用于ISR。
参数描述
- xQueue:队列句柄
返回值
队列没有满返回pdFALSE,其它值表示队列满。
向队列尾部覆盖式投递队列项
函数描述
BaseType_t xQueueOverwrite(QueueHandle_t xQueue, const void * pvItemToQueue);
其实是个宏,真正被调用的函数是 xQueueGenericSend()
。这个宏是 xQueueSendToBack()
的另一个版本,向队列尾投递一个队列项,如果队列已满,则覆盖之前的队列项。一般用于只有一个队列项的队列中,如果队列的队列项超过1个,使用这个宏会触发一个断言(已经正确定义 configASSERT()
的情况下)。这个宏绝不可以在中断服务程序中调用,可以使用使用带有中断保护的版本 xQueueOverwriteFromISR()
来完成相同功能。
参数描述
- xQueue:队列句柄。
- pvItemToQueue:指针,指向要入队的项目。要保存到队列中的项目字节数在队列创建时就已确定。因此要从指针pvItemToQueue指向的区域拷贝到队列存储区域的字节数,也已确定。
返回值
总是返回pdPASS。
用法举例
void vFunction( void *pvParameters )
{
QueueHandle_t xQueue;
unsigned long ulVarToSend, ulValReceived;
/*创建队列,保存一个unsignedlong值。如果一个队列的队列项超过1个,强烈建议不要使用xQueueOverwrite(),如果使用xQueueOverwrite()会触发一个断言(已经正确定义configASSERT()的情况下)。*/
xQueue = xQueueCreate( 1, sizeof( unsigned long ) );
/*使用 xQueueOverwrite().向队列写入10*/
ulVarToSend = 10;
xQueueOverwrite( xQueue, &ulVarToSend );
/*从队列读取值,但是不把这个值从队列中删除。*/
ulValReceived = 0;
xQueuePeek( xQueue, &ulValReceived, 0 );
if( ulValReceived != 10 )
{
/* 处理错误*/
}
/*到这里队列仍是满的。使用xQueueOverwrite()覆写队列,写入值100 */
ulVarToSend = 100;
xQueueOverwrite( xQueue, &ulVarToSend );
/* 从队列中读取值*/
xQueueReceive( xQueue, &ulValReceived, 0 );
if( ulValReceived != 100 )
{
/*处理错误 */
}
/* ... */
}
向队列尾部覆盖式投递队列项(带中断保护)
函数描述
BaseType_t xQueueOverwriteFromISR (QueueHandle_t xQueue, const void * pvItemToQueue, BaseType_t *pxHigherPriorityTaskWoken);
其实是个宏,真正被调用的函数是 xQueueGenericSendFromISR()
。这个宏的功能与 xQueueOverwrite()
相同,用在中断服务程序中。
参数描述
- xQueue:队列句柄。
- pvItemToQueue:指针,指向要入队的项目。要保存到队列中的项目字节数在队列创建时就已确定。因此要从指针pvItemToQueue指向的区域拷贝到队列存储区域的字节数,也已确定。
- pxHigherPriorityTaskWoken:如果入队导致一个任务解锁,并且解锁的任务优先级高于当前运行的任务,则该函数将
*pxHigherPriorityTaskWoken
设置成 pdTRUE。如果xQueueSendFromISR()
设置这个值为 pdTRUE,则中断退出前需要一次上下文切换。从FreeRTOS V7.3.0起,pxHigherPriorityTaskWoken 称为一个可选参数,并可以设置为 NULL。
返回值
总是返回pdPASS。