FreeRTOS-01-任務相關函數

3 任務相關API函數

任務相關函數如下:

任務創建和刪除API函數

任務創建和刪除實驗(動態方法)

任務創建和刪除實驗(靜態方法)

任務掛起和恢復API函數

任務掛起和恢復實驗

3.1 任務創建API函數(動態方法)

函數原型:

#include "FreeRTOS.h"
#include "task.h"

BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
    const char * const pcName,
    const configSTACK_DEPTH_TYPE usStackDepth,
    void * const pvParameters,
    UBaseType_t uxPriority,
    TaskHandle_t * const pxCreatedTask );

函數描述:使用動態方法創建一個任務,任務控制塊和任務堆棧在函數內創建。最新創建的任務初始化為就緒態,如果當前沒有更高優先順序的任務運行,則立刻變為運行態。

函數參數說明:

參數名 說明
pxTaskCode 任務函數,通常為一個無限循環。
pcName 任務名字,名稱長度有限制,在FreeRTOSConfig.h中有定義configMAX_TASK_NAME_LEN。
usStackDepth 任務堆棧大小,實際申請到的堆棧是usStackDepth的4倍。configMINIMAL_STACK_SIZE定義的是空閑任務堆棧大小。
pvParameters 傳遞給任務函數的參數
uxPriority 任務優先順序,範圍0~configMAX_PRIORITIES-1。
pxCreatedTask 任務句柄,任務創建成功以後會返回此任務的任務句柄, 這個句柄其實就是 任務的任務堆棧。 此參數就用來保存這個任務句柄。其他 API 函數可能會使 用到這個句柄。如果任務句柄不需要使用,可以被設置為NULL。

返回值:

pdPASS:任務創建成功。
errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY: 任務創建失敗,因為堆記憶體不足!

3.2 任務創建函數(靜態方法)

函數原型:

#include "FreeRTOS.h"
#include "task.h"

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 );

函數描述:使用靜態方法創建一個任務。任務所需要的RAM需要用戶來提供。

函數參數說明:

參數名 說明
pxTaskCode 任務函數,通常為一個無限循環。
pcName 任務名字,名稱長度有限制,在FreeRTOSConfig.h中有定義configMAX_TASK_NAME_LEN。
usStackDepth 任務堆棧大小,靜態創建任務的堆棧由用戶給出,通常為一個數組,這個參數就是數組的大小。
pvParameters 傳遞給任務函數的參數
uxPriority 任務優先順序,範圍0~configMAX_PRIORITIES-1。
puxStackBuffer 任務堆棧,一般為數組,數組類型為StackType_t類型。
pxTaskBuffer 任務控制塊

返回值:

NULL:任務創建失敗,puxStackBuffer或pxTaskBuffer為空。
其他值: 任務創建成功,返回任務的任務句柄。

3.3 任務刪除API函數

函數原型:

void vTaskDelete( TaskHandle_t xTaskToDelete ) PRIVILEGED_FUNCTION;

函數描述:刪除任務,刪除之後的任務不再存在,也不能再使用此函數的句柄。如果任務使用的是xTaskCreate()創建的,此任務被刪除後此任務之前申請的堆棧和控制塊記憶體會在任務中被釋放掉。

函數參數:xTaskToDelete要刪除的任務的任務句柄。

返回值:

3.4 任務創建和刪除實驗(動態方法)

創建兩個任務,這兩個任務的功能如下:

task00:此任務每個1000ms列印一次字元串,調用5次之後調用vTaskDelete()函數刪除task01。

task01:此任務為普通任務,間隔500ms列印一次字元串,和task00同樣的任務優先順序。

task00任務創建程式碼:

configSTACK_DEPTH_TYPE Task00_STACK_SIZE = 5;
UBaseType_t  Task00_Priority = 1;
TaskHandle_t Task00_xHandle;

void vTask00_Code(void *para)
{
    static unsigned int cnt = 0;
    for (;;)
    {
        PRINT(" task00 cnt %u...", cnt);
        if (cnt == 4)
            vTaskDelete(Task01_xHandle);
        cnt++;
        vTaskDelay(1000);
    }
}

xTaskCreate(vTask00_Code, "task00", Task00_STACK_SIZE, NULL, Task00_Priority, &Task00_xHandle);

