FreeRTOS消息隊列
????消息隊列是FreeRTOS中重要的通信機制,需要熟練掌握。
1 消息隊列的概念及其作用?
????消息隊列就是通過 RTOS 內(nèi)核提供的服務,任務或中斷服務子程序可以將一個消息(注意,F(xiàn)reeRTOS 消息隊列傳遞的是實際數(shù)據(jù),并不是數(shù)據(jù)地址,RTX,uCOS-II 和 uCOS-III 是傳遞的地址)放入到隊列。 同樣,一個或者多個任務可以通過 RTOS 內(nèi)核服務從隊列中得到消息。通常,先進入消息隊列的消息先傳 給任務,也就是說,任務先得到的是最先進入到消息隊列的消息,即先進先出的原則(FIFO),F(xiàn)reeRTOS 的消息隊列支持 FIFO 和 LIFO 兩種數(shù)據(jù)存取方式。
????也許有不理解的初學者會問采用消息隊列多麻煩,搞個全局數(shù)組不是更簡單,其實不然。在裸機編程時,使用全局數(shù)組的確比較方便,但是在加上 RTOS 后就是另一種情況了。相比消息隊列,使用全局數(shù)組主要有如下四個問題:?
◆ 使用消息隊列可以讓 RTOS 內(nèi)核有效地管理任務,而全局數(shù)組是無法做到的,任務的超時等機制需要用戶自己去實現(xiàn)。
◆ 使用了全局數(shù)組就要防止多任務的訪問沖突,而使用消息隊列則處理好了這個問題,用戶無需擔心。
◆ 使用消息隊列可以有效地解決中斷服務程序與任務之間消息傳遞的問題。?
◆ FIFO 機制更有利于數(shù)據(jù)的處理。
2 FreeRTOS任務間消息隊列的實現(xiàn)
????任務間消息隊列的實現(xiàn)是指各個任務之間使用消息隊列實現(xiàn)任務間的通信。下面我們通過如下的框圖來說明一下 FreeRTOS 消息隊列的實現(xiàn):

運行條件:?
◆ 創(chuàng)建消息隊列,可以存放 10 個消息。
◆ 創(chuàng)建 2 個任務 Task1 和 Task2,任務 Task1 向消息隊列放數(shù)據(jù),任務 Task2 從消息隊列取數(shù)據(jù)。?
◆ FreeRTOS 的消息存取采用 FIFO 方式。?
運行過程主要有以下兩種情況:
◆ 任務 Task1 向消息隊列放數(shù)據(jù),任務Task2 從消息隊列取數(shù)據(jù),如果放數(shù)據(jù)的速度快于取數(shù)據(jù)的速度,那么會出現(xiàn)消息隊列存放滿的情況,
????FreeRTOS 的消息存放函數(shù) xQueueSend 支持超時等待,用戶可以設(shè)置超時等待,直到有空間可以存放消息或者設(shè)置的超時時間溢出。
◆ 任務 Task1 向消息隊列放數(shù)據(jù),任務 Task2 從消息隊列取數(shù)據(jù),如果放數(shù)據(jù)的速度慢于取數(shù)據(jù)的速度,那么會出現(xiàn)消息隊列為空的情況,F(xiàn)reeRTOS 的消息獲取函數(shù) xQueueReceive 支持超時等待, 用戶可以設(shè)置超時等待,直到消息隊列中有消息或者設(shè)置的超時時間溢出。
????FIFO 方式數(shù)據(jù)存取過程的動態(tài)演示看官方地址:
????http://www.freertos.org/Embedded-RTOS-Queues.html 里面的 GIF 圖片。
3 FreeRTOS中斷方式消息隊列的實現(xiàn)
FreeRTOS 中斷方式消息隊列的實現(xiàn)是指中斷函數(shù)和 FreeRTOS 任務之間使用消息隊列。
????下面我們通過如下的框圖來說明一下 FreeRTOS 消息隊列的實現(xiàn):

運行條件:?
◆ 創(chuàng)建消息隊列,可以存放 10 個消息。
◆ 創(chuàng)建 1 個任務 Task1 和一個串口接收中斷。
◆ FreeRTOS 的消息存取采用 FIFO 方式。?
運行過程主要有以下兩種情況:?
????◆ 中斷服務程序向消息隊列放數(shù)據(jù),任務 Task1 從消息隊列取數(shù)據(jù),如果放數(shù)據(jù)的速度快于取數(shù)據(jù)的速度,那么會出現(xiàn)消息隊列存放滿的情況。由于中斷服務程序里面的消息隊列發(fā)送函數(shù) xQueueSendFromISR 不支持超時設(shè)置,所以發(fā)送前要通過函數(shù) xQueueIsQueueFullFromISR 檢測消息隊列是否滿。
????◆ 中斷服務程序向消息隊列放數(shù)據(jù),任務 Task1 從消息隊列取數(shù)據(jù),如果放數(shù)據(jù)的速度慢于取數(shù)據(jù)的速度,那么會出現(xiàn)消息隊列存為空的情況。在 FreeRTOS 的任務中可以通過函數(shù) xQueueReceive 獲取消息,因為此函數(shù)可以設(shè)置超時等待,直到消息隊列中有消息存放或者設(shè)置的超時時間溢出。
4 消息隊列 API?函數(shù)
◆ xQueueCreate ()?
◆ xQueueSend ()?
◆ xQueueSendFromISR ()?
◆ xQueueReceive ()
函數(shù) xQueueCreate 用于創(chuàng)建消息隊列。
◆ 第 1 個參數(shù)是消息隊列支持的消息個數(shù)。?
◆ 第 2 個參數(shù)是每個消息的大小,單位字節(jié)。
◆ 返回值,如果創(chuàng)建成功會返回消息隊列的句柄,如果由于 FreeRTOSConfig.h 文件中 heap 大小不足, 無法為此消息隊列提供所需的空間會返回 NULL。
????使用這個函數(shù)要注意以下問題:FreeRTOS 的消息傳遞是數(shù)據(jù)的復制,而不是傳遞的數(shù)據(jù)地址,這點要特別注意。每一次傳遞都是 uxItemSize 個字節(jié)。舉例:
函數(shù) xQueueSend 用于任務中消息發(fā)送。
◆ 第 1 個參數(shù)是消息隊列句柄。?
◆ 第 2 個參數(shù)要傳遞數(shù)據(jù)地址,每次發(fā)送都是將消息隊列創(chuàng)建函數(shù) xQueueCreate 所指定的單個消息大小復制到消息隊列空間中。
◆ 第 3 個參數(shù)是當消息隊列已經(jīng)滿時,等待消息隊列有空間時的最大等待時間,單位系統(tǒng)時鐘節(jié)拍。?
◆ 返回值,如果消息成功發(fā)送返回 pdTRUE,否則返回 errQUEUE_FULL。 使用這個函數(shù)要注意以下問題:
使用這個函數(shù)要注意以下問題:?
1. FreeRTOS 的消息傳遞是數(shù)據(jù)的復制,而不是傳遞的數(shù)據(jù)地址。?
2. 此函數(shù)是用于任務代碼中調(diào)用的,故不可以在中斷服務程序中調(diào)用此函數(shù),中斷服務程序中使用的是 xQueueSendFromISR。?
3. 如果消息隊列已經(jīng)滿且第三個參數(shù)為 0,那么此函數(shù)會立即返回。?
4. 如果用戶將 FreeRTOSConfig.h 文件中的宏定義 INCLUDE_vTaskSuspend 配置為 1 且第三個參數(shù)配置為 portMAX_DELAY,那么此發(fā)送函數(shù)會永久等待直到消息隊列有空間可以使用。?
5. 消息隊列還有兩個函數(shù) xQueueSendToBack 和 xQueueSendToFront,函數(shù) xQueueSendToBack 實現(xiàn)的是 FIFO 方式的存取,函數(shù) xQueueSendToFront 實現(xiàn)的是 LIFO 方式的讀寫。我們這里說的函 數(shù) xQueueSend 等效于 xQueueSendToBack,即實現(xiàn)的是 FIFO 方式的存取。
舉例:
函數(shù) xQueueSendFromISR 用于中斷服務程序中消息發(fā)送。
◆ 第 1 個參數(shù)是消息隊列句柄。
◆ 第 2 個參數(shù)要傳遞數(shù)據(jù)地址,每次發(fā)送都是將消息隊列創(chuàng)建函數(shù) xQueueCreate 所指定的單個消息大 小復制到消息隊列空間中。?
◆ 第3 個參數(shù)用于保存是否有高優(yōu)先級任務準備就緒。如果函數(shù)執(zhí)行完畢后,此參數(shù)的數(shù)值是 pdTRUE, 說明有高優(yōu)先級任務要執(zhí)行,否則沒有。
◆ 返回值,如果消息成功發(fā)送返回 pdTRUE,否則返回 errQUEUE_FULL。
舉例:
函數(shù) xQueueReceive 用于接收消息隊列中的數(shù)據(jù)。
◆ 第 1 個參數(shù)是消息隊列句柄。?
◆ 第 2 個參數(shù)是從消息隊列中復制出數(shù)據(jù)后所儲存的緩沖地址,緩沖區(qū)空間要大于等于消息隊列創(chuàng)建函 數(shù) xQueueCreate 所指定的單個消息大小,否則取出的數(shù)據(jù)無法全部存儲到緩沖區(qū),從而造成內(nèi)存溢出。?
◆ 第 3 個參數(shù)是消息隊列為空時,等待消息隊列有數(shù)據(jù)的最大等待時間,單位系統(tǒng)時鐘節(jié)拍。 ◆ 返回值,如果接到到消息返回 pdTRUE,否則返回 pdFALSE。
使用這個函數(shù)要注意以下問題:
1. 此函數(shù)是用于任務代碼中調(diào)用的,故不可以在中斷服務程序中調(diào)用此函數(shù),中斷服務程序使用的是 xQueueReceiveFromISR。?
2. 如果消息隊列為空且第三個參數(shù)為 0,那么此函數(shù)會立即返回。
3. 如果用戶將 FreeRTOSConfig.h 文件中的宏定義 INCLUDE_vTaskSuspend 配置為 1 且第三個參數(shù)配 置為 portMAX_DELAY,那么此函數(shù)會永久等待直到消息隊列有數(shù)據(jù)。
舉例: