任務基礎知識
FreeRTOS任務特性
- 簡單
- 沒有使用限制
- 支持搶佔
- 支持優先級
- 每個任務都擁有堆棧導致RAM內存使用量加大
- 使用搶佔必須考慮重入的問題(可重入函數主要用於多任務環境中,一個可重入的函數簡單來說就是可以被中斷的函數,也就是說,可以在這個函數執行的任何時刻中斷它,轉入OS調度下去執行另外一段代碼,而返回控制時不會出現什麼錯誤;而不可重入的函數由於使用了一些系統資源,比如全局變量區,中斷向量表等,所以它如果被中斷的話,可能會出現問題,這類函數是不能運行在多任務環境下的)
FreeRTOS任務狀態
- 運行態
- 就緒態
- 阻塞態
- 掛起態
FreeRTOS任務優先級
在FreeRTOSconfig.h中定義了可使用的最大優先級
#define configMAX_PRIORITIES (32) //可使用的最大優先級
數字越大,優先級越高
FreeRTOS任務實現
任務實現的具體功能代碼
void vATaskFunction(void *pvParameters)
{
--任務應用程序--
for( ; ; )
{
vTaskDelay();
vTaskDelete(NULL);
}
}
FreeRTOS任務控制塊
- 描述任務屬性的數據結構成爲任務控制塊,爲TCB_t
- FreeRTOS 的每個任務都有一些屬性需要存儲,FreeRTOS 把這些屬性集合到一起用一個結構體來表示,這個結構體叫做任務控制塊
FreeRTOS任務堆棧
- FreeRTOS 之所以能正確的恢復一個任務的運行就是因爲有任務堆棧在保駕護航,任務調度器在進行任務切換的時候會將當前任務的現場(CPU
寄存器值等)保存在此任務的任務堆棧中,等到此任務下次運行的時候就會先用堆棧中保存的值來恢復現場,恢復現場以後任務就會接着從上次中斷的地方開始運行,這裏看不懂沒關係 - 還有一個地方特別要注意的就是分配任務的時候,你給的堆棧內存大小一定要大於任務所佔內存大小,不然會無法運行
- 在程序中任務的實際堆棧大小就應該是我們所定義的 4 倍
基本瞭解了我們任務的基礎知識後就開始創建一個任務來驗證FreeRTOS是否移植成功
任務創建與刪除
任務創建與刪除有動態方法與靜態方法之分,他們之間的區別是:
- 動態方法:任務控制塊與內存堆棧所使用的內存由FreeRTOS自動分配
- 靜態方法:需要自己手動去分配
在這裏我主要記錄動態方法
相關API函數
xTaskCreate()函數(動態方法創建):
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
const char * const pcName,
const uint16_t usStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask )
參數:
- pxTaskCode: 任務函數
- pcName: 任務名字,一般用於追蹤和調試,任務名字長度不能超過configMAX_TASK_NAME_LEN
- usStackDepth: 任務堆棧大小,注意實際申請到的堆棧是 usStackDepth 的 4 倍。其中空閒任務的任務堆棧大小爲
configMINIMAL_STACK_SIZE - pvParameters: 傳遞給任務函數的參數
- uxPriotiry: 任務優先級,範圍 0~ configMAX_PRIORITIES-1
- pxCreatedTask: 任務句柄,任務創建成功以後會返回此任務的任務句柄,這個句柄其實就是任務的任務堆棧。此參數就用來保存這個任務句柄。其他 API函數可能會使用到這個句柄
vTaskDelete( TaskHandle_t xTaskToDelete )函數:
xTaskToDelete //要刪除的任務句柄,刪除自己就是NULL
具體實例:
任務一是第一個LED燈500ms閃爍一次,任務二是1s內第二個LED燈亮200ms,滅800ms。任務一運行5次之後刪除任務二。
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"
//開始任務的參數
#define START_TASK_SIZE 120
#define START_TASK_PRIO 3
TaskHandle_t start_handle;
void start_task( void * pvParameters );
//任務一的參數
#define TASK1_SIZE 120
#define TASK1_PRIO 4
TaskHandle_t task1_handle;
void task1( void * pvParameters );
//任務二的參數
#define TASK2_SIZE 120
#define TASK2_PRIO 5
TaskHandle_t task2_handle;
void task2( void * pvParameters );
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
delay_init();
uart_init(115200);
LED_Init();
xTaskCreate((TaskFunction_t ) start_task,
(char * ) "start_task",
(uint16_t ) START_TASK_SIZE,
(void * ) NULL,
(UBaseType_t ) START_TASK_PRIO,
(TaskHandle_t * ) &start_handle );
//開啓任務調度
vTaskStartScheduler();
}
void start_task( void * pvParameters )
{
xTaskCreate((TaskFunction_t ) task1,
(char * ) "task1",
(uint16_t ) TASK1_SIZE,
(void * ) NULL,
(UBaseType_t ) TASK1_PRIO,
(TaskHandle_t * ) &task1_handle );
xTaskCreate((TaskFunction_t ) task2,
(char * ) "task2",
(uint16_t ) TASK2_SIZE,
(void * ) NULL,
(UBaseType_t ) TASK2_PRIO,
(TaskHandle_t * ) &task2_handle );
vTaskDelete(start_handle);
}
void task1( void * pvParameters )
{
unsigned char i = 0;
while(1)
{
i++;
if(i == 5)
{
vTaskDelete(task2_handle);
printf("task1 is be delete!");
}
LED0 = ~LED0;
vTaskDelay(500);
printf("task1 is runing\r\n");
}
}
void task2( void * pvParameters )
{
while(1)
{
LED1 = 0;
vTaskDelay(200);
LED1 = 1;
vTaskDelay(800);
printf("task2 is runing\r\n");
}
}