task01任務創建程式碼:

configSTACK_DEPTH_TYPE Task01_STACK_SIZE = 5;
UBaseType_t  Task01_Priority = 1;
TaskHandle_t Task01_xHandle;

void vTask01_Code(void *para)
{
    static unsigned int cnt = 0;
    for (;;)
    {
        PRINT(" task01 cnt %u...", cnt);
        cnt++;
        vTaskDelay(500);
    }
}

xTaskCreate(vTask01_Code, "task01", Task01_STACK_SIZE, NULL, Task01_Priority, &Task01_xHandle);

編譯,運行,測試結果符合預期,task00運行5秒之後刪除了task01:

image-20210717164936914

3.5 任務創建和刪除實驗(靜態方法)

使用靜態方式創建一個任務,該任務每個1秒列印一個字元串:

#define STATIC_STACK_SIZE 5
UBaseType_t  Static_Task_Priority = 1;
StaticTask_t Static_xTaskBuffer;
StackType_t  Static_xStack[STATIC_STACK_SIZE];
TaskHandle_t Static_xhandle = NULL;  //任務句柄

void static_task_code(void *para)
{
    static unsigned int cnt = 0;
    for (;;)
    {
        PRINT(" static task cnt %u...", cnt);
        cnt++;
        vTaskDelay(1000);
    }
}

Static_xhandle = xTaskCreateStatic (static_task_code,
        "static task",
        STATIC_STACK_SIZE,
        NULL,
        Static_Task_Priority,
        Static_xStack,
        &Static_xTaskBuffer);

3.6 vTaskDelay()

函數原型:

#include "FreeRTOS.h"
#include "task.h"

void vTaskDelay( const TickType_t xTicksToDelay );

函數描述:調用該函數的任務將進入阻塞態,中斷一段固定的時鐘周期。

函數參數:xTicksToDelay表示調用函數的任務的阻塞態保持時間。延時達到之後將進入就緒態。例如:當時鐘計數到10000時,函數調用了vTaskDelay(100),然後任務進入阻塞態,並且保持阻塞態直到時鐘計數到10100。

宏pdMS_TO_TICKS()可以被使用來延時毫秒。例如:調用vTaskDelay( pdMS_TO_TICKS(100) ),任務將進入阻塞態100毫秒。

3.7 任務掛起函數

函數原型:

#include 「FreeRTOS.h」
#include 「task.h」
void vTaskSuspend( TaskHandle_t pxTaskToSuspend );

函數描述:將一個任務設置為掛起態。一個任務在掛起態將不會被調度轉為運行態。將任務從掛起態移出來的唯一方式是調用vTaskResume()函數。

函數參數:pxTaskToSuspen表示需要掛起的任務句柄。一個任務可以通過設置參數為NULL來掛起自己。

3.8 調度器掛起函數

函數原型:

#include 「FreeRTOS.h」
#include 「task.h」
void vTaskSuspendAll( void );

函數描述:掛起調度器,但保留中斷使能。當調度器被掛起時,如果一個中斷需要請求上下文切換,中斷請求將保持等待直到調度器從掛起中恢復。調度器從掛起態恢復需要調用xTaskResumeAll()函數。vTaskSuspendAll()支援嵌套使用,當要恢復調度器運行時,vTaskSuspendAll()函數被調用幾次就需要調用xTaskResumeAll()函數幾次。

3.9 任務恢複函數

函數原型:

#include 「FreeRTOS.h」
#include 「task.h」
void vTaskResume( TaskHandle_t pxTaskToResume );

函數描述:將一個任務從掛起態轉換為就緒態。任務必須是之前使用vTaskSuspend()函數進入的掛起態。

函數參數:pxTaskToResume需要恢復的任務句柄。

3.10 調度器恢複函數

函數原型:

#include 「FreeRTOS.h」
#include 「task.h」
BaseType_t xTaskResumeAll( void );

函數描述:恢復調度器為調度狀態。調度器必須是之前使用vTaskSuspendAll()函數進入的掛起狀態。

返回值:pdTRUE:調度器轉換為活躍狀態。

pdFALSE:調度器嵌套調用了vTaskSuspendAll(),調度器依然保持掛起狀態。

