在實際的應用中,常常會遇到一個任務或者中斷服務需要和另外一個任務進行“溝通交流”,這個“溝通交流”的過程其實就是消息傳遞的過程。在沒有作業系統的時候兩個應用程式進行消息傳遞一般使用全局變量的方式,但是如果在使用作業系統的應用中用全局變量來傳遞消息就會涉及到“資源管理”的問題。FreeRTOS對此提供了一個叫做“隊列”的機制來完成任務與任務、任務與中斷之間的消息傳遞。本章我們就來學習FreeRTOS隊列,本章分為如下幾部分:
13.1隊列簡介
13.2隊列結構體
13.3隊列建立
13.4向隊列發送消息
13.5隊列上鎖和解鎖
13.6從隊列讀取消息
13.7隊列操作實驗
13.1隊列簡介隊列
是為了任務與任務、任務與中斷之間的通信而準備的,可以在任務與任務、任務與中斷之間傳遞消息,隊列中可以存儲有限的、大小固定的資料項目。任務與任務、任務與中斷之間要交流的資料儲存在隊列中,叫做隊列項目。隊列所能儲存的最大資料項目數量叫做隊列的長度,建立隊列的時候會指定資料項目的大小和隊列的長度。由于隊列用來傳遞消息的,是以也稱為消息隊列。FreeRTOS中的信号量的也是依據隊列實作的!是以有必要深入的了解FreeRTOS的隊列。
13.3隊列建立
13.3.1函數原型
在使用隊列之前必須先建立隊列,有兩種建立隊列的方法,一種是靜态的,使用函數xQueueCreateStatic();另一個是動态的,使用函數xQueueCreate()。這兩個函數本質上都是宏,真正完成隊列建立的函數是xQueueGenericCreate()和xQueueGenericCreateStatic(),這兩個函數在檔案queue.c中有定義,這四個函數的原型如下。
1、函數xQueueCreate()此函數本質上是一個宏,用來動态建立隊列,此宏最終調用的是函數xQueueGenericCreate(),函數原型如下:
QueueHandle_t xQueueCreate(UBaseType_t uxQueueLength,UBaseType_t uxItemSize)
參數:
uxQueueLength:要建立的隊列的隊列長度,這裡是隊列的項目數。
uxItemSize:隊列中每個項目(消息)的長度,機關為位元組
傳回值:
其他值:隊列創捷成功以後傳回的隊列句柄!
NULL:隊列建立失敗。
2、函數xQueueCreateStatic()
此函數也是用于建立隊列的,但是使用的靜态方法建立隊列,隊列所需要的記憶體由使用者自行配置設定,此函數本質上也是一個宏,此宏最終調用的是函數xQueueGenericCreateStatic(),函數原型如下:
QueueHandle_t xQueueCreateStatic(UBaseType_t uxQueueLength,UBaseType_t uxItemSize,uint8_t *pucQueueStorageBuffer,StaticQueue_t *pxQueueBuffer)
參數:
uxQueueLength:要建立的隊列的隊列長度,這裡是隊列的項目數。
uxItemSize:隊列中每個項目(消息)的長度,機關為位元組
pucQueueStorage:指向隊列項目的存儲區,也就是消息的存儲區,這個存儲區需要使用者自行配置設定。此參數必須指向一個uint8_t類型的數組。這個存儲區要大于等于(uxQueueLength * uxItemsSize)位元組。
pxQueueBuffer:此參數指向一個StaticQueue_t類型的變量,用來儲存隊列結構體。
傳回值:
其他值:隊列創捷成功以後的隊列句柄!
NULL:隊列建立失敗。
3、函數xQueueGenericCreate()函數
xQueueGenericCreate()用于動态建立隊列,建立隊列過程中需要的記憶體均通過FreeRTOS中的動态記憶體管理函數pvPortMalloc()配置設定,
函數原型如下:QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_tuxItemSize, const uint8_t ucQueueType )
參數:
uxQueueLength:要建立的隊列的隊列長度,這裡是隊列的項目數。
uxItemSize:隊列中每個項目(消息)的長度,機關為位元組。
ucQueueType:隊列類型,由于FreeRTOS中的信号量等也是通過隊列來實作的,建立信号量的函數最終也是使用此函數的,是以在建立的時候需要指定此隊列的用途,也就是隊列類型,一共有六種類型:
queueQUEUE_TYPE_BASE普通的消息隊列
queueQUEUE_TYPE_SET隊列集
queueQUEUE_TYPE_MUTEX互斥信号量
queueQUEUE_TYPE_COUNTING_SEMAPHORE計數型信号量
queueQUEUE_TYPE_BINARY_SEMAPHORE二值信号量
queueQUEUE_TYPE_RECURSIVE_MUTEX遞歸互斥信号量函數
xQueueCreate()建立隊列的時候此參數預設選擇的就是queueQUEUE_TYPE_BASE。
傳回值:
其他值:隊列創捷成功以後的隊列句柄!
NULL:隊列建立失敗。
4、函數xQueueGenericCreateStatic()
此函數用于動态建立隊列,建立隊列過程中需要的記憶體需要由使用者自行配置設定好,函數原型如下:
QueueHandle_t xQueueGenericCreateStatic( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, StaticQueue_t *pxStaticQueue, const uint8_t ucQueueType )
參數:
uxQueueLength:要建立的隊列的隊列長度,這裡是隊列的項目數。
uxItemSize:隊列中每個項目(消息)的長度,機關為位元組
pucQueueStorage:指向隊列項目的存儲區,也就是消息的存儲區,這個存儲區需要使用者自行配置設定。此參數必須指向一個uint8_t類型的數組。這個存儲區要大于等于(uxQueueLength * uxItemsSize)位元組。
pxStaticQueue:此參數指向一個StaticQueue_t類型的變量,用來儲存隊列結構體。
ucQueueType:隊列類型。
傳回值:
其他值:隊列創捷成功以後隊列句柄!
NULL:隊列建立失敗。
13.4向隊列發送消息
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHLwEEVNRTVU9kMNpHW4Z0MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL1MTNwQzM0UTMzETMwEjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
13.6從隊列讀取消息
/按鍵消息隊列的數量
#define KEYMSG_Q_NUM 1 //按鍵消息隊列的數量 (1)
#define MESSAGE_Q_NUM 4 //發送資料的消息隊列的數量(2)
QueueHandle_t Key_Queue; //按鍵值消息隊列句柄
QueueHandle_t Message_Queue;//資訊隊列句柄
// (1)、隊列Key_Queue用來傳遞按鍵值的,也就是一個u8變量,是以隊列長度為1就行了。并且消息長度為1個位元組。
//(2)、隊列Message_Queue用來傳遞序列槽接收到的資料,隊列長度設定為4,每個消息的長度為USART_REC_LEN(在usart.h中有定義)。
//建立消息
Key_QueueKey_Queue=xQueueCreate(KEYMSG_Q_NUM,sizeof(u8)); (1)//建立消息Message_Queue,隊列項長度是序列槽接收緩沖區長度
Message_Queue=xQueueCreate(MESSAGE_Q_NUM,USART_REC_LEN);(2)
//task1任務函數
void task1_task(void *pvParameters)
{
u8 key,i=0;
BaseType_t err;
while(1)
{
key=KEY_Scan(0); //掃描按鍵
if((Key_Queue!=0)&&(key)) //消息隊列Key_Queue建立成功,并且按鍵被按下
{
err=xQueueSend(Key_Queue,&key,10);(3)
if(err==errQUEUE_FULL) //發送按鍵值
{
printf("隊列Key_Queue已滿,資料發送失敗!\r\n");
}
}
i++;
if(i%10==0)
check_msg_queue();//檢Message_Queue隊列的容量(4)
if(i==50)
{
i=0; LED0=!LED0;
}
vTaskDelay(10); //延時10ms,也就是10個時鐘節拍
}
}