FreeRTOS任務(wù)通知 基于STM32

一、任務(wù)通知簡(jiǎn)介

FreeRTOS 從 V8.2.0 版本開(kāi)始提供任務(wù)通知這個(gè)功能,每個(gè)任務(wù)都有一個(gè) 32 位的通知 值,在大多數(shù)情況下,任務(wù)通知可以替代二值信號(hào)量、計(jì)數(shù)信號(hào)量、事件組,也可以替代 長(zhǎng)度為 1 的隊(duì)列(可以保存一個(gè) 32位整數(shù)或指針值)。

相對(duì)于以前使用 FreeRTOS 內(nèi)核通信的資源,必須創(chuàng)建隊(duì)列、二進(jìn)制信號(hào)量、計(jì)數(shù)信 號(hào)量或事件組的情況,使用任務(wù)通知顯然更靈活。

按照 FreeRTOS 官方的說(shuō)法,使用任務(wù) 通知比通過(guò)信號(hào)量等 ICP 通信方式解除阻塞的任務(wù)要快 45%,并且更加省 RAM 內(nèi)存空間 (使用 GCC 編譯器,-o2 優(yōu)化級(jí)別),任務(wù)通知的使用無(wú)需創(chuàng)建隊(duì)列。想要使用任務(wù)通知, 必須將 FreeRTOSConfig.h 中的宏定義
configUSE_TASK_NOTIFICATIONS 設(shè)置為 1
,其實(shí) FreeRTOS 默認(rèn)是為 1 的,所以任務(wù)通知是默認(rèn)使能的。

FreeRTOS 提供以下幾種方式發(fā)送通知給任務(wù) :

發(fā)送通知給任務(wù), 如果有通知未讀,不覆蓋通知值。

發(fā)送通知給任務(wù),直接覆蓋通知值。

發(fā)送通知給任務(wù),設(shè)置通知值的一個(gè)或者多個(gè)位,可以當(dāng)做事件組來(lái)使用。

發(fā)送通知給任務(wù),遞增通知值,可以當(dāng)做計(jì)數(shù)信號(hào)量使用。 通過(guò)對(duì)以上任務(wù)通知方式的合理使用,可以在一定場(chǎng)合下替代 FreeRTOS 的信號(hào)量, 隊(duì)列、事件組等。

當(dāng)然,凡是都有利弊,不然的話 FreeRTOS 還要內(nèi)核的 IPC 通信機(jī)制干嘛,消息通知 雖然處理更快,RAM 開(kāi)銷更小,但也有以下限制 :

只能有一個(gè)任務(wù)接收通知消息,因?yàn)楸仨氈付ń邮胀ㄖ娜蝿?wù)。。

只有等待通知的任務(wù)可以被阻塞,發(fā)送通知的任務(wù),在任何情況下都不會(huì)因?yàn)榘l(fā) 送失敗而進(jìn)入阻塞態(tài)。

二、任務(wù)通知的運(yùn)作機(jī)制

顧名思義,任務(wù)通知是屬于任務(wù)中附帶的資源,所以在任務(wù)被創(chuàng)建的時(shí)候,任務(wù)通知 也被初始化的,而在分析隊(duì)列和信號(hào)量的章節(jié)中,我們知道在使用隊(duì)列、信號(hào)量前,必須 先創(chuàng)建隊(duì)列和信號(hào)量,目的是為了創(chuàng)建隊(duì)列數(shù)據(jù)結(jié)構(gòu)。

比如使用 xQueueCreate()函數(shù)創(chuàng)建 隊(duì)列,用 xSemaphoreCreateBinary()函數(shù)創(chuàng)建二值信號(hào)量等等。再來(lái)看任務(wù)通知,由于任務(wù) 通知的數(shù)據(jù)結(jié)構(gòu)包含在任務(wù)控制塊中,只要任務(wù)存在,任務(wù)通知數(shù)據(jù)結(jié)構(gòu)就已經(jīng)創(chuàng)建完畢, 可以直接使用,所以使用的時(shí)候很是方便。

任務(wù)通知可以在任務(wù)中向指定任務(wù)發(fā)送通知,也可以在中斷中向指定任務(wù)發(fā)送通知, FreeRTOS 的每個(gè)任務(wù)都有一個(gè) 32 位的通知值,任務(wù)控制塊中的成員變量 ulNotifiedValue 就是這個(gè)通知值。

只有在任務(wù)中可以等待通知,而不允許在中斷中等待通知。如果任務(wù)在等待的通知暫時(shí)無(wú)效,任務(wù)會(huì)根據(jù)用戶指定的阻塞超時(shí)時(shí)間進(jìn)入阻塞狀態(tài),我們可以將等 待通知的任務(wù)看作是消費(fèi)者;其它任務(wù)和中斷可以向等待通知的任務(wù)發(fā)送通知,發(fā)送通知 的任務(wù)和中斷服務(wù)函數(shù)可以看作是生產(chǎn)者,當(dāng)其他任務(wù)或者中斷向這個(gè)任務(wù)發(fā)送任務(wù)通知, 任務(wù)獲得通知以后,該任務(wù)就會(huì)從阻塞態(tài)中解除,這與 FreeRTOS 中內(nèi)核的其他通信機(jī)制 一致。

