目錄
1、什麼是任務
我們平時在使用 51、 AVR、 STM32 單片機裸機(未使用系統)的時候一般都是在main 函數裏面用 while(1)做一個大循環來完成所有的處理, 即應用程序是一個無限的循環,循環中調用相應的函數完成所需的處理。
有時候我們也需要中斷中完成一些處理。相對於多任務系統而言,這個就是單任務系統,也稱作前後臺系統,中斷服務函數作爲前臺程序,大循環while(1)作爲後臺程序。
具體可參考本人另一篇關於前後臺系統與RTOS的介紹:https://blog.csdn.net/weixin_42108484/article/details/80557273
2、任務的特性
①簡單。
②沒有使用限制。
③支持搶佔
④支持優先級
⑤每個任務都擁有堆棧導致了 RAM 使用量增大。
⑥如果使用搶佔的話的必須仔細的考慮重入的問題。
3、任務的狀態
3.1 運行態
當一個任務正在運行時, 那麼就說這個任務處於運行態, 處於運行態的任務就是當前正在使用處理器的任務。 如果使用的是單核處理器的話那麼不管在任何時刻永遠都只有一個任務處於運行態。
3.2 就緒態
處於就緒態的任務是那些已經準備就緒(這些任務沒有被阻塞或者掛起), 可以運行的任務,但是處於就緒態的任務還沒有運行,因爲有一個同優先級或者更高優先級的任務正在運行!
3.3 阻塞態
如果一個任務當前正在等待某個外部事件的話就說它處於阻塞態, 比如說如果某個任務調用了函數 vTaskDelay()的話就會進入阻塞態, 直到延時週期完成。任務在等待隊列、信號量、事件組、通知或互斥信號量的時候也會進入阻塞態。任務進入阻塞態會有一個超時時間,當超過這個超時時間任務就會退出阻塞態,即使所等待的事件還沒有來臨!
3.4 掛起態
像阻塞態一樣,任務進入掛起態以後也不能被調度器調用進入運行態, 但是進入掛起態的任務沒有超時時間。任務進入和退出掛起態通過調用函數 vTaskSuspend()和 xTaskResume()。
總結:處於就緒態的最高優先級的任務纔會運行
4、任務的優先級
每個任務都可以分一個從 0~(configMAX_PRIORITIES-1)的優先級,configMAX_PRIORITIES 在文件 FreeRTOSConfig.h 中有定義,也就是優先級不能超過 32 級。優先級數字越低表示任務的優先級越低,0的優先級最低, configMAX_PRIORITIES-1 的優先級最高。空閒任務的優先級最低,爲 0。
處於就緒態的最高優先級的任務纔會運行,獲取處理器使用權 ,當宏 configUSE_TIME_SLICING 定義爲 1 的時候多個任務可以共用一個優先級,數量不限 就緒態的優先級相同的任務就會使用時間片輪轉調度器獲取運行時間。
5、任務的實現
void vATaskFunction(void *pvParameters)//任務函數本質也是函數,任務名爲void類型
{
for( ; ; )//執行過程
{
//編寫要實現的任務代碼
vTaskDelay(); //FreeRTOS的延時函數
}
//任務函數一般不允許跳出循環,如果一定要跳出循環的話在跳出循環以後一定要調用函數 vTaskDelete(NULL)刪除此任務
vTaskDelete(NULL);
}
6、任務控制塊
FreeRTOS 的每個任務都有一些屬性需要存儲, FreeRTOS 把這些屬性集合到一起用一個結構體來表示, 這個結構體叫做任務控制塊: TCB_t,在使用函數 xTaskCreate()創建任務的時候就會自動的給每個任務分配一個任務控制塊。 此結構體在文件 tasks.c 中有定義typedef struct tskTaskControlBlock {}tskTCB;
7、任務堆棧
FreeRTOS 之所以能正確的恢復一個任務的運行就是因爲有任務堆棧在保駕護航,任務調度器在進行任務切換的時候會將當前任務的現場(CPU 寄存器值等)保存在此任務的任務堆棧中,等到此任務下次運行的時候就會先用堆棧中保存的值來恢復現場,恢復現場以後任務就會接着從上次中斷的地方開始運行。
創建任務的時候需要給任務指定堆棧,如果使用的函數 xTaskCreate()創建任務(動態方法)的話那麼任務堆棧就會由函數 xTaskCreate()自動創建,如果使用函數 xTaskCreateStatic()創建任務(靜態方法)的話就需要程序員自行定義任務堆棧,然後堆棧首地址作爲函數的參數 puxStackBuffer 傳遞給函數:
TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode,
const char * const pcName,
const uint32_t ulStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
StackType_t * const puxStackBuffer, //任務堆棧,需要用戶定義
StaticTask_t * const pxTaskBuffer )
任務堆棧的數據類型爲 StackType_t, StackType_t 本質上是 uint32_t,在 portmacro.h 中有定義 :
#define portSTACK_TYPE uint32_t
#define portBASE_TYPE long
typedef portSTACK_TYPE StackType_t; //StackType_t 類型的變量爲 4 個字節
typedef long BaseType_t;
typedef unsigned long UBaseType_t;