消息队列
一、概述
消息队列(Queue)是 FreeRTOS 中最常用的任务间通信机制之一,用于实现任务与任务之间、任务与中断之间的安全数据传递。
它基于先进先出(FIFO)的队列数据结构,在此基础上增加了阻塞等待机制,并支持紧急消息插入,从而满足实时系统中不同优先级和时序要求的数据通信需求。
二、运作机制
创建消息队列时, FreeRTOS 会先给消息队列分配一块内存空间,这块内存的大小等于消息队列控制块大小加单个消息空间大小与消息队列长度的乘积,接着再初始化消息队列,此时消息队列为空。FreeRTOS的消息队列控制块由多个元素组成,当消息队列被 创建时,系统会为控制块分配对应的内存空间,用于保存消息队列的一些信息如消息的存储位置,头指针 pcHead、尾指针 pcTail、消息大小uxItemSize以及队列长度uxLength等。同时每个消息队列都与消息空间在同一段连续的内存空间中,在创建成功的时候,这些内存就被占用了,只有删除了消息队列的时候,这段内存才会被释放掉,创建成功的时候就已经分配好每个消息空间与消息队列的容量,无法更改,每个消息空间可以存放不大于消息大小uxItemSize的任意类型的数据,所有消息队列中的消息空间总数即是消息队列的长度,这个长度可在消息队列创建时指定。
消息队列使用过程时,发送消息的数据是直接进行拷贝的,就像函数调用一直,当然这个拷贝只是浅拷贝。
任务或者中断服务程序都可以给消息队列发送消息,当发送消息时,如果队列未满或者允许覆盖入队,FreeRTOS 会将消息拷贝到消息队列队尾,否则,会根据用户指定的阻塞超时时间进行阻塞,在这段时间中,如果队列一直不允许入队,该任务将保持阻塞状态以等待队列允许入队。当其它任务从其等待的队列中读取入了数据(队列未满),该任务将 自动由阻塞态转移为就绪态。当等待的时间超过了指定的阻塞时间,即使队列中还不允许 入队,任务也会自动从阻塞态转移为就绪态,此时发送消息的任务或者中断程序会收到一个错误码 errQUEUE_FULL。
当消息队列不再被使用时,应该删除它以释放系统资源,否则会占用大量资源空间。
三、函数接口
1、头文件
c
#include "queue.h"
2、消息队列创建函数
c
QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength,
UBaseType_t uxItemSize );
- 函数说明:消息队列创建
- 参数:
uxQueueLength:消息队列能够存储的最大长度。uxItemSize:每个信息的大小,单位是字节
- 返回值:
- 成功:返回 消息队列的句柄
- 失败:返回 NULL。
3、消息队列静态创建函数
c
QueueHandle_t xQueueCreateStatic( UBaseType_t uxQueueLength,
UBaseType_t uxItemSize,
uint8_t *pucQueueStorageBuffer,
StaticQueue_t *pxQueueBuffer );
- 函数说明:消息队列创建
- 参数:
uxQueueLength:消息队列能够存储的最大长度。uxItemSize:每个信息的大小,单位是字节pucQueueStorageBuffer:指向一个 uint8_t 类型的数组,数组的大小至少有uxQueueLength*uxItemSize个字节。当uxItemSize为 0 时,pucQueueStorageBuffer可以为 NULL。pxQueueBuffer:指向StaticQueue_t类型的变量,该变量用于存储队列的数据结构。
- 返回值:
- 成功:返回 消息队列的句柄
- 失败:返回 NULL。
4、消息队列发送队列信息到队尾
c
BaseType_t xQueueSend( QueueHandle_t xQueue,
const void * pvItemToQueue,
TickType_t xTicksToWait );
- 函数说明:向队列队尾发送消息,该信息是拷贝存储到队列中的
- 参数:
xQueue:消息队列句柄。pvItemToQueue:需要发送的信息的指针xTicksToWait:队列满时,等待队列空闲的最大超时时间。如果队列满并且xTicksToWait被设置成 0,函数立刻返回。超时时间的单位为系统节拍周期,常量portTICK_PERIOD_MS用于辅助计算真实的时间,单位为ms。如果INCLUDE_vTaskSuspend设置成 1,并且指定延时为portMAX_DELAY将导致任务挂起(没有超时)。
- 返回值:
- 成功:返回
pdTURE - 失败:返回
errQUEUE_FULL。
- 成功:返回
5、消息队列发送队列信息到队尾(中断)
c
BaseType_t xQueueSendFromISR( QueueHandle_t xQueue,
const void *pvItemToQueue,
BaseType_t *pxHigherPriorityTaskWoken );
-
函数说明:向队列队尾发送消息,该信息是拷贝存储到队列中的,该函数用在中断服务中。
-
参数:
-
xQueue:消息队列句柄。 -
pvItemToQueue:需要发送的信息的指针 -
pxHigherPriorityTaskWoken:如果入队导致一个任务解锁,并且解锁的任务优先级高于当前被中断的任务,则将pxHigherPriorityTaskWoken设置成pdTRUE,然后在中断退出前需要进行一次上下文切换,去执行被唤醒的优先级更高的任务。从FreeRTOS V7.3.0起,pxHigherPriorityTaskWoken作为一个可选参数,可以设置为 NULL。 -
成功:返回
pdTURE -
失败:返回
errQUEUE_FULL。
-
6、消息队列发送队列信息到队首
c
BaseType_t xQueueSendToFront( QueueHandle_t xQueue,
const void * pvItemToQueue,
TickType_t xTicksToWait );
-
函数说明:向队列队队首发送消息,一般需要将消息发送到队首的叫紧急消息
-
参数:
xQueue:消息队列句柄。pvItemToQueue:需要发送的信息的指针xTicksToWait:队列满时,等待队列空闲的最大超时时间。如果队列满并且xTicksToWait被设置成 0,函数立刻返回。超时时间的单位为系统节拍周期,常量portTICK_PERIOD_MS用于辅助计算真实的时间,单位为ms。如果INCLUDE_vTaskSuspend设置成 1,并且指定延时为portMAX_DELAY将导致任务挂起(没有超时)。
-
返回值:
-
成功:返回
pdTURE -
失败:返回
errQUEUE_FULL。
-
7、消息队列发送队列信息到队首(中断)
c
BaseType_t xQueueSendToFrontFromISR( QueueHandle_t xQueue,
const void *pvItemToQueue,
BaseType_t *pxHigherPriorityTaskWoken );
-
函数说明:向队列队队首发送消息,一般需要将消息发送到队首的叫紧急消息,该函数用在中断服务中。
-
参数:
xQueue:消息队列句柄。pvItemToQueue:需要发送的信息的指针pxHigherPriorityTaskWoken:如果入队导致一个任务解锁,并且解锁的任务优先级高于当前被中断的任务,则将pxHigherPriorityTaskWoken设置成pdTRUE,然后在中断退出前需要进行一次上下文切换,去执行被唤醒的优先级更高的任务。从FreeRTOS V7.3.0起,pxHigherPriorityTaskWoken作为一个可选参数,可以设置为 NULL。
-
返回值:
-
成功:返回
pdTURE -
失败:返回
errQUEUE_FULL。
-
8、消息队列接收消息
c
BaseType_t xQueueReceive( QueueHandle_t xQueue,
void *pvBuffer,
TickType_t xTicksToWait );
-
函数说明:向队列队首接收消息,并将接收到的信息从队列中删除
-
参数:
xQueue:消息队列句柄。pvBuffer:指向接收到要保存的数据。xTicksToWait:队列满时,等待队列空闲的最大超时时间。如果队列满并且xTicksToWait被设置成 0,函数立刻返回。超时时间的单位为系统节拍周期,常量portTICK_PERIOD_MS用于辅助计算真实的时间,单位为ms。如果INCLUDE_vTaskSuspend设置成 1,并且指定延时为portMAX_DELAY将导致任务挂起(没有超时)。
-
返回值:
-
成功:返回
pdTURE -
失败:返回
pdFALSE。
-
9、消息队列接收消息
c
BaseType_t xQueuePeek( QueueHandle_t xQueue,
void *pvBuffer,
TickType_t xTicksToWait );
-
函数说明:向队列队首接收消息,但是不会删除数据信息
-
参数:
xQueue:消息队列句柄。pvBuffer:指向接收到要保存的数据。xTicksToWait:队列满时,等待队列空闲的最大超时时间。如果队列满并且xTicksToWait被设置成 0,函数立刻返回。超时时间的单位为系统节拍周期,常量portTICK_PERIOD_MS用于辅助计算真实的时间,单位为ms。如果INCLUDE_vTaskSuspend设置成 1,并且指定延时为portMAX_DELAY将导致任务挂起(没有超时)。
-
返回值:
-
成功:返回
pdTURE -
失败:返回
pdFALSE。
-
10、消息队列接收消息(中断)
c
BaseType_t xQueueReceiveFromISR( QueueHandle_t xQueue,
void *pvBuffer,
BaseType_t *pxHigherPriorityTaskWoken );
-
函数说明:向队列队首接收消息,并将接收到的信息从队列中删除,该函数用在中断服务中。
-
参数:
xQueue:消息队列句柄。pvBuffer:指向接收到要保存的数据。pxHigherPriorityTaskWoken:在使用之前必须初始化成 pdFALSE。如果API函数(即xQueueReceiveFromISR)导致一个任务解锁,并且解锁的任务优先级高于当前运行的任务,则API函数(即xQueueReceiveFromISR)将pxHigherPriorityTaskWoken设置成pdTRUE。在中断退出前,触发一次任务切换。pxHigherPriorityTaskWoken作为一个可选参数,可以设置为NULL。
-
返回值:
-
成功:返回
pdTURE -
失败:返回
pdFALSE。
-
11、消息队列接收消息(中断)
c
BaseType_t xQueuePeekFromISR( QueueHandle_t xQueue,
void *pvBuffer,
BaseType_t *pxHigherPriorityTaskWoken );
-
函数说明:向队列队首接收消息,并将接收到的信息从队列中删除,该函数用在中断服务中。
-
参数:
xQueue:消息队列句柄。pvBuffer:指向接收到要保存的数据。pxHigherPriorityTaskWoken:在使用之前必须初始化成 pdFALSE。如果API函数(即xQueueReceiveFromISR)导致一个任务解锁,并且解锁的任务优先级高于当前运行的任务,则API函数(即xQueueReceiveFromISR)将pxHigherPriorityTaskWoken设置成pdTRUE。在中断退出前,触发一次任务切换。pxHigherPriorityTaskWoken作为一个可选参数,可以设置为NULL。
-
返回值:
-
成功:返回
pdTURE -
失败:返回
pdFALSE。
-
12、pdMS_TO_TICKS 宏
c
#define pdMS_TO_TICKS( xTimeInMs ) \
( ( TickType_t ) ( ( ( TickType_t ) ( xTimeInMs ) * configTICK_RATE_HZ ) / 1000 ) )
- 宏说明:将"毫秒(
ms)"转换为 FreeRTOS 内核使用的"系统节拍(tick)"数 - 参数:
xTimeInMs:消息队列句柄。 - 返回值:
TickType_t类型的值
注:以上均为学习资料。