博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
FreeRTOS学习笔记——任务壮态或信息查询与任务运行时间统计
阅读量:4218 次
发布时间:2019-05-26

本文共 10170 字,大约阅读时间需要 33 分钟。

前面几章我们花费了大量的精力来学习FreeRTOS 的任务管理,但是真正涉及到的与任务相关的API 函数只有那么几个。但是FreeRTOS 还有很多与任务相关的API 函数,不过这些API函数大多都是辅助函数了,本章我们就来看一下这些与任务相关的其他的API 函数。本章分为如下几部分:
11.1 任务相关API 函数预览
11.2 任务相关API 函数详解

11.3 任务壮态查询API 函数实验

11.1 任务相关API 函数预览

先通过一个表11.1.1 来看一下这些与任务相关的其他API 函数都有哪些:

这些API 函数在FreeRTOS 官网上都有,如图11.1.2 所示:

11.2 任务相关API 函数详解

1、函数uxTaskPriorityGet()
此函数用来获取指定任务的优先级,要使用此函数的话宏INCLUDE_uxTaskPriorityGet 应该定义为1,函数原型如下:

参数:

xTask: 要查找的任务的任务句柄。
返回值: 获取到的对应的任务的优先级。
2、函数vTaskPrioritySet()
此函数用于改变某一个任务的任务优先级, 要使用此函数的话宏INCLUDE_vTaskPrioritySet 应该定义为1,函数原型如下:

参数:

xTask: 要查找的任务的任务句柄。
uxNewPriority: 任务要使用的新的优先级,可以是0~ configMAX_PRIORITIES – 1。
返回值: 无。
3、uxTaskGetSystemState()
此函数用于获取系统中所有任务的任务壮态,每个任务的壮态信息保存在一个TaskStatus_t类型的结构体里面,这个结构体里面包含了任务的任务句柄、任务名字、堆栈、优先级等信息,要使用此函数的话宏configUSE_TRACE_FACILITY 应该定义为1,函数原型如下:

参数:

pxTaskStatusArray: 指向TaskStatus_t 结构体类型的数组首地址,每个任务至少需要一个TaskStatus_t 结构体, 任务的数量可以使用函数uxTaskGetNumberOfTasks()。结构体TaskStatus_t 在文件task.h 中有如下定义:

uxArraySize: 保存任务壮态数组的数组的大小。

pulTotalRunTime: 如果configGENERATE_RUN_TIME_STATS 为1 的话此参数用来保存系统总的运行时间。
返回值: 统计到的任务壮态的个数,也就是填写到数组pxTaskStatusArray 中的个数,此值应该等于函数uxTaskGetNumberOfTasks()的返回值。如果参数uxArraySize 太小的话返回值可能为0。
4、函数vTaskGetInfo()
此函数也是用来获取任务壮态的,但是是获取指定的单个任务的壮态的,任务的壮态信息填充到参数pxTaskStatus 中,这个参数也是TaskStatus_t 类型的。要使用此函数的话宏configUSE_TRACE_FACILITY 要定义为1,函数原型如下:

参数:

xTask: 要查找的任务的任务句柄。
pxTaskStatus: 指向类型为TaskStatus_t 的结构体变量。
xGetFreeStackSpace: 在结构体TaskStatus_t 中有个字段usStackHighWaterMark 来保存自任务运行以来任务堆栈剩余的历史最小大小,这个值越小说明越接近堆栈溢出, 但是计算这个值需要花费一点时间, 所以我们可以通过将xGetFreeStackSpace 设置为pdFALSE 来跳过这个步骤,当设置为pdTRUE的时候就会检查堆栈的历史剩余最小值。
eState: 结构体TaskStatus_t 中有个字段eCurrentState 用来保存任务运行壮态,这个字段是eTaskState 类型的,这是个枚举类型,在task.h 中有如下定义:

获取任务运行壮态会耗费不少时间,所以为了加快函数vTaskGetInfo()的执行速度结构体TaskStatus_t 中的字段eCurrentState 就可以由用户直接赋值,参数eState 就是要赋的值。如果不在乎这点时间,那么可以将eState 设置为eInvalid,这样任务的壮态信息就由函数vTaskGetInfo()去想办法获取。

返回值: 无。

5、函数xTaskGetApplicationTaskTag()
此函数用于获取任务的Tag(标签)值,任务控制块中有个成员变量pxTaskTag 来保存任务的标签值。标签的功能由用户自行决定,此函数就是用来获取这个标签值的,FreeRTOS 系统内核是不会使用到这个标签的。要使用此函数的话宏configUSE_APPLICATION_TASK_TAG 必须为1,函数原型如下:

参数:

xTask: 要获取标签值的任务对应的任务句柄,如果为NULL 的话就获取当前正在运行的任务标签值。
返回值: 任务的标签值。
6、函数xTaskGetCurrentTaskHandle()
此函数用于获取当前任务的任务句柄,其实获取到的就是任务控制块,在前面讲解任务创建函数的时候说过任务句柄就是任务控制。如果要使用此函数的话宏INCLUDE_xTaskGetCurrentTaskHandle 应该为1,函数原型如下:

参数: 无

返回值: 当前任务的任务句柄。
7、函数xTaskGetHandle()
此函数根据任务名字获取任务的任务句柄,在使用函数xTaskCreate()或xTaskCreateStatic()创建任务的时候都会给任务分配一个任务名,函数xTaskGetHandle()就是使用这个任务名字来查询其对应的任务句柄的。要使用此函数的话宏INCLUDE_xTaskGetHandle 应该设置为1,此函数原型如下:

参数:

pcNameToQuery: 任务名,C 语言字符串。

返回值:

NULL: 没有任务名pcNameToQuery 所对应的任务。
其他值: 任务名pcNameToQuery 所对应的任务句柄
8、函数xTaskGetIdleTaskHandle()
此函数用于返回空闲任务的任务句柄, 要使用此函数的话宏INCLUDE_xTaskGetIdleTaskHandle 必须为1,函数原型如下:

参数: 无

返回值: 空闲任务的任务句柄。
9、函数uxTaskGetStackHighWaterMark()
每个任务都有自己的堆栈,堆栈的总大小在创建任务的时候就确定了,此函数用于检查任务从创建好到现在的历史剩余最小值,这个值越小说明任务堆栈溢出的可能性就越大!FreeRTOS 把这个历史剩余最小值叫做“高水位线”。此函数相对来说会多耗费一点时间,所以在代码调试阶段可以使用, 产品发布的时候最好不要使用。要使用此函数的话宏

INCLUDE_uxTaskGetStackHighWaterMark 必须为1,此函数原型如下:

参数:

xTask: 要查询的任务的任务句柄,当这个参数为NULL 的话说明查询自身任务(即调用函数uxTaskGetStackHighWaterMark()的任务)的“高水位线”。
返回值: 任务堆栈的“高水位线”值,也就是堆栈的历史剩余最小值。
10、函数eTaskGetState()
此函数用于查询某个任务的运行壮态,比如:运行态、阻塞态、挂起态、就绪态等,返回值是个枚举类型。要使用此函数的话宏INCLUDE_eTaskGetState 必须为1,函数原型如下:

参数:

xTask: 要查询的任务的任务句柄。
返回值: 返回值为eTaskState 类型,这是个枚举类型,在文件task.h 中有定义,前面讲解函数vTaskGetInfo()的时候已经讲过了。

11、函数pcTaskGetName()

根据某个任务的任务句柄来查询这个任务对应的任务名,函数原型如下:

参数:

xTaskToQuery: 要查询的任务的任务句柄,此参数为NULL 的话表示查询自身任务(调用函数pcTaskGetName())的任务名字
返回值: 返回任务所对应的任务名。
12、函数xTaskGetTickCount()
此函数用于查询任务调度器从启动到现在时间计数器xTickCount 的值。xTickCount 是系统的时钟节拍值,并不是真实的时间值。每个滴答定时器中断xTickCount 就会加1,一秒钟滴答定时器中断多少次取决于宏configTICK_RATE_HZ。理论上xTickCount 存在溢出的问题,但是这个溢出对于FreeRTOS 的内核没有影响,但是如果用户的应用程序有使用到的话就要考虑溢出了。什么时候溢出取决于宏configUSE_16_BIT_TICKS,当此宏为1 的时候xTixkCount 就是个16 位的变量,当为0 的时候就是个32 位的变量。函数原型如下:

参数: 无。

返回值: 时间计数器xTickCount 的值。

13、函数xTaskGetTickCountFromISR()

此函数是xTaskGetTickCount()的中断级版本,用于在中断服务函数中获取时间计数器xTickCount 的值,函数原型如下:

参数: 无。

返回值: 时间计数器xTickCount 的值。
14、函数xTaskGetSchedulerState()
此函数用于获取FreeRTOS 的任务调度器运行情况:运行?关闭?还是挂起!要使用此函数的话宏INCLUDE_xTaskGetSchedulerState 必须为1,此函数原型如下:

参数: 无。

