FreeRTOS實(shí)時(shí)操作系統(tǒng)的任務(wù)通知方法
前言
注:本文介紹任務(wù)通知的基礎(chǔ)知識(shí),詳細(xì)源碼分析見FreeRTOS進(jìn)階任務(wù)通知示例分析
每個(gè)RTOS任務(wù)都有一個(gè)32位的通知值,任務(wù)創(chuàng)建時(shí),這個(gè)值被初始化為0。RTOS任務(wù)通知相當(dāng)于直接向任務(wù)發(fā)送一個(gè)事件,接收到通知的任務(wù)可以解除阻塞狀態(tài),前提是這個(gè)阻塞事件是因等待通知而引起的。發(fā)送通知的同時(shí),也可以可選的改變接收任務(wù)的通知值。
可以通過(guò)下列方法向接收任務(wù)更新通知:
- 不覆蓋接收任務(wù)的通知值
- 覆蓋接收任務(wù)的通知值
- 設(shè)置接收任務(wù)通知值的某些位
- 增加接收任務(wù)的通知值
相對(duì)于用前必須分別創(chuàng)建隊(duì)列、二進(jìn)制信號(hào)量、計(jì)數(shù)信號(hào)量或事件組的情況,使用任務(wù)通知顯然更靈活。更好的是,相比于使用信號(hào)量解除任務(wù)阻塞,使用任務(wù)通知可以快45%、使用更少的RAM(使用GCC編譯器,-o2優(yōu)化級(jí)別)。
使用API函數(shù)xTaskNotify()和xTaskNotifyGive()(中斷保護(hù)等價(jià)函數(shù)為xTaskNotifyFromISR()和vTaskNotifyGiveFromISR())發(fā)送通知,在接收RTOS任務(wù)調(diào)用API函數(shù)xTaskNotifyWait()或ulTaskNotifyTake()之前,這個(gè)通知都被保持著。如果接收RTOS任務(wù)已經(jīng)因?yàn)榈却ㄖM(jìn)入阻塞狀態(tài),則接收到通知后任務(wù)解除阻塞并清除通知。
RTOS任務(wù)通知功能默認(rèn)是使能的,可以通過(guò)在文件FreeRTOSConfig.h中設(shè)置宏configUSE_TASK_NOTIFICATIONS為0來(lái)禁止這個(gè)功能,禁止后每個(gè)任務(wù)節(jié)省8字節(jié)內(nèi)存。
雖然RTOS任務(wù)通知速度更快并且占用內(nèi)存更少,但它也有一些限制:
只能有一個(gè)任務(wù)接收通知事件。
接收通知的任務(wù)可以因?yàn)榈却ㄖM(jìn)入阻塞狀態(tài),但是發(fā)送通知的任務(wù)即便不能立即完成通知發(fā)送也不能進(jìn)入阻塞狀態(tài)。
1.發(fā)送通知-方法1
1.1函數(shù)描述
BaseType_t xTaskNotify( TaskHandle_txTaskToNotify, uint32_t ulValue, eNotifyAction eAction);
向指定任務(wù)發(fā)送指定的通知值。如果打算使用RTOS任務(wù)通知實(shí)現(xiàn)輕量級(jí)的二進(jìn)制或計(jì)數(shù)信號(hào)量,推薦使用API函數(shù)xTaskNotifyGive()來(lái)代替本函數(shù)。
此函數(shù)不可以在中斷服務(wù)例程中調(diào)用,中斷保護(hù)等價(jià)函數(shù)為xTaskNotifyFromISR()。
1.2參數(shù)描述
xTaskToNotify
:被通知的任務(wù)句柄。
ulValue
:通知更新值eAction:枚舉類型,指明更新通知值的方法
枚舉變量成員以及作用如下表所示。
1.3返回值
參數(shù)eAction為eSetValueWithoutOverwrite時(shí),如果被通知任務(wù)還沒(méi)取走上一個(gè)通知,又接收到了一個(gè)通知,則這次通知值未能更新并返回pdFALSE,否則返回pdPASS。
2.發(fā)送通知-方法2
2.1函數(shù)描述
BaseType_t xTaskNotifyGive(TaskHandle_t xTaskToNotify );
其實(shí)這是一個(gè)宏,本質(zhì)上相當(dāng)于xTaskNotify( ( xTaskToNotify ), ( 0 ), eIncrement )??梢允褂迷揂PI函數(shù)代替二進(jìn)制或計(jì)數(shù)信號(hào)量,但速度更快。在這種情況下,應(yīng)該使用API函數(shù)ulTaskNotifyTake()來(lái)等待通知,而不應(yīng)該使用API函數(shù)xTaskNotifyWait()。
此函數(shù)不可以在中斷服務(wù)例程中調(diào)用,中斷保護(hù)等價(jià)函數(shù)為vTaskNotifyGiveFromISR()。
2.2參數(shù)描述
xTaskToNotify:被通知的任務(wù)句柄。
2.3用法舉例
staticvoid prvTask1( void *pvParameters ); staticvoid prvTask2( void *pvParameters ); /* 保存任務(wù)句柄 */ staticTaskHandle_t xTask1 = NULL, xTask2 = NULL; /* 創(chuàng)建兩個(gè)任務(wù),它們之間反復(fù)發(fā)送通知,啟動(dòng)RTOS調(diào)度器*/ voidmain( void ) { xTaskCreate( prvTask1, "Task1",200, NULL, tskIDLE_PRIORITY, &xTask1 ); xTaskCreate( prvTask2, "Task2",200, NULL, tskIDLE_PRIORITY, &xTask2 ); vTaskStartScheduler(); } /*-----------------------------------------------------------*/ staticvoid prvTask1( void *pvParameters ) { for( ;; ) { /*向prvTask2(),發(fā)送通知,使其解除阻塞狀態(tài) */ xTaskNotifyGive( xTask2 ); /* 等待prvTask2()的通知,進(jìn)入阻塞 */ ulTaskNotifyTake( pdTRUE, portMAX_DELAY); } } /*-----------------------------------------------------------*/ staticvoid prvTask2( void *pvParameters ) { for( ;; ) { /* 等待prvTask1()的通知,進(jìn)入阻塞 */ ulTaskNotifyTake( pdTRUE, portMAX_DELAY); /*向prvTask1(),發(fā)送通知,使其解除阻塞狀態(tài) */ xTaskNotifyGive( xTask1 ); } }
3.獲取通知
3.1函數(shù)描述
uint32_t ulTaskNotifyTake( BaseType_txClearCountOnExit, TickType_txTicksToWait );
ulTaskNotifyTake()是專門為使用更輕量級(jí)更快的方法來(lái)代替二進(jìn)制或計(jì)數(shù)信號(hào)量而量身打造的。FreeRTOS獲取信號(hào)量的API函數(shù)為xSemaphoreTake(),可以使用ulTaskNotifyTake()函數(shù)等價(jià)代替。
當(dāng)一個(gè)任務(wù)使用通知值來(lái)實(shí)現(xiàn)二進(jìn)制或計(jì)數(shù)信號(hào)量時(shí),其它任務(wù)或者中斷要使用API函數(shù)xTaskNotifyGive()或者使用參數(shù)eAction為eIncrement的API函數(shù)xTaskNotify()。推薦使用xTaskNotifyGive()函數(shù)(其實(shí)是個(gè)宏,我們這里把它看作一個(gè)API函數(shù))。另外需要注意的是,如果在中斷中使用,要使用它們的中斷保護(hù)等價(jià)函數(shù):vTaskNotifyGiveFromISR()和xTaskNotifyFromISR()。
API函數(shù)xTaskNotifyTake()有兩種方法處理任務(wù)的通知值,一種方法是在函數(shù)退出時(shí)將通知值清零,這種方法適用于實(shí)現(xiàn)二進(jìn)制信號(hào)量;另外一種方法是在函數(shù)退出時(shí)將通知值減1,這種方法適用于實(shí)現(xiàn)計(jì)數(shù)信號(hào)量。
如果RTOS任務(wù)的通知值為0,使用xTaskNotifyTake()可以可選的使任務(wù)進(jìn)入阻塞狀態(tài),直到該任務(wù)的通知值不為0。進(jìn)入阻塞的任務(wù)不消耗CPU時(shí)間。
3.2參數(shù)描述
xClearCountOnExit
:如果該參數(shù)設(shè)置為pdFALSE,則API函數(shù)xTaskNotifyTake()退出前,將任務(wù)的通知值減1;如果該參數(shù)設(shè)置為pdTRUE,則API函數(shù)xTaskNotifyTake()退出前,將任務(wù)通知值清零。
xTicksToWait
:因等待通知而進(jìn)入阻塞狀態(tài)的最大時(shí)間。時(shí)間單位為系統(tǒng)節(jié)拍周期。宏pdMS_TO_TICKS用于將指定的毫秒時(shí)間轉(zhuǎn)化為相應(yīng)的系統(tǒng)節(jié)拍數(shù)。
3.3返回值
返回任務(wù)的當(dāng)前通知值,為0或者為調(diào)用API函數(shù)xTaskNotifyTake()之前的通知值減1。
3.4用法舉例
/* 中斷處理程序。*/ voidvANInterruptHandler( void ) { BaseType_txHigherPriorityTaskWoken; prvClearInterruptSource(); /* xHigherPriorityTaskWoken必須被初始化為pdFALSE。如果調(diào)用vTaskNotifyGiveFromISR()會(huì)解除vHandlingTask任務(wù)的阻塞狀態(tài),并且vHandlingTask任務(wù)的優(yōu)先級(jí)高于當(dāng)前處于運(yùn)行狀態(tài)的任務(wù),則xHigherPriorityTaskWoken將會(huì)自動(dòng)被設(shè)置為pdTRUE。*/ xHigherPriorityTaskWoken = pdFALSE; /*向一個(gè)任務(wù)發(fā)送通知,xHandlingTask是該任務(wù)的句柄。*/ vTaskNotifyGiveFromISR( xHandlingTask,&xHigherPriorityTaskWoken ); /* 如果xHigherPriorityTaskWoken為pdTRUE,則強(qiáng)制上下文切換。這個(gè)宏的實(shí)現(xiàn)取決于移植層,可能會(huì)調(diào)用portEND_SWITCHING_ISR */ portYIELD_FROM_ISR(xHigherPriorityTaskWoken ); } /*---------------------------------------------------------------------------------------------------*/ /* 一個(gè)因?yàn)榈却ㄖ枞娜蝿?wù)。*/ voidvHandlingTask( void *pvParameters ) { BaseType_txEvent; for( ;; ) { /*等待通知,無(wú)限期阻塞。參數(shù)pdTRUE表示函數(shù)退出前會(huì)清零通知值。這顯然是用于替代二進(jìn)制信號(hào)量的用法。需要注意的是,真實(shí)的程序一般不會(huì)無(wú)限期阻塞。*/ ulTaskNotifyTake( pdTRUE, portMAX_DELAY); /* 當(dāng)處理完所有事件后,仍然等待下一個(gè)通知*/ do { xEvent = xQueryPeripheral(); if( xEvent != NO_MORE_EVENTS ) { vProcessPeripheralEvent( xEvent); } } while( xEvent != NO_MORE_EVENTS ); } }
4.等待通知
4.1函數(shù)描述
BaseType_t xTaskNotifyWait( uint32_tulBitsToClearOnEntry, uint32_tulBitsToClearOnExit, uint32_t*pulNotificationValue, TickType_txTicksToWait );
如果打算使用RTOS任務(wù)通知實(shí)現(xiàn)輕量級(jí)的二進(jìn)制或計(jì)數(shù)信號(hào)量,推薦使用API函數(shù)ulTaskNotifyTake()來(lái)代替本函數(shù)。
4.2參數(shù)描述
ulBitsToClearOnEntry
:在使用通知之前,先將任務(wù)的通知值與參數(shù)ulBitsToClearOnEntry的按位取反值按位與操作。設(shè)置參數(shù)ulBitsToClearOnEntry為0xFFFFFFFF(ULONG_MAX),表示清零任務(wù)通知值。
ulBitsToClearOnExit
:在函數(shù)xTaskNotifyWait()退出前,將任務(wù)的通知值與參數(shù)ulBitsToClearOnExit的按位取反值按位與操作。
設(shè)置參數(shù)ulBitsToClearOnExit為0xFFFFFFFF(ULONG_MAX),表示清零任務(wù)通知值。
pulNotificationValue
:用于向外回傳任務(wù)的通知值。這個(gè)通知值在參數(shù)ulBitsToClearOnExit起作用前將通知值拷貝到*pulNotificationValue中。如果不需要返回任務(wù)的通知值,這里設(shè)置成NULL。
xTicksToWait
:因等待通知而進(jìn)入阻塞狀態(tài)的最大時(shí)間。時(shí)間單位為系統(tǒng)節(jié)拍周期。宏pdMS_TO_TICKS用于將指定的毫秒時(shí)間轉(zhuǎn)化為相應(yīng)的系統(tǒng)節(jié)拍數(shù)。
4.3返回值
如果接收到通知,返回pdTRUE,如果API函數(shù)xTaskNotifyWait()等待超時(shí),返回pdFALSE。
4.4用法舉例
/*這個(gè)任務(wù)使用任務(wù)通知值的位來(lái)傳遞不同的事件,這在某些情況下可以代替事件組。*/ voidvAnEventProcessingTask( void *pvParameters ) { uint32_tulNotifiedValue; for( ;; ) { /*等待通知,無(wú)限期阻塞(沒(méi)有超時(shí),所以不用檢查函數(shù)返回值)。其它任務(wù)或者中斷設(shè)置的通知值中的不同位表示不同的事件。參數(shù)0x00表示使用通知前不清除任務(wù)的通知值位,參數(shù)ULONG_MAX 表示函數(shù)xTaskNotifyWait()退出前將任務(wù)通知值設(shè)置為0*/ xTaskNotifyWait( 0x00, ULONG_MAX,&ulNotifiedValue, portMAX_DELAY ); /*根據(jù)通知值處理事件*/ if( ( ulNotifiedValue & 0x01 ) != 0) { prvProcessBit0Event(); } if( ( ulNotifiedValue & 0x02 ) != 0) { prvProcessBit1Event(); } if( ( ulNotifiedValue & 0x04 ) != 0) { prvProcessBit2Event(); } /* ……*/ } }
5.任務(wù)通知并查詢
5.1函數(shù)描述
BaseType_t xTaskNotifyAndQuery(TaskHandle_t xTaskToNotify, uint32_tulValue, eNotifyActioneAction, uint32_t*pulPreviousNotifyValue );
此函數(shù)與任務(wù)通知API函數(shù)xTaskNotify()非常像,只不過(guò)此函數(shù)具有一個(gè)附加參數(shù),用來(lái)回傳任務(wù)當(dāng)前的通知值,然后根據(jù)參數(shù)ulValue和eAction更新任務(wù)的通知值。
此函數(shù)不能在中斷服務(wù)例程中使用,在中斷服務(wù)例程中使用xTaskNotifyAndQueryFromISR()函數(shù)。
5.2參數(shù)描述
xTaskToNotify
:被通知的任務(wù)句柄。
ulValue
:通知更新值
eAction
:枚舉類型,指明更新通知值的方法,枚舉變量成員以及作用見xTaskNotify()一節(jié)。
pulPreviousNotifyValue
:回傳未被更新的任務(wù)通知值。如果不需要回傳未被更新的任務(wù)通知值,這里設(shè)置為NULL,這樣就等價(jià)于調(diào)用xTaskNotify()函數(shù)。
5.3返回值
參數(shù)eAction為eSetValueWithoutOverwrite時(shí),如果被通知任務(wù)還沒(méi)取走上一個(gè)通知,又接收到了一個(gè)通知,則這次通知值未能更新并返回pdFALSE,否則返回pdPASS。
以上就是FreeRTOS實(shí)時(shí)操作系統(tǒng)的任務(wù)通知方法的詳細(xì)內(nèi)容,更多關(guān)于FreeRTOS任務(wù)通知方法的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
FreeRTOS實(shí)時(shí)操作系統(tǒng)的任務(wù)概要講解
這篇文章主要為大家介紹了FreeRTOS實(shí)時(shí)操作系統(tǒng)的任務(wù)概要講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS實(shí)時(shí)操作系統(tǒng)信號(hào)量基礎(chǔ)
這篇文章主要為大家介紹了FreeRTOS實(shí)時(shí)操作系統(tǒng)信號(hào)量基礎(chǔ),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS實(shí)時(shí)操作系統(tǒng)內(nèi)核配置說(shuō)明
這篇文章主要為大家介紹了FreeRTOS實(shí)時(shí)操作系統(tǒng)內(nèi)核配置及說(shuō)明,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04freertos實(shí)時(shí)操作系統(tǒng)空閑任務(wù)阻塞延時(shí)示例解析
這篇文章主要為大家介紹了freertos實(shí)時(shí)操作系統(tǒng)的空閑任務(wù)及阻塞延時(shí)示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-04-04FreeRTOS進(jìn)階之空閑任務(wù)示例完全解析
這篇文章主要為大家介紹了FreeRTOS進(jìn)階之空閑任務(wù)示例的完全解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS動(dòng)態(tài)內(nèi)存分配管理heap_2示例
這篇文章主要介紹了FreeRTOS動(dòng)態(tài)內(nèi)存分配管理heap_2示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS進(jìn)階之調(diào)度器啟動(dòng)過(guò)程分析
這篇文章主要為大家介紹了FreeRTOS進(jìn)階之調(diào)度器啟動(dòng)過(guò)程分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS實(shí)時(shí)操作系統(tǒng)多任務(wù)管理基礎(chǔ)知識(shí)
這篇文章主要為大家介紹了FreeRTOS實(shí)時(shí)操作系統(tǒng)多任務(wù)管理的基礎(chǔ)知識(shí),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04