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保存任务状态信息的存储,这个存储要足够大。

返回值:无。

任务的详细信息如下:

image-20210801205218591

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保存任务运行时间信息的存储,这个存储要足够大。

返回值:

任务的运行时间统计信息如下:

image-20210801210902871

任务的统计信息提供了每个任务获取到的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。

posted @ 2021-08-01 23:51  zhengcixi  阅读(95)  评论(0编辑  收藏  举报
回到顶部