3.11 任務掛起和恢復實驗

創建兩個任務,任務二創建之後就掛起,任務三創建之後延時5秒之後,恢復任務二的運行。

程式碼大致實現如下:

/* test suppend task */
configSTACK_DEPTH_TYPE Task02_STACK_SIZE = 5;
UBaseType_t  Task02_Priority = 2;
TaskHandle_t Task02_xHandle;

configSTACK_DEPTH_TYPE Task03_STACK_SIZE = 5;
UBaseType_t  Task03_Priority = 1;
TaskHandle_t Task03_xHandle;

void vTask02_Code(void *para)
{
    static unsigned int cnt = 0;
    for (;;)
    {
        PRINT(" task02 cnt %u...", cnt);
        cnt++;
        vTaskDelay(1000);
    }
}

void vTask03_Code(void *para)
{
    static unsigned int cnt = 0;
    for (;;)
    {
        PRINT(" task03 cnt %u...", cnt);
        cnt++;
        vTaskDelay(1000);
        if (cnt == 5)
            vTaskResume(Task02_xHandle);
    }
}

void create_task_test_suppend(void)
{
    if (xTaskCreate(vTask02_Code, "suppend task02", Task02_STACK_SIZE, 
        NULL, Task02_Priority, &Task02_xHandle) != pdPASS)
        PRINT("creat task failed!\n");
    if (xTaskCreate(vTask03_Code, "suppend task03", Task03_STACK_SIZE, 
        NULL, Task03_Priority, &Task03_xHandle) != pdPASS)
        PRINT("creat task failed!\n");
    vTaskSuspend(Task02_xHandle);
}

編譯運行,得到的結果如下:

$ ./build/freertos-simulator 
 task03 cnt 0...
 task03 cnt 1...
 task03 cnt 2...
 task03 cnt 3...
 task03 cnt 4...
 task02 cnt 0...
 task03 cnt 5...
 task02 cnt 1...
 task03 cnt 6...
 task02 cnt 2...
 task03 cnt 7...
 task02 cnt 3...
 task03 cnt 8...

3.11 調度器掛起和恢復實驗

創建兩個任務,任務四創建之後運行,任務五創建之後延時5秒之後,掛起調度器,然後恢復調度器。

程式碼大致實現如下:

configSTACK_DEPTH_TYPE Task04_STACK_SIZE = 5;
UBaseType_t  Task04_Priority = 2;
TaskHandle_t Task04_xHandle;

configSTACK_DEPTH_TYPE Task05_STACK_SIZE = 5;
UBaseType_t  Task05_Priority = 1;
TaskHandle_t Task05_xHandle;

void vTask04_Code(void *para)
{
    static unsigned int cnt = 0;
    for (;;)
    {
        PRINT(" task04 cnt %u...", cnt);
        cnt++;
        vTaskDelay(1000);
    }
}

void vTask05_Code(void *para)
{
    static unsigned int cnt = 0;
    for (;;)
    {
        PRINT(" task05 cnt %u...", cnt);
        cnt++;
        vTaskDelay(1000);
        if (cnt == 5) {
            vTaskSuspendAll();
            PRINT("... ...\n");
            xTaskResumeAll();
        }
    }
}

void create_task_test_suppend(void)
{
    if (xTaskCreate(vTask04_Code, "suppend task04", Task04_STACK_SIZE, 
        NULL, Task04_Priority, &Task04_xHandle) != pdPASS)
        PRINT("creat task failed!\n");
    if (xTaskCreate(vTask05_Code, "suppend task05", Task05_STACK_SIZE, 
        NULL, Task05_Priority, &Task05_xHandle) != pdPASS)
        PRINT("creat task failed!\n");
}

編譯運行:

 task04 cnt 0...
 task05 cnt 0...
 task04 cnt 1...
 task05 cnt 1...
 task04 cnt 2...
 task05 cnt 2...
 task04 cnt 3...
 task05 cnt 3...
 task04 cnt 4...
 task05 cnt 4...
 task04 cnt 5...
... ...

 task05 cnt 5...
 task04 cnt 6...
 task05 cnt 6...
 task04 cnt 7...
 task05 cnt 7...
Tags: