FreeRTOS任務通知 基于STM32
一、任務通知簡介
FreeRTOS 從 V8.2.0 版本開始提供任務通知這個功能,每個任務都有一個 32 位的通知 值,在大多數情況下,任務通知可以替代二值信號量、計數信號量、事件組,也可以替代 長度為 1 的隊列(可以保存一個 32位整數或指針值)。
相對于以前使用 FreeRTOS 內核通信的資源,必須創建隊列、二進制信號量、計數信 號量或事件組的情況,使用任務通知顯然更靈活。
按照 FreeRTOS 官方的說法,使用任務 通知比通過信號量等 ICP 通信方式解除阻塞的任務要快 45%,并且更加省 RAM 內存空間 (使用 GCC 編譯器,-o2 優化級別),任務通知的使用無需創建隊列。想要使用任務通知, 必須將 FreeRTOSConfig.h 中的宏定義
configUSE_TASK_NOTIFICATIONS 設置為 1,其實 FreeRTOS 默認是為 1 的,所以任務通知是默認使能的。
FreeRTOS 提供以下幾種方式發送通知給任務 :
發送通知給任務, 如果有通知未讀,不覆蓋通知值。
發送通知給任務,直接覆蓋通知值。
發送通知給任務,設置通知值的一個或者多個位,可以當做事件組來使用。
發送通知給任務,遞增通知值,可以當做計數信號量使用。 通過對以上任務通知方式的合理使用,可以在一定場合下替代 FreeRTOS 的信號量, 隊列、事件組等。
當然,凡是都有利弊,不然的話 FreeRTOS 還要內核的 IPC 通信機制干嘛,消息通知 雖然處理更快,RAM 開銷更小,但也有以下限制 :
只能有一個任務接收通知消息,因為必須指定接收通知的任務。。
只有等待通知的任務可以被阻塞,發送通知的任務,在任何情況下都不會因為發 送失敗而進入阻塞態。
二、任務通知的運作機制
顧名思義,任務通知是屬于任務中附帶的資源,所以在任務被創建的時候,任務通知 也被初始化的,而在分析隊列和信號量的章節中,我們知道在使用隊列、信號量前,必須 先創建隊列和信號量,目的是為了創建隊列數據結構。
比如使用 xQueueCreate()函數創建 隊列,用 xSemaphoreCreateBinary()函數創建二值信號量等等。再來看任務通知,由于任務 通知的數據結構包含在任務控制塊中,只要任務存在,任務通知數據結構就已經創建完畢, 可以直接使用,所以使用的時候很是方便。
任務通知可以在任務中向指定任務發送通知,也可以在中斷中向指定任務發送通知, FreeRTOS 的每個任務都有一個 32 位的通知值,任務控制塊中的成員變量 ulNotifiedValue 就是這個通知值。
只有在任務中可以等待通知,而不允許在中斷中等待通知。如果任務在等待的通知暫時無效,任務會根據用戶指定的阻塞超時時間進入阻塞狀態,我們可以將等 待通知的任務看作是消費者;其它任務和中斷可以向等待通知的任務發送通知,發送通知 的任務和中斷服務函數可以看作是生產者,當其他任務或者中斷向這個任務發送任務通知, 任務獲得通知以后,該任務就會從阻塞態中解除,這與 FreeRTOS 中內核的其他通信機制 一致。
三、任務通知的函數接口講解
1. xTaskGenericNotify()
我們先看一下發送通知 API 函數。這類函數比較多,有 6 個。但仔細分析會發現它們 只能完成 3 種操作,每種操作有兩個 API 函數,分別為帶中斷保護版本和不帶中斷保護版 本。FreeRTOS 將 API 細分為帶中斷保護版本和不帶中斷保護版本是為了節省中斷服務程 序處理時間,提升性能。
通過前面通信機制的學習,相信大家都了解了 FreeRTOS 的風格, 這里的任務通知發送函數也是利用宏定義來進行擴展的,所有的函數都是一個宏定義,在 任務中發送任務通知的函數均是調用 xTaskGenericNotify()函數進行發送通知,xTaskGenericNotify()函數是一個通用的任務通知發送函數,在任務中發送通知的 API 函 數 , 如 xTaskNotifyGive() 、 xTaskNotify() ,xTaskNotifyAndQuery() , 都 是 以 xTaskGenericNotify()為原型的,只不過指定的發送方式不同而已。
2.xTaskNotifyGive()
xTaskNotifyGive()是一個宏,宏展開是調用函數 xTaskNotify( ( xTaskToNotify ), ( 0 ), eIncrement ),即向一個任務發送通知,并將對方的任務通知值加 1。該函數可以作為二值 信號量和計數信號量的一種輕量型的實現,速度更快,在這種情況下對象任務在等待任務 通 知 的 時 候 應 該 是 使 用 函 數 ulTaskNotifyTake() 而不是 xTaskNotifyWait() 。xTaskNotifyGive() 不 能 在 中 斷 里 面 使 用 , 而 是 使 用 具 有 中 斷 保 護 功 能 的 vTaskNotifyGiveFromISR()來代替。
xTaskNotifyGive()函數說明
xTaskNotifyGive()函數應用舉例
static void prvTask1( void *pvParameters ); static void prvTask2( void *pvParameters ); /*定義任務句柄 */ static TaskHandle_t xTask1 = NULL, xTask2 = NULL; /* 主函數:創建兩個任務,然后開始任務調度 */ void main( void ) {
xTaskCreate(prvTask1, "Task1", 200, NULL, tskIDLE_PRIORITY, &xTask1);
xTaskCreate(prvTask2, "Task2", 200, NULL, tskIDLE_PRIORITY, &xTask2);
vTaskStartScheduler();
} /*-----------------------------------------------------------*/ static void prvTask1( void *pvParameters ) { for ( ;; ) { /* 向 prvTask2()發送一個任務通知,讓其退出阻塞狀態 */ xTaskNotifyGive( xTask2 ); /* 阻塞在 prvTask2()的任務通知上
如果沒有收到通知,則一直等待*/ ulTaskNotifyTake( pdTRUE, portMAX_DELAY );
}
} /*-----------------------------------------------------------*/ static void prvTask2( void *pvParameters ) { for ( ;; ) { /* 阻塞在 prvTask1()的任務通知上
如果沒有收到通知,則一直等待*/ ulTaskNotifyTake( pdTRUE, portMAX_DELAY ); /* 向 prvTask1()發送一個任務通知,讓其退出阻塞狀態 */ xTaskNotifyGive( xTask1 );
}
}
完整代碼可進群免費領取!!!
嵌入式物聯網的學習之路非常漫長,不少人因為學習路線不對或者學習內容不夠專業而錯失高薪offer。不過別擔心,我為大家整理了一份150多G的學習資源,基本上涵蓋了嵌入式物聯網學習的所有內容。點擊下方鏈接,0元領取學習資源,讓你的學習之路更加順暢!記得點贊、關注、收藏、轉發哦!
- 贊