說明:
本文僅作為學習FreeRTOS的記錄文件,作為初學者肯定很多理解不對甚至錯誤的地方,望網友指正。
FreeRTOS是一個RTOS(實時作業系統)系統,支援搶佔式、合作式和時間片排程。適用於微處理器或小型微處理器的實時應用。
本文件使用的FreeRTOS版本:FreeRTOS Kernel V10.4.1
參考文件:《FreeRTOS_Reference_Manual_V10.0.0.pdf》《FreeRTOS_Real_Time_Kernel-A_Hands-On_Tutorial_Guide.pdf》《STM32F4 FreeRTOS開發手冊_V1.1.pdf》
參考視訊:正點原子FreeRTOS手把手教學-基於STM32_嗶哩嗶哩_bilibili
5 其它任務相關函式
介紹一些任務輔助函式,方便查詢任務的相關資訊。
5.1 設定任務優先順序
函式原型:
#include “FreeRTOS.h”
#include “task.h”
void vTaskPrioritySet( TaskHandle_t pxTask, UBaseType_t uxNewPriority );
函式描述:設定任務優先順序。
函式引數:pxTask設定任務優先順序的任務控制程式碼。如果任務設定自己的優先順序,這個引數可以填為NULL。
返回值:重新設定的任務優先順序值。0表示最低優先順序,configMAX_PRIORITIES – 1表示最高優先順序。
5.2 獲取任務優先順序
函式原型:
#include “FreeRTOS.h”
#include “task.h”
UBaseType_t uxTaskPriorityGet( TaskHandle_t pxTask );
函式描述:獲取任務優先順序。
函式引數:pxTask查詢任務優先順序的任務控制程式碼。如果任務查詢自己的優先順序,這個引數可以填為NULL。
返回值:查詢任務的優先順序值。
測試程式碼:
configSTACK_DEPTH_TYPE Task_STACK_SIZE = 5;
UBaseType_t Task_Priority = 12;
void task_code(void *para)
{
static unsigned int cnt = 0;
for (;;)
{
PRINT(" task cnt %u...", cnt);
cnt++;
vTaskDelay(1000);
}
}
void task_func(void)
{
TaskHandle_t xhandle;
UBaseType_t uxCreatedPriorty, uxOurPriorty;
if (xTaskCreate(task_code, "demo task",
Task_STACK_SIZE, NULL, Task_Priority,
&xhandle) != pdPASS)
{
PRINT("creat task failed!\n");
} else
{
uxCreatedPriorty = uxTaskPriorityGet(xhandle);
uxOurPriorty = uxTaskPriorityGet(NULL);
PRINT("created task priority: %d", uxCreatedPriorty);
PRINT("our task priority: %d", uxOurPriorty);
vTaskPrioritySet(xhandle, 3);
uxCreatedPriorty = uxTaskPriorityGet(xhandle);
uxOurPriorty = uxTaskPriorityGet(NULL);
PRINT("after changed, created task priority: %d", uxCreatedPriorty);
PRINT("after changed, our task priority: %d", uxOurPriorty);
}
}
預設建立任務優先順序為12,然後更改任務優先順序為3。
編譯,執行,結果如下:
$ ./build/freertos-simulator
created task priority: 12
our task priority: 12
after changed, created task priority: 3
after changed, our task priority: 3
task cnt 0...
task cnt 1...
... ...
5.3 獲取系統中所有任務的狀態
函式原型:
#include “FreeRTOS.h”
#include “task.h”
UBaseType_t uxTaskGetSystemState(
TaskStatus_t * const pxTaskStatusArray,
const UBaseType_t uxArraySize,
unsigned long * const pulTotalRunTime );
函式描述:獲取系統中所有任務的任務狀態。TaskStatus_t是一個儲存任務狀態資訊的結構體,結構體中包括任務控制程式碼、任務名稱、堆疊、優先順序等資訊。要使用這個函式需要開啟configUSE_TRACE_FACILITY巨集。
函式引數:pxTaskStatusArray:指向TaskStatus_t資料結構陣列的首地址,每個任務至少包含一個TaskStatus_t結構體。任務的結構體數目可以使用uxTaskGetNumberOfTasks函式獲得。
uxArraySize:儲存任務狀態陣列的陣列的大小。
pulTotalRunTime:如果configGENERATE_RUN_TIME_STATS配置為1,這個引數儲存系統總的執行時間。
返回值:統計到的任務狀態的數目,也就是pxTaskStatusArray陣列成員個數,如果uxArraySize引數太小,返回值可能為0。
TaskStatus_t結構體定義如下:
typedef struct xTASK_STATUS
{
TaskHandle_t xHandle; //任務控制程式碼
const char * pcTaskName; //任務名字
UBaseType_t xTaskNumber; //任務編號
eTaskState eCurrentState; //任務當前狀態
UBaseType_t uxCurrentPriority; //任務當前優先順序
UBaseType_t uxBasePriority; //任務基礎優先順序
uint32_t ulRunTimeCounter; //任務執行總時間
StackType_t * pxStackBase; //堆疊基地址
configSTACK_DEPTH_TYPE usStackHighWaterMark;//從任務建立以來任務堆疊剩餘的最小大小,這個值太小說明堆疊有溢位的風險。
} TaskStatus_t;
5.4 獲取系統中單個任務的狀態
函式原型:
#include “FreeRTOS.h”
#include “task.h”
void vTaskGetTaskInfo( TaskHandle_t xTask,
TaskStatus_t *pxTaskStatus,
BaseType_t xGetFreeStackSpace,
eTaskState eState );
函式描述:獲取單個任務的任務狀態。要使用這個函式需要開啟configUSE_TRACE_FACILITY巨集。
函式引數:xTask:任務控制程式碼;pxTaskStatus:存放獲取的任務狀態資訊;
xGetFreeStackSpace:TaskStatus_t結構中有個成員usStackHighWaterMark存放了任務建立以來任務堆疊剩餘的最小大小,但是計算這個值需要一些時間,所以可以通過設定xGetFreeStackSpace值為pdFALSE來跳過這個步驟,當設定為pdTRUE才會檢查堆疊剩餘的最小大小。
eState:TaskStatus_t結構中有個成員eCurrentState存放任務的當前執行狀態,但是獲取任務狀態需要花費不少時間,可通過引數eState直接將任務狀態賦值給eCurrentState。也可以將eStates設定為eInvalid,那麼任務狀態資訊有函式vTaskGetInfo()函式獲取。
測試程式碼:
configSTACK_DEPTH_TYPE Task_STACK_SIZE = 20;
UBaseType_t Task_Priority = 12;
void task_code(void *para)
{
static unsigned int cnt = 0;
for (;;)
{
PRINT(" task cnt %u...", cnt);
cnt++;
vTaskDelay(1000);
}
}
void task_func(void)
{
TaskHandle_t xhandle;
TaskStatus_t xTaskDetails;
char *state_str[] = {"running", "ready", "blocked", "suspended", "deleted", "invalid"};
if (xTaskCreate(task_code, "demo task",
Task_STACK_SIZE, NULL, Task_Priority,
&xhandle) != pdPASS)
{
PRINT("creat task failed!\n");
} else
{
vTaskPrioritySet(xhandle, 3);
vTaskGetTaskInfo(xhandle, &xTaskDetails, pdTRUE, eInvalid);
PRINT("Task name : %s", xTaskDetails.pcTaskName);
PRINT("Task number : %d", xTaskDetails.xTaskNumber);
PRINT("Task CurrentState : %s", state_str[xTaskDetails.eCurrentState]);
PRINT("Task CurrentPriority: %d", xTaskDetails.uxCurrentPriority);
PRINT("Task BasePriority : %d", xTaskDetails.uxBasePriority);
PRINT("Task RunTimeCounter : %d", xTaskDetails.ulRunTimeCounter);
PRINT("Task StackBase : %p", xTaskDetails.pxStackBase);
PRINT("Task StackHighWaterMark: %u", xTaskDetails.usStackHighWaterMark);
}
}
編譯,執行,結果如下:
$ ./build/freertos-simulator
Task name : demo task
Task number : 1
Task CurrentState : running
Task CurrentPriority: 3
Task BasePriority : 3
Task RunTimeCounter : 0
Task StackBase : 0x2060010
Task StackHighWaterMark: 15
task cnt 0...
task cnt 1...
5.5 獲取排程器執行狀態
函式原型:
#include “FreeRTOS.h”
#include “task.h”
BaseType_t xTaskGetSchedulerState( void );
函式描述:獲取排程器當前的執行狀態。使用這個函式需要將巨集INCLUDE_xTaskGetSchedulerState置為1。
函式引數:無
返回值:INCLUDE_xTaskGetSchedulerState:排程器未啟動。排程器啟動使用vTaskStartSchedule()函式完成,所以xTaskGetSchedulerState()函式在vTaskStartSchedule()函式之前呼叫會返回這個值。
taskSCHEDULER_RUNNING:排程器正在執行。
taskSCHEDULER_SUSPENDED:排程器被掛起,因為呼叫了vTaskSuspendAll()函式。
5.6 獲取任務執行狀態
函式原型:
#include “FreeRTOS.h”
#include “task.h”
eTaskState eTaskGetState( TaskHandle_t pxTask );
函式描述:獲取任務的執行狀態。使用此函式需要將INCLUDE_eTaskGetState巨集置為1。
函式引數:xTask:要獲取的任務控制程式碼
返回值:任務的執行狀態,eTaskState是一個列舉變數。
/* Task states returned by eTaskGetState. */
typedef enum
{
eRunning = 0, /* A task is querying the state of itself, so must be running. */
eReady, /* The task being queried is in a read or pending ready list. */
eBlocked, /* The task being queried is in the Blocked state. */
eSuspended, /* The task being queried is in the Suspended state,
or is in the Blocked state with an infinite time out. */
eDeleted, /* The task being queried has been deleted, but its TCB has not yet been freed. */
eInvalid /* Used as an 'invalid state' value. */
} eTaskState;
5.7 設定任務的tag(標籤)值
函式原型:
#include “FreeRTOS.h”
#include “task.h”
void vTaskSetApplicationTaskTag( TaskHandle_t xTask, TaskHookFunction_t pxTagValue );
函式描述:設定任務的標籤值,標籤值的具體函式和用法由使用者決定。FreeRTOS核心不會使用這個標籤值。如果要使用這個函式必須將configUSE_APPLICATION_TASK_TAG巨集置為1。
函式引數:xTask:任務控制程式碼,如果設為NULL表示設定自身任務的標籤值。
pxTagValue:要設定的標籤值,這是一個TaskHookFunction_t型別的函式指標,也可以設定為其它值。
返回值:無
5.8 獲取任務的tag(標籤)值
函式原型:
#include “FreeRTOS.h”
#include “task.h”
TaskHookFunction_t xTaskGetApplicationTaskTag( TaskHandle_t xTask );
函式描述:獲取任務的tag(標籤)值,任務控制塊中有個成員變數pxTaskTag來儲存任務的標籤值。標籤的功能由使用者決定。核心一般不會使用這個標籤值。使用這個函式需要將configUSE_APPLICATION_TASK_TAG 巨集置為1。
函式引數:xTask:任務控制程式碼
返回值:任務的標籤值。
5.9 獲取當前任務控制程式碼
函式原型:
#include “FreeRTOS.h”
#include “task.h”
TaskHandle_t xTaskGetCurrentTaskHandle( void );
函式描述:獲取當前任務(執行態)的任務的控制程式碼。其實獲取到的就是任務控制塊。使用這個函式需要將INCLUDE_xTaskGetCurrentTaskHandle巨集置為1。
函式引數:無
返回值:當前任務的任務控制程式碼。
5.10 獲取某個任務控制程式碼
函式原型:
#include “FreeRTOS.h”
#include “task.h”
TaskHandle_t xTaskGetHandle( const char *pcNameToQuery );
函式描述:根據任務名回去任務控制程式碼。使用xTaskCreate()或者xTaskCreateStatic()函式建立任務時,有一個pcName引數,這個引數就是存放的任務名。xTaskGetHandle就是通過這個任務名來查詢任務控制程式碼的。使用這個函式必須將INCLUDE_xTaskGetHandle巨集置為1。
函式引數:任務名,C語言字串。
返回值:沒有找到pcNameToQuery對應的任務返回NULL;找到了返回對應的任務控制程式碼。
5.11 獲取空閒任務的控制程式碼
函式原型:
#include “FreeRTOS.h”
#include “task.h”
TaskHandle_t xTaskGetIdleTaskHandle( void );
函式描述:獲取空閒任務的任務控制程式碼。使用這個函式需要將INCLUDE_xTaskGetIdleTaskHandle巨集置為1。
函式引數:無
返回值:空閒函式的任務控制程式碼。
5.12 檢查任務堆疊剩餘大小
函式原型:
#include “FreeRTOS.h”
#include “task.h”
UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask );
函式描述:每個任務都有自己的堆疊。當任務建立的時候指定了堆疊的大小。這個函式用於檢查任務從建立到現在的歷史剩餘最小值。值越小說明堆疊溢位的可能性越大。FreeRTOS把這個歷史最小值叫做”高水位線“。使用此函式需要將INCLUDE_uxTaskGetStackHighWaterMark巨集設定為1。
函式引數:xTask:要查詢的任務控制程式碼。引數為NULL表示查詢任務自身。
返回值:任務堆疊的”高水位線“值,也就是歷史剩餘最小值。
5.13 獲取任務名
函式原型:
#include “FreeRTOS.h”
#include “task.h”
char * pcTaskGetName( TaskHandle_t xTaskToQuery );
函式描述:獲取任務的任務名。
函式引數:xTask:要查詢的任務控制程式碼,此引數為NULL表示查詢自身任務。
返回值:返回任務所對應的任務名。
5.14 查詢任務排程器計數器值
函式原型:
#include “FreeRTOS.h”
#include “task.h”
TickType_t xTaskGetTickCount( void );
函式描述:查詢任務排程器從啟動到現在時間計數器xTickCount的值。
函式引數:無
返回值:時間計數器xTickCount的值
xTickCount:是系統的時鐘節拍值,並不是真實的時間值。每個滴答定時器中斷xTickCount就會加1,1秒滴答定時器中斷多少次取決於巨集configTICK_RATE_HZ。理論上xTickCount存在溢位的問題,但是這個溢位對核心沒有影響,如果使用者有使用的話就要考慮溢位。什麼時候溢位取決於巨集configUSE_16_BIT_TICKS,此巨集為1的時候xTickCount為16位的變數,此巨集為0的時候xTickCount為32位的變數。
5.15 獲取系統任務數
函式原型:
#include “FreeRTOS.h”
#include “task.h”
UBaseType_t uxTaskGetNumberOfTasks( void );
函式描述:獲取系統當前任務數
函式引數:無
返回值:當前系統中的任務數量。包括掛起態、阻塞態、就緒態、空閒任務、執行態任務。
5.16 獲取任務列表
函式原型:
#include “FreeRTOS.h”
#include “task.h”
void vTaskList( char *pcWriteBuffer );
函式描述:獲取任務的詳細資訊。函式會建立一個表格來描述每個任務的詳細資訊。使用這個函式必須將configUSE_TRACE_FACILITY和configUSE_STATS_FORMATTING_FUNCTIONS巨集置為1。
函式引數:pcWriteBuffer儲存任務狀態資訊的儲存,這個儲存要足夠大。
返回值:無。
任務的詳細資訊如下:
Name:任務名
State:任務狀態。X:任務正在執行;B:阻塞態;R:就緒態;S:掛起態;D:任務已經被刪除。
Priority:任務優先順序
Stack:任務堆疊”高水位線“,也就是堆疊歷史最小剩餘大小。
Num:任務編號,這個編號是唯一的。當多個任務使用同一個任務名時,可以使用這個編號進行區分。
5.17 統計任務的執行時間資訊
函式原型:
#include “FreeRTOS.h”
#include “task.h”
void vTaskGetRunTimeStats( char *pcWriteBuffer );
函式描述:獲取任務的執行時間統計資訊。使用這個函式必須將configGENERATE_RUN_TIME_STATS和configUSE_STATS_FORMATTING_FUNCTIONS巨集置為1。
如果巨集configGENERATE_RUN_TIME_STATS設定為1,還需要定義下列的巨集:
portCONFIGURE_TIMER_FOR_RUN_TIME_STATS():此巨集用來初始化一個外設來提供時間統計功能所需要的時基,一般是定時器/計數器。這個時基的解析度一定要比FreeRTOS的系統時鐘高,一般設定為比系統時鐘高10~20倍。
portGET_RUN_TIME_COUNTER_VALUE()或者portALT_GET_RUN_TIME_COUNTER_VALUE(Time):這兩個巨集實現其中一個即可。用於獲取當前的時基的時間值。
函式引數:pcWriteBuffer儲存任務執行時間資訊的儲存,這個儲存要足夠大。
返回值:無
任務的執行時間統計資訊如下:
任務的統計資訊提供了每個任務獲取到的CPU使用權總的時間。表裡面提供了每個任務的執行時間和其所佔總時間的百分比。
5.18 設定執行緒本地儲存指標的值
函式原型:
#include “FreeRTOS.h
#include “task.h”
void vTaskSetThreadLocalStoragePointer( TaskHandle_t xTaskToSet,
BaseType_t xIndex, void *pvValue );
函式描述:此函式用於設定執行緒本地儲存指標的值,每個任務都有自己的指標陣列來作為執行緒本地儲存,使用這些執行緒本地儲存可以用來在任務控制塊中儲存一些應用資訊,這些資訊只屬於任務自己。執行緒本地儲存指標陣列的大小由configNUM_THREAD_LOCAL_STORAGE_POINTERS巨集決定。如果要使用這個函式,這個巨集就能設定為0。
函式引數:xTaskToSet:任務控制程式碼,如果設為NULL表示自身任務。xIndex:要設定的執行緒本地儲存指標陣列的索引。pvValue:要儲存的值。
返回值:無
5.19 獲取執行緒本地儲存指標的值
函式原型:
#include “FreeRTOS.h”
#include “task.h”
void *pvTaskGetThreadLocalStoragePointer( TaskHandle_t xTaskToQuery,
BaseType_t xIndex );
函式描述:此函式用於獲取執行緒本地儲存指標的值,如果要使用這個函式configNUM_THREAD_LOCAL_STORAGE_POINTERS巨集不能設定為0。
函式引數:xTaskToQuery:任務控制程式碼,如果設為NULL表示自身任務。xIndex:要設定的執行緒本地儲存指標陣列的索引。
返回值:獲取到的執行緒本地儲存指標的值。
5.19 任務狀態查詢API函式實驗
目的:學習使用任務狀態查詢相關API函式,包括uxTaskGetSystemState()、vTaskGetInfo()、eTaskGetState()、vTaskList()。
設計:建立query_task,用於任務狀態和資訊查詢任務,此任務中使用任務狀態和資訊相關的API函式。建立print_task:間隔1s不停列印計數資訊,提示系統正在執行。
測試程式碼:
configSTACK_DEPTH_TYPE Print_Task_STACK_SIZE = 5;
UBaseType_t Print_Task_Priority = 1;
TaskHandle_t Print_xhandle;
configSTACK_DEPTH_TYPE Query_Task_STACK_SIZE = 20;
UBaseType_t Query_Task_Priority = 2;
TaskHandle_t Query_xhandle;
char InfoBuffer[1000];
void print_task_code(void *para)
{
static unsigned int cnt = 0;
for (;;)
{
PRINT(" print task cnt %u...", cnt);
cnt++;
vTaskDelay(1000);
}
}
void query_task_code(void *para)
{
unsigned int totalRunTime;
UBaseType_t arraySize, x;
TaskStatus_t *statusArray;
PRINT("----------- uxTaskGetSystemState() ---------------");
arraySize = uxTaskGetNumberOfTasks();
statusArray = pvPortMalloc(arraySize * sizeof(TaskStatus_t));
if (statusArray != NULL)
{
arraySize = uxTaskGetSystemState(statusArray, arraySize, &totalRunTime);
PRINT("TaskName TaskPriority TaskNumber");
for (x = 0; x < arraySize; x++)
{
PRINT("%-16s%-16d%-2d",
statusArray[x].pcTaskName,
statusArray[x].uxCurrentPriority,
statusArray[x].xTaskNumber);
}
}
vPortFree(statusArray);
PRINT("----------- uxTaskGetSystemState() end -----------\n");
PRINT("----------- vTaskGetInfo() ----------------");
TaskHandle_t taskHandle;
TaskStatus_t taskStatus;
taskHandle = xTaskGetHandle("print task");
vTaskGetInfo(taskHandle, &taskStatus, pdTRUE, eInvalid);
PRINT(" task name: %s", taskStatus.pcTaskName);
PRINT(" task number: %d", taskStatus.xTaskNumber);
PRINT(" task state: %d", taskStatus.eCurrentState);
PRINT(" task current priority: %d", taskStatus.uxCurrentPriority);
PRINT(" task base priority: %d", taskStatus.uxBasePriority);
PRINT("task stack base address: 0x%x", taskStatus.pxStackBase);
PRINT(" task high water mark: %d", taskStatus.usStackHighWaterMark);
PRINT(" task run time counter: %d",taskStatus.ulRunTimeCounter);
PRINT("----------- vTaskGetInfo() end ------------\n");
PRINT("----------- eTaskGetState() ----------------");
eTaskState taskState;
char *state_str[] = {"running", "ready", "blocked", "suspended", "deleted", "invalid"};
taskHandle = xTaskGetHandle("query task");
taskState = eTaskGetState(taskHandle);
PRINT("task state:%s", state_str[taskState]);
PRINT("----------- eTaskGetState() end ------------\n");
PRINT("----------- vTaskList() ----------------");
PRINT("Name State Priority Stack Num");
PRINT("******************************************");
vTaskList(InfoBuffer);
PRINT("%s", InfoBuffer);
PRINT("----------- vTaskList() end ------------\n");
for (;;)
{
static unsigned int cnt = 0;
PRINT(" query task cnt %u...", cnt);
cnt++;
vTaskDelay(1000);
}
}
void creat_task(void)
{
if (xTaskCreate(print_task_code, "print task",
Print_Task_STACK_SIZE, NULL, Print_Task_Priority,
&Print_xhandle) != pdPASS)
{
PRINT("creat task failed!\n");
}
if (xTaskCreate(query_task_code, "query task",
Query_Task_STACK_SIZE, NULL, Query_Task_Priority,
&Query_xhandle) != pdPASS)
{
PRINT("creat task failed!\n");
}
vTaskStartScheduler();
}
編譯、執行,結果如下:
$ ./build/freertos-simulator
----------- uxTaskGetSystemState() ---------------
TaskName TaskPriority TaskNumber
query task 2 2
print task 1 1
IDLE 0 3
Tmr Svc 30 4
----------- uxTaskGetSystemState() end -----------
----------- vTaskGetInfo() ----------------
task name: print task
task number: 1
task state: 1
task current priority: 1
task base priority: 1
task stack base address: 0x868010
task high water mark: 0
task run time counter: 0
----------- vTaskGetInfo() end ------------
----------- eTaskGetState() ----------------
task state:running
----------- eTaskGetState() end ------------
----------- vTaskList() ----------------
Name State Priority Stack Num
******************************************
query task X 2 15 2
print task R 1 0 1
IDLE R 0 65 3
Tmr Svc B 30 135 4
----------- vTaskList() end ------------
query task cnt 0...
print task cnt 0...
query task cnt 1...
print task cnt 1...
可以得到,“print task”任務處於就緒態,任務優先順序為1,棧空間已經用完了。任務編號為1。“query task”處於執行態,任務優先順序為2,棧空間剩餘15,任務編號為2。