本節需要掌握以下內容:
1、任務通知的簡介(了解)
2、任務通知值和通知狀態(熟悉)
3、任務通知相關API函數介紹(熟悉)
4、任務通知模擬信號量實驗(掌握)
5、任務通知模擬消息郵箱實驗(掌握)
6、任務通知模擬事件標志組實驗(掌握)
7、課堂總結(掌握)
一、任務通知的簡介(了解)
1.1 任務通知的相關概念
任務通知:用來通知任務的,任務控制塊中的結構體成員變量ulNotifiedValue就是這個通知值。
(隊列、信號量、事件標志組也可以用來通知任務。隊列可以往其它任務發數據,信號量同樣發送一個資源,釋放信號量,另外一個任務獲取信號量,事件標志組把某一位置一,另一個任務就來讀這個位是不是1。這些都能用來通知任務,為什么我們還要用任務通知呢?
最主要的是:內存消耗比較小,因為隊列、信號量、事件標志組使用之前都要提前創建好,才能去操作它,而任務通知就不用去創建,因為它的結構體成員就在任務控制塊TCB里面。
每創建一個任務就會給這個任務的任務控制塊分配個內存,任務控制塊中的結構體成員變量ulNotifiedValue就是這個通知值。而任務創建好之后,這個結構體成員變量就被創建好了)
- 使用隊列、信號量、事件標志組時都需創建一個結構體,通過中間的結構體進行間接通信!
?使用隊列/信號量/事件標志組時發送數據,就是把發送數據放在隊列/信號量/事件標志組的結構體中,接收也是從隊列/信號量/事件標志組的結構體中讀出來。
- 使用任務通知時,任務結構體TCB中就包含了內部對象,可以直接接收別人發過來的“通知”
發送的時候實際就是任務一直接去操作任務二 任務控制塊中的?結構體成員變量ulNotifiedValue,給這個成員寫一個值,接收的時候就直接去讀這個值。
?任務通知值的更新方式
- 不覆蓋接受任務的通知值(這個結構體數據成員有數值就不寫進去,沒有數值的時候才寫進去)
- 覆蓋接受任務的通知值(不管有沒有數值,都能寫進去)
- 更新接受任務通知值的一個或多個bit
- 增加接受任務的通知值
只要合理、靈活的利用任務通知的特點,可以在一些場合中替代隊列、信號量、時間標志組!
1.2 任務通知的優勢及劣勢
任務通知的優勢:
- 效率更高:使用任務通知向任務發送時間或數據比使用隊列、時間標志組或信號快得多(freeRTOS官方也是做了一個測試,使用任務通知來模擬二值信號量這樣的一個方式來解除任務的阻塞事件,相對于常規的二值信號量,快了45%)
- 使用內存更小:使用其它方法時都要創建對應的結構體,使用任務通知時無需額外創建結構體
任務通知的劣勢:
- 無法發送數據給ISR:ISR沒有任務結構體,所以無法給ISR發送數據。但是ISR可以使用任務通知的功能,發數據給任務。(發送可以不能接收)
- 無法廣播給多個任務:任務通知只能是被指定的一個任務接受并處理
- 無法緩存多個數據:任務通知時通過更新任務通知值來發送數據的,任務結構體中只有一個任務通知值,只能一個數據。(隊列的話,只要有m個隊列項就保存m個數據)
- 發送受阻不支持阻塞:發送方無法進入阻塞狀態等待(隊列已滿,可以阻塞)
二、任務通知值和通知狀態
任務都有一個結構體:任務控制塊TCB,它里邊有兩個結構體成員變量:
- 一個是uint32_t類型,用來表示通知值
- 一個是uint8_t類型,用來表示通知狀態
2.1 任務通知值
任務通知值的更新方式有多種類型:
- 計數值(發送一次任務通知值更新,數值類型累加,類似信號量)
- ?相應位置一(發送一次任務通知值更新,相應位置一,類似事件標志組)
- 任意數值(支持覆寫和不覆寫,類似隊列)
2.2 任務通知狀態
其中任務通知狀態共有三種值:
- ?任務未等待通知:任務通知默認的初始化狀態
- 等待通知:接收方已經準備好了(調用了接收任務通知函數),等待發送放給個通知
- 等待接收:發送方已經發送出去了(調用了發送任務通知函數),等待接收方接收
三、任務通知相關API函數介紹(介紹)
任務通知API函數主要有兩類:①發送通知,②接收通知。
注意:發送通知API函數可以用于任務和中斷服務函數中;接收通知API函數只能用在任務中。(因為中斷沒有任務控制塊這個結構體)
3.1 發送通知相關API函數:
函數 | 描述 |
xTaskNotify() | 發送通知,帶有通知值 |
xTaskNotifyAndQuery() | 發送通知,帶有通知值并且保留接收任務的原通知值 |
xTaskNotifyGive() | 發送通知,不帶通知值 |
xTaskNotifyFromISR() | 在中斷中發送任務通知 |
xTaskNotifyAndQueryFromISR() | |
vTaskNotifyGiveFromISR() |
?在任務中發送通知的3個API函數原型如下所示,可以看到內部都是都是調用的xTaskGenericNotity()函數,唯一的區別就是帶入的入口參數有去區別
?
xTaskGenericNotity()函數參數?如下:
形參 | 描述 |
xTaskToNotify | 接收任務通知的任務句柄 |
uxIndexToNotify | 任務的指定通知(任務通知相關數組成員) |
ulValue | 任務通知值 |
eAction | 通知方式(通知值更新方式) |
pulPreviousNotificationValue | 用于保存更新前的任務通知值(為NULL則不保存) |
?任務通知方式共有以下幾種:
?3.2 接收通知相關API函數:
函數 | 描述 |
ulTaskNotifyTake() | 獲取任務通知,可以設置在退出此函數的時候將任務通知值清零或者減一。 當任務通知用作二值信號量或者計數信號量的時候,使用此函數來獲取信號量。 |
xTaskNotifyWait() | 獲取任務通知,比 ulTaskNotifyTak()更為復雜,可獲取通知值和清除通知值的指定位 |
總結:?
- 當任務通知用作于信號量時,使用函數獲取信號量:ulTaskNotifyTake()
- 當任務通知用作于事件標志組或隊列時,使用此函數來獲取: xTaskNotifyWait()
3.2.1?任務通知用作于信號量ulTaskNotifyTake()

?此函數用于接收任務通知值,可以設置在退出此函數的時候將任務通知值清零或者減一
形參 | 描述 |
uxIndexToWaitOn | 任務的指定通知(任務通知相關數組成員) |
xClearCountOnExit | 指定在成功接收通知后,將通知值清零或減 1, pdTRUE:把通知值清零;pdFALSE:把通知值減一 |
xTicksToWait | 阻塞等待任務通知值的最大時間 |
返回值 | 描述 |
0 | 接收失敗 |
非 0 | 接收成功,返回任務通知的通知值 |
3.2.2?任務通知用作于事件標志組或隊列 xTaskNotifyWait()
?此函數用于獲取通知值和清除通知值的指定位值,適用于模擬隊列和事件標志組,使用該函數來獲取任務通知。
形參 | 描述 |
uxIndexToWaitOn | 任務的指定通知(任務通知相關數組成員) |
ulBitesToClearOnEntry | 等待前清零指定任務通知值的比特位(舊值對應bit清0) |
ulBitesToClearOnExit | 成功等待后清零指定的任務通知值比特位(新值對應bit清0) |
pulNotificationValue | 用來取出通知值(如果不需要取出,可設為NULL) |
xTicksToWait | 阻塞等待任務通知值的最大時間 |
返回值 | 描述 |
pdTRUE | 等待任務通知成功 |
pdFALSE | 等待任務通知失敗 |
?四、任務通知模擬信號量實驗(掌握)
4.1、實驗目的:
學習 FreeRTOS 的任務通知功能模擬二值信號量和計數型信號量
4.2、實驗設計:
將設計三個任務:start_task、task1、task2
三個任務的功能如下:
- start_task:用來創建task1和task2任務
- task1:用于按鍵掃描,當檢測到按鍵KEY0被按下時,將發送任務通知
- task2:用于接收任務通知,并打印相關提示信息
4.3 實驗代碼
demo.c
五、任務通知模擬信息郵箱實驗(掌握)
5.1、實驗目的:
學習 FreeRTOS 的任務通知功能模擬消息郵箱
5.2、實驗設計:
將設計三個任務:start_task、task1、task2
三個任務的功能如下:
- start_task:用來創建task1和task2任務
- task1:用于按鍵掃描,將按下的按鍵鍵值通過任務通知發送給指定任務
- task2:用于接收任務通知,并根據接收到的數據做相應動作
5.3 實驗代碼
demo.c
代碼明天更新
六、任務通知模擬時間標志組實驗(掌握)
6.1、實驗目的:
學習 FreeRTOS 的任務通知功能模擬事件標志組
6.2、實驗設計:
將設計三個任務:start_task、task1、task2
三個任務的功能如下:
- start_task:用來創建task1和task2任務
- task1:用于按鍵掃描,當檢測到按鍵按下時,發送任務通知設置不同標志位
- task2:用于接收任務通知,并打印相關提示信息
6.3 實驗代碼
demo.c