一、消息隊列概述
????????隊列又稱消息隊列,是一種常用于任務間通信的數據結構,隊列可以在任務與任務間、 中斷和任務間傳遞信息,實現了任務接收來自其他任務或中斷的不固定長度的消息,任務能夠從隊列里面讀取消息,當隊列中的消息是空時,讀取消息的任務將被阻塞,用戶還可以指定阻塞的任務時間 xTicksToWait,在這段時間中,如果隊列為空,該任務將保持阻塞狀態以等待隊列數據有效。
????????當隊列中有新消息時,被阻塞的任務會被喚醒并處理新消息;當等待的時間超過了指定的阻塞時間,即使隊列中尚無有效數據,任務也會自動從阻塞態轉為就緒態。
????????消息隊列是一種異步的通信方式。通過消息隊列服務,任務或中斷服務例程可以將一條或多條消息放入消息隊列中。同樣,一個或多個任務可以從消息隊列中獲得消息。當有多個消息發送到消息隊列時,通常是將先進入消息隊列的消息先傳給任務,也就是說,任務先得到的是最先進入消息隊列的 消息,即先進先出原則(FIFO),但是也支持后進先出原則(LIFO)。
- 消息支持先進先出方式排隊,支持異步讀寫工作方式。
- 讀寫隊列均支持超時機制。
- 消息支持后進先出方式排隊,往隊首發送消息(LIFO)。
- 可以允許不同長度(不超過隊列節點最大值)的任意類型消息。
- 一個任務能夠從任意一個消息隊列接收和發送消息。
- 多個任務能夠從同一個消息隊列接收和發送消息。
- 當隊列使用結束后,可以通過刪除隊列函數進行刪除。
二、常用函數接口
//頭文件
#include "queue.h"
1.消息隊列創建函數
QueueHandle_t xQueueCreate(UBaseType_t uxQueueLength,UBaseType_t uxItemSize);功能描述:用于創建一個新的隊列。
參數:
- uxQueueLength-隊列能夠存儲的最大消息單元數目,即隊列長度。
- uxItemSize-隊列中消息單元的大小,以字節為單位,該大小設置非常重要,否則得到的數據不完整。返回值:
成功-如果創建成功則返回一個隊列句柄,用于訪問創建的隊列;
失敗-如果創建不成功則返回NULL,可能原因是創建隊列需要的 RAM 無法分配成功。eg:
//創建消息隊列,Q_LEN為4,Q_SIZE為32
g_queue = xQueueCreate(Q_LEN, Q_SIZE);
2.消息隊列靜態創建函數
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,可能原因是創建隊列需要的 RAM 無法分配成功。
3.用于向隊列尾部發送一個隊列消息
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 將導致任務掛起(沒有超時)。返回值:
消息發送成功成功返回 pdTRUE,否則返回 errQUEUE_FULL。eg:
//往消息隊列中發送消息
xReturn = xQueueSend(g_queue, send_buff, portMAX_DELAY );
if(xReturn != pdTRUE)
{printf("send failure\r\n");
}
4.在中斷服務程序中用于向隊列尾部發送一個消息
BaseType_t xQueueSendFromISR(QueueHandle_t xQueue,const void *pvItemToQueue,BaseType_t *pxHigherPriorityTaskWoken);參數說明:
- xQueue-隊列句柄。
- pvItemToQueue-指針,指向要發送到隊列尾部的消息。
- pxHigherPriorityTaskWoken-如果入隊導致一個任務解鎖,
并且解鎖的任務優先級高于當前被中斷的任務,
則將*pxHigherPriorityTaskWoken設置成 pdTRUE,
然后在中斷退出前需要進行一次上下文切換,去執行被喚醒的優先級更高的任務,
可提高實時性。從FreeRTOS V7.3.0 起,
pxHigherPriorityTaskWoken 作為一個可選參數,可以設置為 NULL。返回值:
消息發送成功成功返回 pdTRUE,否則返回 errQUEUE_FULL。
5.向隊列隊首發送一個消息
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 將導致任務無限阻塞(沒有超時)。返回值:
消息發送成功成功返回 pdTRUE,否則返回 errQUEUE_FULL。
6.在中斷服務程序中向消息隊列隊首發送一個消息
BaseType_t xQueueSendToFrontFromISR(QueueHandle_t xQueue,const void *pvItemToQueue,BaseType_t *pxHigherPriorityTaskWoken);參數說明:
- xQueue-隊列句柄。
- pvItemToQueue-指針,指向要發送到隊首的消息。
- pxHigherPriorityTaskWoken-如果入隊導致一個任務解鎖,
并且解鎖的任務優先級高于當前被中斷的任務,
則將*pxHigherPriorityTaskWoken設置成 pdTRUE,
然后在中斷退出前需要進行一次上下文切換,去執行被喚醒的優先級更高的任務。
從FreeRTOS V7.3.0 起,pxHigherPriorityTaskWoken 作為一個可選參數,可以設置為 NULL。返回值:
消息發送成功成功返回 pdTRUE,否則返回 errQUEUE_FULL。
7.從一個隊列中接收消息,并把接收的消息從隊列中刪除
BaseType_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait);參數說明:
- xQueue-隊列句柄。
- pvBuffer-指針,指向接收到要保存的數據。
- xTicksToWait-隊列空時,阻塞超時的最大時間。如果該參數設置為 0,
函數立刻返回。超時時間的單位為系統節拍周期,
常量 portTICK_PERIOD_MS 用 于輔助計算真實的時間,單位為 ms。
如果 INCLUDE_vTaskSuspend 設 置成 1,并且指定延時為 portMAX_DELAY
將導致任務無限阻塞(沒有超時)。返回值:
隊列項接收成功返回 pdTRUE,否則返回 pdFALSE。若接收完消息,不想刪除,可以使用xQueuePeek函數。eg:
//阻塞等待消息
xReturn = xQueueReceive(g_queue, recv_buff, portMAX_DELAY);
if(xReturn != pdTRUE)
{printf("send failure\r\n");
}//記得給緩沖區清零
memset(recv_buff, 0, sizeof (recv_buff));
8.在中斷中從一個隊列中接收消息,并從隊列中刪除該消息
BaseType_t xQueueReceiveFromISR(QueueHandle_t xQueue, void *pvBuffer, BaseType_t *pxHigherPriorityTaskWoken);參數說明:
- xQueue-隊列句柄。
- pvBuffer-pxHigherPriorityTaskWoken
- pxHigherPriorityTaskWoken-在使用之前必須初始化成 pdFALSE。
如果API函數(即xQueueReceiveFromISR)導致一個任務解鎖,
并且解鎖的任務優先級高于當前運行的任務,則API函數(即xQueueReceiveFromISR)將*pxHigherPriorityTaskWoken設置成pdTRUE。在中斷退出前,觸發一次任務切換。pxHigherPriorityTaskWoken 作為一個可選參數,可以設置為NULL。返回值:
隊列項接收成功返回 pdTRUE,否則返回 pdFALSE。
若接收完消息,不想刪除,可以使用xQueuePeekFromISR函數。
三、示例代碼
1、任務與任務之間的源碼:
https://download.csdn.net/download/m0_63622771/90897081
2、任務與中斷之間的源碼:
https://download.csdn.net/download/m0_63622771/90897085