FreeRTOS進(jìn)階之空閑任務(wù)示例完全解析
當(dāng)RTOS調(diào)度器開始工作后,為了保證至少有一個(gè)任務(wù)在運(yùn)行,空閑任務(wù)被自動(dòng)創(chuàng)建,占用最低優(yōu)先級(0優(yōu)先級)。
xReturn = xTaskCreate( prvIdleTask, "IDLE",configMINIMAL_STACK_SIZE, (void * ) NULL, (tskIDLE_PRIORITY | portPRIVILEGE_BIT ), &xIdleTaskHandle);
空閑任務(wù)是FreeRTOS不可缺少的任務(wù),因?yàn)镕reeRTOS設(shè)計(jì)要求必須至少有一個(gè)任務(wù)處于運(yùn)行狀態(tài)。我們來看一下空閑任務(wù)要做的工作。
1.釋放內(nèi)存
從V9.0版本開始,如果一個(gè)任務(wù)刪除另外一個(gè)任務(wù),被刪除任務(wù)的堆棧和TCB立即釋放。如果一個(gè)任務(wù)刪除自己,則任務(wù)的堆棧和TCB和以前一樣,通過空閑任務(wù)刪除。所以空閑任務(wù)開始就會(huì)檢查是否有任務(wù)刪除了自己,如果有的話,空閑任務(wù)負(fù)責(zé)刪除這個(gè)任務(wù)的TCB和堆??臻g。
2. 處理空閑優(yōu)先級任務(wù)
當(dāng)使用搶占式內(nèi)核,相同優(yōu)先級的任務(wù)使用時(shí)間片方式獲得CPU權(quán)限。如果有任務(wù)與空閑任務(wù)共享一個(gè)優(yōu)先級,并且宏configIDLE_SHOULD_YIELD設(shè)置為1,那么空閑任務(wù)不必等到時(shí)間片耗盡再進(jìn)行任務(wù)切換。
所以空閑任務(wù)檢查空閑優(yōu)先級下的就緒列表中是否有多個(gè)任務(wù),有的話則執(zhí)行任務(wù)切換,讓用戶任務(wù)獲得CPU權(quán)限。
宏configIDLE_SHOULD_YIELD控制任務(wù)在空閑優(yōu)先級中的行為。僅在滿足下列條件后,才會(huì)起作用。
- 使用搶占式內(nèi)核調(diào)度
- 用戶任務(wù)使用空閑優(yōu)先級。
通過時(shí)間片共享同一個(gè)優(yōu)先級的多個(gè)任務(wù),如果共享的優(yōu)先級大于空閑優(yōu)先級,并假設(shè)沒有更高優(yōu)先級任務(wù),這些任務(wù)應(yīng)該獲得相同的處理器時(shí)間。
但如果共享空閑優(yōu)先級時(shí),情況會(huì)稍微有些不同。當(dāng)configIDLE_SHOULD_YIELD為1時(shí),其它共享空閑優(yōu)先級的用戶任務(wù)就緒時(shí),空閑任務(wù)立刻讓出CPU,用戶任務(wù)運(yùn)行,這樣確保了能最快響應(yīng)用戶任務(wù)。處于這種模式下也會(huì)有不良效果(取決于你的程序需要),描述如下:
圖中描述了四個(gè)處于空閑優(yōu)先級的任務(wù),任務(wù)A、B和C是用戶任務(wù),任務(wù)I是空閑任務(wù)。上下文切換周期性的發(fā)生在T0、T1…T6時(shí)刻。當(dāng)用戶任務(wù)運(yùn)行時(shí),空閑任務(wù)立刻讓出CPU,但是,空閑任務(wù)已經(jīng)消耗了當(dāng)前時(shí)間片中的一定時(shí)間。這樣的結(jié)果就是空閑任務(wù)I和用戶任務(wù)A共享一個(gè)時(shí)間片。用戶任務(wù)B和用戶任務(wù)C因此獲得了比用戶任務(wù)A更多的處理器時(shí)間。
可以通過下面方法避免:
- 如果合適的話,將處于空閑優(yōu)先級的各單獨(dú)的任務(wù)放置到空閑鉤子函數(shù)中;
- 創(chuàng)建的用戶任務(wù)優(yōu)先級大于空閑優(yōu)先級;
- 設(shè)置IDLE_SHOULD_YIELD為0;
設(shè)置configIDLE_SHOULD_YIELD為0將阻止空閑任務(wù)為用戶任務(wù)讓出CPU,直到空閑任務(wù)的時(shí)間片結(jié)束。這確保所有處在空閑優(yōu)先級的任務(wù)分配到相同多的處理器時(shí)間,但是,這是以分配給空閑任務(wù)更高比例的處理器時(shí)間為代價(jià)的。
3.執(zhí)行空閑任務(wù)鉤子函數(shù)
空閑任務(wù)鉤子是一個(gè)函數(shù),這個(gè)函數(shù)由用戶來實(shí)現(xiàn),RTOS規(guī)定了函數(shù)的名字和參數(shù),這個(gè)函數(shù)在每個(gè)空閑任務(wù)周期都會(huì)被調(diào)用。
要?jiǎng)?chuàng)建一個(gè)空閑鉤子:
- 設(shè)置FreeRTOSConfig.h 文件中的configUSE_IDLE_HOOK 為1;
- 定義一個(gè)函數(shù),函數(shù)名和參數(shù)如下所示:
void vApplicationIdleHook(void );
這個(gè)鉤子函數(shù)不可以調(diào)用會(huì)引起空閑任務(wù)阻塞的API函數(shù)(例如:vTaskDelay()、帶有阻塞時(shí)間的隊(duì)列和信號量函數(shù)),在鉤子函數(shù)內(nèi)部使用協(xié)程是被允許的。
使用空閑鉤子函數(shù)設(shè)置CPU進(jìn)入省電模式是很常見的。
4.低功耗tickless模式
通常情況下,F(xiàn)reeRTOS回調(diào)空閑任務(wù)鉤子函數(shù)(需要設(shè)計(jì)者自己實(shí)現(xiàn)),在空閑任務(wù)鉤子函數(shù)中設(shè)置微處理器進(jìn)入低功耗模式來達(dá)到省電的目的。因?yàn)橄到y(tǒng)要響應(yīng)系統(tǒng)節(jié)拍中斷事件,因此使用這種方法會(huì)周期性的退出、再進(jìn)入低功耗狀態(tài)。如果系統(tǒng)節(jié)拍中斷頻率過快,則大部分電能和CPU時(shí)間會(huì)消耗在進(jìn)入和退出低功耗狀態(tài)上。
FreeRTOS的tickless空閑模式會(huì)在空閑周期時(shí)停止周期性系統(tǒng)節(jié)拍中斷。停止周期性系統(tǒng)節(jié)拍中斷可以使微控制器長時(shí)間處于低功耗模式。移植層需要配置外部喚醒中斷,當(dāng)喚醒事件到來時(shí),將微控制器從低功耗模式喚醒。
微控制器喚醒后,會(huì)重新使能系統(tǒng)節(jié)拍中斷。由于微控制器在進(jìn)入低功耗后,系統(tǒng)節(jié)拍計(jì)數(shù)器是停止的,但我們又需要知道這段時(shí)間能折算成多少次系統(tǒng)節(jié)拍中斷周期,這就需要有一個(gè)不受低功耗影響的外部時(shí)鐘源,即微處理器處于低功耗模式時(shí)它也在計(jì)時(shí)的,這樣在重啟系統(tǒng)節(jié)拍中斷時(shí)就可以根據(jù)這個(gè)外部計(jì)時(shí)器計(jì)算出一個(gè)調(diào)整值并寫入RTOS 系統(tǒng)節(jié)拍計(jì)數(shù)器變量中。
空閑任務(wù)的源代碼如下所示,其中宏portTASK_FUNCTION翻譯出來為:
void prvIdleTask(void * pvParameters)。
static portTASK_FUNCTION( prvIdleTask,pvParameters ){ /*防止編譯器警告 */ (void ) pvParameters; for(;; ) { /*檢查是否有任務(wù)刪除了自己,如果有的話,空閑任務(wù)負(fù)責(zé)刪除這個(gè)任務(wù)的TCB和堆??臻g */ prvCheckTasksWaitingTermination(); #if( configUSE_PREEMPTION == 0 ) {/*如果我們沒有使用搶占式調(diào)度,我們會(huì)強(qiáng)制任務(wù)切換,看看是否有其它任務(wù)變得有效.如果使用搶占式調(diào)度,是不需要這樣的,因?yàn)槿蝿?wù)變得有效后會(huì)搶占空閑任務(wù).*/taskYIELD(); } #endif/* configUSE_PREEMPTION */ #if( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) {/* 當(dāng)使用搶占式內(nèi)核,相同優(yōu)先級的任務(wù)使用時(shí)間片方式獲得CPU權(quán)限.如果有任務(wù)與空閑任務(wù)共享一個(gè)優(yōu)先級,那么空閑任務(wù)不必等到時(shí)間片耗盡再進(jìn)行任務(wù)切換.如果空閑優(yōu)先級下的就緒列表中有多個(gè)任務(wù),則執(zhí)行用戶任務(wù)*/if(listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) >( UBaseType_t ) 1 ){ taskYIELD();} } #endif/* ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 )) */ #if( configUSE_IDLE_HOOK == 1 ) {externvoid vApplicationIdleHook( void );/*調(diào)用用戶定義函數(shù).這樣允許設(shè)計(jì)者在不增加任務(wù)開銷的情況下實(shí)現(xiàn)后臺(tái)功能注意:這個(gè)函數(shù)中絕對不允許調(diào)用任務(wù)可能引起阻塞的函數(shù).*/vApplicationIdleHook(); } #endif/* configUSE_IDLE_HOOK */ #if( configUSE_TICKLESS_IDLE != 0 ) { TickType_txExpectedIdleTime;/*如果每次執(zhí)行空閑任務(wù)都掛起調(diào)度器,起然后再解除調(diào)度器,這很難讓人滿意,因此這里執(zhí)行兩次同樣的比較(xExpectedIdleTime和configEXPECTED_IDLE_TIME_BEFORE_SLEEP),第一次比較是測試一下是否達(dá)到預(yù)期的空閑時(shí)間,并不會(huì)掛起調(diào)度器.*/xExpectedIdleTime= prvGetExpectedIdleTime();if(xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP ){ vTaskSuspendAll(); { /*現(xiàn)在調(diào)度器被掛起,需要再次采樣空閑時(shí)間,這次空閑時(shí)間可以使用了*/ configASSERT(xNextTaskUnblockTime >= xTickCount ); xExpectedIdleTime= prvGetExpectedIdleTime(); if(xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP ) {portSUPPRESS_TICKS_AND_SLEEP(xExpectedIdleTime ); } } (void ) xTaskResumeAll();} } #endif/* configUSE_TICKLESS_IDLE */ }}static portTASK_FUNCTION( prvIdleTask,pvParameters ) { /*防止編譯器警告 */ (void ) pvParameters; for(;; ) { /*檢查是否有任務(wù)刪除了自己,如果有的話,空閑任務(wù)負(fù)責(zé)刪除這個(gè)任務(wù)的TCB和堆??臻g */ prvCheckTasksWaitingTermination(); #if( configUSE_PREEMPTION == 0 ) { /*如果我們沒有使用搶占式調(diào)度,我們會(huì)強(qiáng)制任務(wù)切換,看看是否有其它任務(wù)變得有效. 如果使用搶占式調(diào)度,是不需要這樣的,因?yàn)槿蝿?wù)變得有效后會(huì)搶占空閑任務(wù).*/ taskYIELD(); } #endif/* configUSE_PREEMPTION */ #if( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) { /* 當(dāng)使用搶占式內(nèi)核,相同優(yōu)先級的任務(wù)使用時(shí)間片方式獲得CPU權(quán)限.如果有任務(wù)與空閑 任務(wù)共享一個(gè)優(yōu)先級,那么空閑任務(wù)不必等到時(shí)間片耗盡再進(jìn)行任務(wù)切換. 如果空閑優(yōu)先級下的就緒列表中有多個(gè)任務(wù),則執(zhí)行用戶任務(wù)*/ if(listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) >( UBaseType_t ) 1 ) { taskYIELD(); } } #endif/* ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 )) */ #if( configUSE_IDLE_HOOK == 1 ) { externvoid vApplicationIdleHook( void ); /*調(diào)用用戶定義函數(shù).這樣允許設(shè)計(jì)者在不增加任務(wù)開銷的情況下實(shí)現(xiàn)后臺(tái)功能 注意:這個(gè)函數(shù)中絕對不允許調(diào)用任務(wù)可能引起阻塞的函數(shù).*/ vApplicationIdleHook(); } #endif/* configUSE_IDLE_HOOK */ #if( configUSE_TICKLESS_IDLE != 0 ) { TickType_txExpectedIdleTime; /*如果每次執(zhí)行空閑任務(wù)都掛起調(diào)度器,起然后再解除調(diào)度器,這很難讓人滿意,因此這里 執(zhí)行兩次同樣的比較(xExpectedIdleTime和configEXPECTED_IDLE_TIME_BEFORE_SLEEP), 第一次比較是測試一下是否達(dá)到預(yù)期的空閑時(shí)間,并不會(huì)掛起調(diào)度器.*/ xExpectedIdleTime= prvGetExpectedIdleTime(); if(xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP ) { vTaskSuspendAll(); { /*現(xiàn)在調(diào)度器被掛起,需要再次采樣空閑時(shí)間,這次空閑時(shí)間可以使用了*/ configASSERT(xNextTaskUnblockTime >= xTickCount ); xExpectedIdleTime= prvGetExpectedIdleTime(); if(xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP ) { portSUPPRESS_TICKS_AND_SLEEP(xExpectedIdleTime ); } } (void ) xTaskResumeAll(); } } #endif/* configUSE_TICKLESS_IDLE */ } }
以上就是FreeRTOS進(jìn)階之空閑任務(wù)示例完全解析的詳細(xì)內(nèi)容,更多關(guān)于FreeRTOS進(jìn)階空閑任務(wù)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
FreeRTOS實(shí)時(shí)操作系統(tǒng)空閑任務(wù)的阻塞延時(shí)實(shí)現(xiàn)
這篇文章主要為大家介紹了FreeRTOS實(shí)時(shí)操作系統(tǒng)空閑任務(wù)的阻塞延時(shí)實(shí)現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS實(shí)時(shí)操作系統(tǒng)隊(duì)列的API函數(shù)講解
這篇文章主要為大家介紹了FreeRTOS實(shí)時(shí)操作系統(tǒng)隊(duì)列的API函數(shù)講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS進(jìn)階之系統(tǒng)延時(shí)完全解析
這篇文章主要為大家介紹了FreeRTOS進(jìn)階之系統(tǒng)延時(shí)完全解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS任務(wù)控制API函數(shù)的功能分析
這篇文章主要為大家介紹了FreeRTOS任務(wù)控制API函數(shù)的功能分析,F(xiàn)reeRTOS任務(wù)控制API函數(shù)主要實(shí)現(xiàn)任務(wù)延時(shí)、任務(wù)掛起、解除任務(wù)掛起、任務(wù)優(yōu)先級獲取和設(shè)置等功能2022-04-04FreeRTOS進(jìn)階之空閑任務(wù)示例完全解析
這篇文章主要為大家介紹了FreeRTOS進(jìn)階之空閑任務(wù)示例的完全解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS實(shí)時(shí)操作系統(tǒng)隊(duì)列基礎(chǔ)
這篇文章主要為大家介紹了FreeRTOS實(shí)時(shí)操作系統(tǒng)隊(duì)列基礎(chǔ),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS實(shí)時(shí)操作系統(tǒng)結(jié)構(gòu)示例
這篇文章主要介紹了FreeRTOS實(shí)時(shí)操作系統(tǒng)結(jié)構(gòu)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS實(shí)時(shí)操作系統(tǒng)的任務(wù)概要講解
這篇文章主要為大家介紹了FreeRTOS實(shí)時(shí)操作系統(tǒng)的任務(wù)概要講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04