返回值:
taskSCHEDULER_NOT_STARTED: 调度器未启动, 调度器的启动是通过函数vTaskStartScheduler() 来完成, 所以在函数

vTaskStartScheduler() 未调用之前调用函数xTaskGetSchedulerState()的话就会返回此值。taskSCHEDULER_RUNNING: 调度器正在运行。taskSCHEDULER_SUSPENDED: 调度器挂起。

15、函数uxTaskGetNumberOfTasks()

此函数用于查询系统当前存在的任务数量,函数原型如下:

参数: 无。

返回值: 当前系统中存在的任务数量, 此值=挂起态的任务+阻塞态的任务+就绪态的任务+空闲任务+运行态的任务。
16、函数vTaskList()

此函数会创建一个表格来描述每个任务的详细信息,如图11.2.1 所示:

表中的信息如下:

Name: 创建任务的时候给任务分配的名字。
State: 任务的壮态信息,B 是阻塞态,R 是就绪态,S 是挂起态,D 是删除态。
Priority:任务优先级。
Stack: 任务堆栈的“高水位线”,就是堆栈历史最小剩余大小。
Num: 任务编号,这个编号是唯一的,当多个任务使用同一个任务名的时候可以通过此
编号来做区分。

函数原型如下:

参数:

pcWriteBuffer: 保存任务壮态信息表的存储区。存储区要足够大来保存任务状态信息表。

返回值: 无

17、函数vTaskGetRunTimeStats()

FreeRTOS 可以通过相关的配置来统计任务的运行时间信息,任务的运行时间信息提供了每个任务获取到CPU 使用权总的时间。函数vTaskGetRunTimeStats()会将统计到的信息填充到一个表里面,表里面提供了每个任务的运行时间和其所占总时间的百分比,如图11.2.2 所示:

函数vTaskGetRunTimeStats() 是一个很实用的函数, 要使用此函数的话宏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: 保存任务时间信息的存储区。存储区要足够大来保存任务时间信息。
返回值: 无
18、函数vTaskSetApplicationTaskTag()
此函数是为高级用户准备的,此函数用于设置某个任务的标签值 ,这个标签值的具体函数和用法由用户自行决定,FreeRTOS 内核不会使用这个标签值,如果要使用此函数的话宏configUSE_APPLICATION_TASK_TAG 必须为1,函数原型如下:

参数:

xTask: 要设置标签值的任务,此值为NULL 的话表示设置自身任务的标签值。
pxHookFunction: 要设置的标签值,这是一个TaskHookFunction_t 类型的函数指针,但是也可以设置为其他值。
返回值: 无
19、函数SetThreadLocalStoragePointer()
此函数用于设置线程本地存储指针的值,每个任务都有它自己的指针数组来作为线程本地存储,使用这些线程本地存储可以用来在任务控制块中存储一些应用信息,这些信息只属于任务自己的。线程本地存储指针数组的大小由宏configNUM_THREAD_LOCAL_STORAGE_POINTERS 来决定的。如果要使用此函数的话宏configNUM_THREAD_LOCAL_STORAGE_POINTERS 不能为0,宏的具体值是本地存储指针数组的大小,函数原型如下:

参数:

xTaskToSet: 要设置线程本地存储指针的任务的任务句柄,如果是NULL 的话表示设置任务自身的线程本地存储指针。
xIndex: 要设置的线程本地存储指针数组的索引。
pvValue: 要存储的值。
返回值: 无
20、函数GetThreadLocalStoragePointer()
此函数用于获取线程本地存储指针的值, 如果要使用此函数的话宏configNUM_THREAD_LOCAL_STORAGE_POINTERS 不能为0,函数原型如下:

参数:

xTaskToSet: 要获取的线程本地存储指针的任务句柄,如果是NULL 的话表示获取任务自身的线程本地存储指针。
xIndex: 要获取的线程本地存储指针数组的索引。
返回值: 获取到的线程本地存储指针的值。
11.3 任务壮态查询API 函数实验
11.3.1 实验程序设计
FreeRTOS 与任务相关的API 函数中有很多是与任务壮态或者信息查询有关的,比如函数uxTaskGetSystemState()、vTaskGetInfo()、eTaskGetState()和vTaskList()。本实验我们就来学习这些函数的使用方法。

1、实验目的

