FreeRTOS 操作系統學習
http://wiki.csie.ncku.edu.tw/embedded/FreeRTOS_Melot.pdf
1. 任務
1.1 FreeRTOS 中的任務
只要硬件和內存足夠,FreeRTOS 運行的任務數量不受限制,作爲一個實時操作系統,FreeRTOS 同時支持循環和非循環任務。在 RTOS 中,任務由一個簡單的C函數定義,參數爲 void* 類型,無返回值 (void)。
用些函數用於對任務的管理 : 任務創建(vTaskCreate()),任務銷燬((vTaskDelete()),優先級管理(uxTaskPriorityGet(), vTaskPrioritySet()) 延遲/恢復((vTaskDelay(), vTaskDelayUntil(),vTaskSuspend(), vTaskResume(),vTaskResumeFromISR())
爲了便於調試,用戶可以選擇很多操作,例如創建關鍵序列或對任務進行監控。、
1.1.1 任務的生命週期
本節更詳細地講解任務從創建至銷燬的整個發展過程。此時,我們假設只有一個內核,在指定的時間內只運行一個任務,每個人物只有“ 運行 (Running) ” “ 不運行 (Not Running) ”兩種狀態,由於我們假設是單核運行,且任意時刻有且只有一個任務在運行,那麼其他的未運行的任務一定是處於“不運行 (Not Running)”狀態. 圖1 給出了這種情形下生命週期的簡單示意圖
當一個任務從 非運行狀態 進入運行狀態,稱之爲“切入”,反之,成爲“切出”。
圖1 生命週期示意圖
由於存在一些原因導致任務無法運行,由於“未運行”狀態可以展開,如圖2所示,當任務處於延遲或等待事件觸發時,高優先級任務可以搶佔低優先級任務(調度在第2節中介紹)。當任務正在處理器資源準的過程中,這個狀態稱之爲“就緒(Ready)”態。當任務處於等待另一個任務完成(例如 等待信號量同步完成或互斥量)被延後執行,處於等待的狀態稱之爲“阻塞。(Blocked)”。總之,調用vTaskSuspend() 、 vTaskResume() 、 xTaskResumeFromISR() 這些函數,可以使任務進入或退出“掛起 (Suspend)”狀態。
強調任務能自行退出“運行(Running)”態是非常重要的(即進入延遲、掛起或事件等待),只有調度器能使任務重新“切入”運行狀態,當一個任務試圖重新進入“運行”態,它的狀態應爲“就緒(Ready)”,只有任務調度器能決定當前的時間片分配給哪個就緒任務。
圖2 任務的生命週期
1.2 創建 和 刪除任務
由一個簡單的C函數定義的任務,它帶有一個void *參數並且不返回任何內容(請參見 文本1)
void ATaskFunction( void *pvParameters );文本1: 一個典型的任務函數 |
一個任務在銷燬(Destroy)之前會一直運行。任務通常是一個死循環函數,或在到達最後一個大括號之前調用vTaskDestroy(NULL),由於死循環中的任何代碼都可能失敗並導致退出此循環,即使是重複性任務,在最後的大括號之前調用vTaskDelete()也更安全。文本3 是一個任務實現的典型例子。
可以使用vTaskCreate()創建任務(文本2)。 此函數參數列表如下:
- pvTaskCode: 一個指向任務實現函數的指針.
- pcName: 任務名. 這對FreeRTOS沒用,但僅用於調試目的
- usStackDepth: 以字爲單位的此任務的堆棧長度. 堆棧的實際大小取決於微控制器. 如果堆棧爲32位(4字節),而usStackDepth的值爲100,則將爲任務分配400字節(4乘以100).
- pvParameters: 任務的指針參數. 較好的做法是創建一個專用的結構體變量,實例化並賦值,然後將其指針交給任務。.
- uxPriority: 任務優先級, 賦值範圍從 0 到 ( MAX_PRIORITIES–1). 在第2節中將對此進行討論
- pxCreatedTask: 指向可以處理任務標識符的指針. 如果任務標識符將來不會被修改,則可以將其設爲NULL。
portBASE_TYPE xTaskCreate ( pdTASK_CODE pvTaskCode, const signed portCHAR * const pcName, unsigned portSHORT usStackDepth, void * pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask ); |
void ATaskFunction( void *pvParameters ) { /* 可以按照常規函數聲明變量的方法對變量進行聲明。. 每個使用此函數創建的任務 ,會重新創建一個iVariableExample 變量. 如果變量是靜態變量,所有此任務的實例將共享變量的存儲,一個實例修改將導致所有實例的這個變量值都發生改變 */
int iVariableExample = 0;
/* 死循環中爲任務的具體實現. */ for( ;; ) { /* 任務功能實現代碼. */ }
/* 應該在不打破上述循環的前提下執行任務,然後才能刪除該任務。 傳遞給vTaskDelete()函數的NULL參數表示要刪除的任務是當前正在調用的任務。 */
vTaskDelete( NULL ); } |
當任務創建後可以使用xTaskDestroy()例程銷燬任務。 參數爲pxCreatedTask,例程見文本4中給出,示例參考文本3
void vTaskDelete( xTaskHandle pxTask ); |
刪除任務後,空閒任務將釋放所有釋放所有分配給該任務的內存資源。注意,所有動態分配的內存必須手動釋放。