3 FreeRTOSB队列
-
3.1 队列基本知识
队列可以在任务与任务、任务与中断之间传递消息,但是在队列中存储有限的、大小固定的数据项目。任务与任务、任务与中断之间交流的数据保存在队列中,叫做队列项目。队列所能保存的最大数据项目数量叫做队列的长度,我们在创建队列的时候需要制定数据项目的类型和队列的长度。由于队列是用于传递消息的,也成为消息队列,队列是信号量实现的依据。 -
3.2 队列结构体
该结构体定义在queue.c中,具体的成员如下:typedef struct QueueDefinition { int8_t *pcHead; //指向队列存储区开始地址。 int8_t *pcTail; //指向队列存储区最后一个字节。 int8_t *pcWriteTo; //指向存储区中下一个空闲区域。 union { //当用作队列的时候指向最后一个出队的队列项首地址 int8_t *pcReadFrom; //当用作递归互斥量的时候用来记录递归互斥量被调用的次数 UBaseType_t uxRecursiveCallCount; } u; //等待发送任务列表,那些因为队列满导致入队 //失败而进入阻塞态的任务就会挂到此列表上。 List_t xTasksWaitingToSend; //等待接收任务列表,那些因为队列空导致出队失败而进 //入阻塞态的任务就会挂到此列表上。 List_t xTasksWaitingToReceive; //队列中当前队列项数量,也就是消息数 volatile UBaseType_t uxMessagesWaiting; //创建队列时指定的队列长度,也就是队列中最大允许的队列项(消息)数量 UBaseType_t uxLength; //创建队列时指定的每个队列项(消息)最大长度,单位字节 UBaseType_t uxItemSize; //当队列上锁以后用来统计从队列中接收到的队列项数量,也就是出队 //的队列项数量,当队列没有上锁的话此字段为 queueUNLOCKED volatile int8_t cRxLock; //当队列上锁以后用来统计发送到队列中的队列项数量,也就是入队 //的队列项数量,当队列没有上锁的话此字段为 queueUNLOCKED volatile int8_t cTxLock; #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && \ ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) uint8_t ucStaticallyAllocated; //如果使用静态存储的话此字段设置为 pdTURE。 #endif #if ( configUSE_QUEUE_SETS == 1 ) //队列集相关宏 struct QueueDefinition *pxQueueSetContainer; #endif #if ( configUSE_TRACE_FACILITY == 1 ) //跟踪调试相关宏 UBaseType_t uxQueueNumber; uint8_t ucQueueType; #endif } xQUEUE; typedef xQUEUE Queue_t;
-
3.3 队列相关API函数
-
3.3.1 队列创建
xQueueCreate( ) && xQueueCreateStatic( ) QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength, UBaseType_t uxItemSize ); 参数: uxQueueLength:要创建队列的长度,队列的项目数 uxItemSize:队列中每个项目的长度,单位为字节(说白了就是队列项目成员的类型,可以是结构体(信息量大时可用)、 数组或者某一地址) QueueHandle_t xQueueCreatStatic(UBaseType_t uxQueueLength, UBaseType_t uxItemSize, uint8_t* pucQueueStorageBuffer, StaticQueue_t * pxQueueBuffer); 参数: uxQueueLength:要创建的队列的队列长度,指的是队列的项目数; uxItemSize:队列中每个项目的长度,单位为字节; pucQueueStorage:指向队列项目的存储区,也就是消息的存储区,该存储区需用户自行分配。此参数必须指向一个uint8_t类型的数组,同时该数组的存储区必须要大于等于(uxQueueLength * uxItemSize)的字节数 pxQueueBuffer:指向StaticQueue_t类型的变量,用以保存队列结构体。 返回值: 其他值:队列创建成功,返回队列的句柄(使用该队列时需要用到该句柄) NULL:队列创建失败
-
3.3.2 向队列发送消息
任务级函数:
BaseType_t xQueueSend( QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait );
BaseType_t xQueueSendToBack( QueueHandle_t xQueue, const void* pvItemToQueue, TickType_t xTicksToWait );
BaseType_t xQueueSendToToFront(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait );
xQueue:将数据发送到队列的句柄;
pvItemToQueue:指向要发送的消息,发送时将此消息拷贝到队列中;
xTicksToWait:阻塞时间,有三种情况。
1)该值为0时,当队列满,则立即返回;
2)portMAX_DELAY,死等,直到队列有空闲的队列项;
3)其他值,等待的时间(心跳次数)
返回值:
pdPASS:向队列发送消息成功;
errQUEUE_FULL:队列已满,消息发送失败;
BaseType_t xQueueOverwrite(QueueHandle_t xQueue, const void * pvItemToQueue);
参数:同上;
返回值:
pdPASS:向队列发送成功,只有返回该值。因为其不管队列是否有空闲,都会将其内容填充到队列的尾部,必将成功。
中断级函数:
BaseType_t xQueueSendFromISR( QueueHandle_t xQueue, const void *pvItemToQueue, BaseType_t *pxHigherPriorityTaskWoken );
BaseType_t xQueueSendToBackFromISR( QueueHandle_t xQueue, const void *pvItemToQueue, BaseType_t *pxHigherPriorityTaskWoken );
BaseType_t xQueueSendToFrontFromISR( QueueHandle_t xQueue, const void *pvItemToQueue, BaseType_t *pxHigherPriorityTaskWoken);
pxHigherPriorityTaskWolen:标记退出该函数以后是否进行任务切换,该值无需用户设置,由函数自行设置,只需提供该变量用于保存该值即可。当该值为pdTRUE时,则在退出中断服务函数之前一定要进行一次任务切换。
BaseType_t xQueueOverwriteFromISR( QueueHandle_t xQueue,
const void *pvItemToQueue, BaseType_t *pxHigherPriorityTaskWoken );
- 3.3.3 从队列读取消息
BaseType_t xQueueReceive ( QueueHandle_t xQueue, //队列句柄
void *pvBuffer, //保存数据的缓冲区
TickType_t xTicksToWait); //阻塞时间
BaseType_t xQueuePeek ( QueueHandle_t xQueue, //队列句柄
void *pvBuffer, //保存数据的缓冲区
TickType_t xTicksToWait); //阻塞时间
BaseType_t xQueueReceiveFromISR( QueueHandle_t xQueue,
void* pvBuffer,
BaseType_t * pxTaskWoken);
BaseType_t xQueuePeekFromISR( QueueHandle_t xQueue, void *pvBuffer);