学习使用FreeRTOS 与任务壮态或者信息查询有关的API 函数,包括uxTaskGetSystemState()、vTaskGetInfo()、eTaskGetState()和vTaskList()。
2、实验设计
本实验设计三个任务:start_task、led0_task 和query_task ,这三个任务的任务功能如下:start_task:用来创建其他2 个任务。led0_task :控制LED0 灯闪烁,提示系统正在运行。query_task :任务壮态和信息查询任务,在此任务中学习使用与任务的壮态和信息查询有关的API 函数。实验需要一个按键 KEY_UP,这四个按键的功能如下:
KEY_UP: 控制程序的运行步骤。
3、实验工程

FreeRTOS 实验11-1 FreeRTOS 任务壮态或信息查询。

4、实验程序与分析
●任务设置

实验中任务优先级、堆栈大小和任务句柄等的设置如下:

● main()函数

在main 函数中我们主要完成硬件的初始化,在硬件初始化完成以后创建了任务start_task()并且开启了FreeRTOS 的任务调度。

● 任务函数

(1)、使用函数uxTaskGetNumberOfTasks()获取当前系统中的任务数量,因为要根据任务数量给任务信息数组StatusArray 分配内存。注意,这里StatusArray 是个指向TaskStatus_t 类型的指针,但是在使用的时候会把他当作一个数组来用。

(2)、调用函数pvPortMalloc()给任务信息数组StatusArray 分配内存,数组是TaskStatus_t 类型。
(3)、调用函数uxTaskGetSystemState()获取系统中所有任务的信息,并将获取到的信息保存在StatusArray 中。
(4)、通过串口将获取到的所有任务的部分信息打印出来,这里并没有把所获取到的信息都输出,只是将任务的任务名、任务优先级和任务编号做了输出。
(5)、任务信息数组StatusArray 使用完毕,释放其内存。
(6)、调用函数xTaskGetHandle()根据任务名来获取任务句柄,这里获取任务名为“led0_task”的任务句柄。我们在创建任务的时候一般都会保存任务的句柄,如果保存了任务句柄的话就可以直接使用。

(7)、调用函数vTaskGetInfo()获取任务名为“led0_task”的任务信息,任务信息保存在TaskStatus 中。获取任务信息的时候允许统计任务堆栈历史最小剩余大小,任务的运行壮态也是由函数vTaskGetInfo()来计。
(8)、通过串口输出获取到的任务led0_task 的任务信息。
(9)、通过函数xTaskGetHandle()获取任务名为“query_task”的任务句柄。
(10)、调用函数eTaskGetState()获取任务的运行壮态。
(11)、通过函数eTaskGetState()获取到的任务运行壮态是个枚举类型:eTaskState,枚举类型不同的值表示不同的含义,这里用字符串来描述这些枚举值的含义。
(12)、通过串口输出任务query_task 的运行壮态信息。
(13)、调用函数vTaskList()统计所有任务的信息,统计出来的任务信息存储在缓冲区InfoBuffer 中,这些任务信息以表格的形式呈现,
(14)、通过串口输出保存在缓冲区InfoBuffer 中的任务信息。
11.3.2 程序运行结果分析
编译并下载实验代码到开发板中,打开串口调试助手,然后按照任务函数query_task()中的步骤一步步的测试分析。
● 第一步
第一步是学习uxTaskGetSystemState()函数的使用,通过此函数获取到系统中当前所有任务的信息,并且通过串口输出其中的一部分信息,这里我们输出了任务名、任务的优先级和任务的编号,如图11.3.2.1 所示:

从图11.3.2.1 可以看出空闲任务的任务优先级最低,为0,定时器服务任务优先级最高,为31。而且任务的优先级和任务的编号是不同的,优先级是用户自行设定的,而编号是根据任务创建的先后顺序来自动分配的。

● 第二步
第二步是通过函数vTaskGetInfo()来获取任务名为“led0_task”的任务信息,并通过串口输出,如图11.3.2.2 所示:

图11.3.2.2 中可以看出有关任务led0_task 的详细信息,包括任务名、任务编号、任务当前优先级、任务基优先级,任务堆栈基地址和堆栈历史剩余最小值。

● 第三步
第三步通过函数eTaskGetStat()来任务query_task 的运行壮态,串口调试助手显示如图11.3.2.3 所示:

● 第四步

第四步是通过函数vTaskList()获取系统中当前所有任务的详细信息,并且将这些信息按照表格的形式组织在一起存放在用户提供的缓冲区中,例程中将这些信息放到了缓冲区InfoBuffer中。最后通过串口输出缓冲区InfoBuffer 中的信息,如图11.3.2.4 所示:

图11.3.2.4 中各列的含义我们在讲解函数vTaskList()的时候已经详细的讲解过了。

