FreeRTOS-03-其它任务相关函数
说明:
本文仅作为学习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。