三、任務(wù)通知的函數(shù)接口講解

1. xTaskGenericNotify()

我們先看一下發(fā)送通知 API 函數(shù)。這類函數(shù)比較多,有 6 個(gè)。但仔細(xì)分析會(huì)發(fā)現(xiàn)它們 只能完成 3 種操作,每種操作有兩個(gè) API 函數(shù),分別為帶中斷保護(hù)版本和不帶中斷保護(hù)版 本。FreeRTOS 將 API 細(xì)分為帶中斷保護(hù)版本和不帶中斷保護(hù)版本是為了節(jié)省中斷服務(wù)程 序處理時(shí)間,提升性能。

通過(guò)前面通信機(jī)制的學(xué)習(xí),相信大家都了解了 FreeRTOS 的風(fēng)格, 這里的任務(wù)通知發(fā)送函數(shù)也是利用宏定義來(lái)進(jìn)行擴(kuò)展的,所有的函數(shù)都是一個(gè)宏定義,在 任務(wù)中發(fā)送任務(wù)通知的函數(shù)均是調(diào)用 xTaskGenericNotify()函數(shù)進(jìn)行發(fā)送通知,xTaskGenericNotify()函數(shù)是一個(gè)通用的任務(wù)通知發(fā)送函數(shù),在任務(wù)中發(fā)送通知的 API 函 數(shù) , 如 xTaskNotifyGive() 、 xTaskNotify() ,xTaskNotifyAndQuery() , 都 是 以 xTaskGenericNotify()為原型的,只不過(guò)指定的發(fā)送方式不同而已。

2.xTaskNotifyGive()

xTaskNotifyGive()是一個(gè)宏,宏展開(kāi)是調(diào)用函數(shù) xTaskNotify( ( xTaskToNotify ), ( 0 ), eIncrement ),即向一個(gè)任務(wù)發(fā)送通知,并將對(duì)方的任務(wù)通知值加 1。該函數(shù)可以作為二值 信號(hào)量和計(jì)數(shù)信號(hào)量的一種輕量型的實(shí)現(xiàn),速度更快,在這種情況下對(duì)象任務(wù)在等待任務(wù) 通 知 的 時(shí) 候 應(yīng) 該 是 使 用 函 數(shù) ulTaskNotifyTake() 而不是 xTaskNotifyWait() 。xTaskNotifyGive() 不 能 在 中 斷 里 面 使 用 , 而 是 使 用 具 有 中 斷 保 護(hù) 功 能 的 vTaskNotifyGiveFromISR()來(lái)代替。

xTaskNotifyGive()函數(shù)說(shuō)明

xTaskNotifyGive()函數(shù)應(yīng)用舉例

 static void prvTask1( void *pvParameters ); static void prvTask2( void *pvParameters ); /*定義任務(wù)句柄 */ static TaskHandle_t xTask1 = NULL, xTask2 = NULL; /* 主函數(shù):創(chuàng)建兩個(gè)任務(wù),然后開(kāi)始任務(wù)調(diào)度 */ 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()發(fā)送一個(gè)任務(wù)通知,讓其退出阻塞狀態(tài) */ xTaskNotifyGive( xTask2 ); /* 阻塞在 prvTask2()的任務(wù)通知上
 如果沒(méi)有收到通知,則一直等待*/ ulTaskNotifyTake( pdTRUE, portMAX_DELAY );
 }
 } /*-----------------------------------------------------------*/ static void prvTask2( void *pvParameters ) { for ( ;; ) { /* 阻塞在 prvTask1()的任務(wù)通知上
 如果沒(méi)有收到通知,則一直等待*/ ulTaskNotifyTake( pdTRUE, portMAX_DELAY ); /* 向 prvTask1()發(fā)送一個(gè)任務(wù)通知,讓其退出阻塞狀態(tài) */ xTaskNotifyGive( xTask1 );
 }
}

完整代碼可進(jìn)群免費(fèi)領(lǐng)取!!!

嵌入式物聯(lián)網(wǎng)的學(xué)習(xí)之路非常漫長(zhǎng),不少人因?yàn)閷W(xué)習(xí)路線不對(duì)或者學(xué)習(xí)內(nèi)容不夠?qū)I(yè)而錯(cuò)失高薪offer。不過(guò)別擔(dān)心,我為大家整理了一份150多G的學(xué)習(xí)資源,基本上涵蓋了嵌入式物聯(lián)網(wǎng)學(xué)習(xí)的所有內(nèi)容。點(diǎn)擊下方鏈接,0元領(lǐng)取學(xué)習(xí)資源,讓你的學(xué)習(xí)之路更加順暢!記得點(diǎn)贊、關(guān)注、收藏、轉(zhuǎn)發(fā)哦!

點(diǎn)擊這里找小助理0元領(lǐng)取:

the end

評(píng)論(0)