11.4 任务运行时间信息统计实验
FreeRTOS 可以通过函数vTaskGetRunTimeStats()来统计每个任务使用CPU 的时间,以及所使用的时间占总时间的比例。在调试代码的时候我们可以根据这个时间使用值来分析哪个任务的CPU 占用率高,然后合理的分配或优化任务。本实验我们就来学习如何使用FreeRTOS 的这个运行时间壮态统计功能。
11.4.1 相关宏的设置
要使用此功能的话宏configGENERATE_RUN_TIME_STATS 必须为1,还需要在定义其他两个宏:portCONFIGURE_TIMER_FOR_RUN_TIME_STATS():配置一个高精度定时器/计数器提供时基。portGET_RUN_TIME_COUNTER_VALUE():读取时基的时间值。这三个宏在FreeRTOSConfig.h 中定义,如下:

其中函数ConfigureTimeForRunTimeStats()和变量FreeRTOSRunTimeTicks 在timer.c 里面定义,如下:

函数ConfigureTimeForRunTimeStats()其实就是初始化定时器,因为时间统计功能需要用户提供一个高精度的时钟,这里使用定时器3。前面在讲函数vTaskGetRunTimeStats()的时候说过,这个时钟的精度要比FreeRTOS 的系统时钟高,大约10~20 倍即可。FreeRTOS 系统时钟我们配置的是1000HZ,周期1ms,这里我们将定时器3 的中断频率配置为20KHZ,周期50us,刚好

是系统时钟频率的20 倍。定时器3 初始化函数如下:

FreeRTOSRunTimeTicks 是个全局变量,用来为时间统计功能提供时间,在定时器3 的中断服务函数中进行更新。

11.4.2 实验程序设计
1、实验目的
学习使用FreeRTOS 运行时间壮态统计函数vTaskGetRunTimeStats()的使用。
2、实验设计
本实验设计四个任务:start_task、task1_task 、task2_task 和RunTimeStats_task,这四个任
务的任务功能如下:
start_task:用来创建其他3 个任务。
task1_task :应用任务1,控制LED0 灯闪烁,并且刷新LCD 屏幕上指定区域的颜色。
task2_task :应用任务2,控制LED1 灯闪烁,并且刷新LCD 屏幕上指定区域的颜色。
RunTimeStats_task:获取按键值,当KEY_UP 键按下以后就调用函数vTaskGetRunTimeStats()
获取任务的运行时间信息,并且将其通过串口输出到串口调试助手上。
实验需要一个按键 KEY_UP,用来获取系统中任务运行时间信息。
3、实验工程

FreeRTOS 实验11-2 FreeRTOS 任务运行时间统计。

4、实验程序与分析

●任务设置

● main()函数

在main 函数中我们主要完成硬件的初始化,在硬件初始化完成以后创建了任务start_task()
并且开启了FreeRTOS 的任务调度。

● 任务函数

(1)、调用函数vTaskGetRunTimeStats()获取任务运行时间信息,此函数会统计任务的运行时间,并且将统计到的运行时间信息按照表格的形式组织在一起并存放在用户设置的缓冲区里面,缓冲区的首地址通过参数传递给函数vTaskGetRunTimeStats()。

(2)、通过串口输出统计到的任务运行时间信息。
11.4.3 程序运行结果分析
编译并下载实验代码到开发板中,打开串口调试助手,按下KEY_UP 按键输出任务的运行时间信息,如图11.4.3.1 所示:

要注意,函数vTaskGetRunTimeStats()相对来说会很耗时间,所以不要太过于频繁的调用此函数,测试阶段可以使用此函数来分析任务的运行情况。还有就是运行时间不是真正的运行时间,真正的时间值要乘以50us。

你可能感兴趣的文章
JavaScript学习
查看>>
《谁动了我的奶酪》
查看>>
查看mysql的日志
查看>>
python中init方法和随机数方法
查看>>
python 文件操作
查看>>
MySQL命名、设计及使用规范
查看>>
python 爬虫
查看>>
pycharm 下载Django
查看>>
搭建一个简单的Django项目
查看>>
解决mysql中文乱码
查看>>
《谁的青春不迷茫》
查看>>
有多努力,就有多幸运
查看>>
【Angular】引入BootStrap第三方库
查看>>
创建Angular项目
查看>>
Where there is life, there is hope
查看>>
Neither the JAVA_HOME nor the JRE_HOME environment variable is defined
查看>>
idea启动Tomcat控制台乱码
查看>>
关于Spring
查看>>
SSH插入数据库乱码
查看>>
JSP分页显示重复
查看>>