FreeRTOS(3)---FreeRTOS 任務概述
FreeRTOS 任務概述
任務和協程(Co-routines)
應用程式可以使用任務也可以使用協程,或者兩者混合使用,但是任務和協程使用不同的API函式,因此在任務和協程之間不能使用同一個佇列或訊號量傳遞資料。
通常情況下,協程僅用在資源非常少的微處理器中,特別是RAM非常稀缺的情況下。目前協程很少被使用到,因此對於協程FreeRTOS作者既沒有把它刪除也沒有進一步開發。
所以本系列文章以後不會對協程過多描述,包括其API函式。
任務的特性
簡而言之:使用RTOS的實時應用程式可認為是一系列獨立任務的集合。每個任務在自己的環境中執行,不依賴於系統中的其它任務或者RTOS排程器。在任何時刻,只有一個任務得到執行,RTOS排程器決定執行哪個任務。排程器會不斷的啟動、停止每一個任務,巨集觀看上去就像整個應用程式都在執行。作為任務,不需要對排程器的活動有所瞭解,在任務切入切出時儲存上下文環境(暫存器值、堆疊內容)是排程器主要的職責。為了實現這點,每個任務都需要有自己的堆疊。當任務切出時,它的執行環境會被儲存在該任務的堆疊中,這樣當再次執行時,就能從堆疊中正確的恢復上次的執行環境。
任務概要
- 簡單
- 沒有使用限制
- 支援完全搶佔
- 支援優先順序
- 每個任務都有自己的堆疊,消耗RAM較多
- 如果使用搶佔,必須小心的考慮可重入問題
任務狀態
一個任務可為下面中的一個:
- 執行:如果一個任務正在執行,那麼說這個任務處於執行狀態。此時它佔用處理器。
- 就緒:就緒的任務已經具備執行的能力(不同於阻塞和掛起),但是因為有一個同優先順序或者更高優先順序的任務處於執行狀態而還沒有真正執行。
- 阻塞:如果任務當前正在等待某個時序或外部中斷,我們就說這個任務處於阻塞狀態。比如一個任務呼叫vTaskDelay()後會阻塞到延時週期到為止。任務也可能阻塞在佇列或訊號量事件上。進入阻塞狀態的任務通常有一個“超時”週期,當事件超時後解除阻塞。
- 掛起:處於掛起狀態的任務同樣對排程器無效。僅當明確的分別呼叫vTaskSuspend() 和xTaskResume() API函式後,任務才會進入或退出掛起狀態。不可以指定超時週期事件(不可以通過設定超時事件而退出掛起狀態)
任務優先順序
每個任務都要被指定一個優先順序,從0~configMAX_PRIORITIES,configMAX_PRIORITIES定義在FreeRTOSConfig.h中。
如果某架構硬體支援CLZ(或類似)指令(計算前導零的數目,Cortex-M3是支援該指令的,從ARMv6T2才支援這個指令),並且打算在移植層使用這個特性來優化任務排程機制,需要有一些步驟,首先將FreeRTOSConfig.h中configUSE_PORT_OPTIMISED_TASK_SELECTION設定為1,並且最大優先順序數目configMAX_PRIORITIES不能大於32。除此之外,configMAX_PRIORITIES可以設定為任意值,但是考慮到configMAX_PRIORITIES設定越大,RAM消耗也越大,一般設定為滿足使用的最小值。
低優先順序數值代表低優先順序。空閒任務(idle task)的優先順序為0(tskIDLE_PRIORITY)。
FreeRTOS排程器確保處於最高優先順序的就緒或執行態任務獲取處理器,換句話說,處於執行狀態的任務,只有其中的最高優先順序任務才會執行。
任何數量的任務可以共享同一個優先順序。如果巨集configUSE_TIME_SLICING未定義或著巨集configUSE_TIME_SLICING定義為1,處於就緒態的多個相同優先順序任務將會以時間片切換的方式共享處理器。
實現一個任務
一個任務具有以下結構:
void vATaskFunction( void *pvParameters )
{
for( ;; )
{
/*-- 應用程式程式碼放在這裡. --*/
}
/* 任務不可以從這個函式返回或退出。在較新的FreeRTOS移植包中,如果
試圖從一個任務中返回,將會呼叫configASSERT()(如果定義的話)。
如果一個任務確實要退出函式,那麼這個任務應呼叫vTaskDelete(NULL)
函式,以便處理一些清理工作。*/
vTaskDelete( NULL );
}
任務函式返回為void,引數只有一個void型別指標。所有的任務函式都應該是這樣。void型別指標可以向任務傳遞任意型別資訊。
任務函式決不應該返回,因此通常任務函式都是一個死迴圈。
任務由xTaskCreate()函式建立,由vTaskDelete()函式刪除。
空閒任務和空閒任務鉤子(idle task和Idle Task hook)
空閒任務
空閒任務是啟動RTOS排程器時由核心自動建立的任務,這樣可以確保至少有一個任務在執行。空閒任務具有最低任務優先順序,這樣如果有其它更高優先順序的任務進入就緒態就可以立刻讓出CPU。
刪除任務後,空閒任務用來釋放RTOS分配給被刪除任務的記憶體。因此,在應用中使用vTaskDelete()函式後確保空閒任務能獲得處理器時間就很重要了。除此之外,空閒任務沒有其它有效功能,所以可以被合理的剝奪處理器時間,並且它的優先順序也是最低的。
應用程式任務共享空閒任務優先順序(tskIDLE_PRIORITY)也是可能的。這種情況如何配置可以參考configIDLE_SHOULE_YIELD配置引數類獲取更多資訊。
空閒任務鉤子
空閒任務鉤子是一個函式,每一個空閒任務週期被呼叫一次。如果你想將任務程式功能執行在空閒優先順序上,可以有兩種選擇:
- 在一個空閒任務鉤子中實現這個功能:因為FreeRTOS必須至少有一個任務處於就緒或執行狀態,因此鉤子函式不可以呼叫可能引起空閒任務阻塞的API函式(比如vTaskDelay()或者帶有超時事件的佇列或訊號量函式)。
- 建立一個具有空閒優先順序的任務去實現這個功能:這是個更靈活的解決方案,但是會帶來更多RAM開銷。
建立一個空閒鉤子步驟如下:
- 在FreeRTOSConfig.h標頭檔案中設定configUSE_IDLE_HOOK為1;
- 定義一個函式,名字和引數原型如下所示:
void vApplicationIdleHook( void );
通常,使用這個空閒鉤子函式設定CPU進入低功耗模式。