3. 任务状态查询与统计信息获取
任务说明
本案例实现SafeRTOS任务状态查询与运行时间统计功能。系统创建两个不同优先级的任务:vTaskA周期性延时(阻塞态),vTaskB持续运行(运行态/就绪态)。主程序通过uxTaskGetSystemState()获取所有任务的状态信息,并通过vTaskGetRunTimeStats()获取各任务CPU运行时间占比,将结果通过串口输出。
核心API与数据结构
uxTaskGetSystemState():获取任务状态快照,填充TaskStatus_t数组vTaskGetRunTimeStats():生成各任务运行时间统计表(需配置configGENERATE_RUN_TIME_STATS为1)TaskStatus_t:包含任务句柄、任务名、任务号、状态、栈高水位、运行时间计数等字段
完整实现代码
/* FreeRTOS内核配置要求(FreeRTOSConfig.h中):
#define configGENERATE_RUN_TIME_STATS 1
#define configUSE_TRACE_FACILITY 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 1
并实现 portGET_RUN_TIME_COUNTER_VALUE() 和 portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()
*/
#include "FreeRTOS.h"
#include "task.h"
#include "stdio.h"
/* 任务句柄 */
TaskHandle_t xTaskAHandle = NULL;
TaskHandle_t xTaskBHandle = NULL;
/* 任务A:周期性延时,进入阻塞态 */
void vTaskA(void *pvParameters)
{
for (;;)
{
vTaskDelay(pdMS_TO_TICKS(500)); /* 阻塞500ms */
}
}
/* 任务B:持续运行,占用CPU */
void vTaskB(void *pvParameters)
{
volatile uint32_t ulCounter = 0;
for (;;)
{
ulCounter++; /* 模拟计算负载 */
}
}
/* 查询并打印任务状态 */
void vPrintTaskStats(void)
{
TaskStatus_t xTaskStatusArray[2];
UBaseType_t uxArraySize = 2;
uint32_t ulTotalRunTime = 0;
uint32_t ulStatsAsPercentage;
UBaseType_t uxIndex;
char *pcTaskName;
/* 获取任务状态快照 */
uxTaskGetSystemState(xTaskStatusArray, uxArraySize, &ulTotalRunTime);
printf("\r\n=== 任务状态 ===\r\n");
printf("任务名\t状态码\t栈高水位(字)\t运行计数\r\n");
for (uxIndex = 0; uxIndex < uxArraySize; uxIndex++)
{
pcTaskName = xTaskStatusArray[uxIndex].pcTaskName;
printf("%s\t%d\t%u\t\t%lu\r\n",
pcTaskName,
xTaskStatusArray[uxIndex].eCurrentState,
xTaskStatusArray[uxIndex].usStackHighWaterMark,
(unsigned long)xTaskStatusArray[uxIndex].ulRunTimeCounter);
}
/* 打印运行时间统计(百分比) */
printf("\r\n=== CPU运行时间统计 ===\r\n");
for (uxIndex = 0; uxIndex < uxArraySize; uxIndex++)
{
if (ulTotalRunTime > 0)
{
ulStatsAsPercentage =
(xTaskStatusArray[uxIndex].ulRunTimeCounter * 100UL) / ulTotalRunTime;
}
else
{
ulStatsAsPercentage = 0;
}
printf("%-10s: %lu%%\r\n",
xTaskStatusArray[uxIndex].pcTaskName,
(unsigned long)ulStatsAsPercentage);
}
}
int main(void)
{
/* 硬件初始化(串口、时钟等,由平台相关代码完成) */
prvSetupHardware();
/* 创建两个测试任务 */
xTaskCreate(vTaskA, "TaskA", 128, NULL, 1, &xTaskAHandle);
xTaskCreate(vTaskB, "TaskB", 128, NULL, 2, &xTaskBHandle);
/* 启动调度器 */
vTaskStartScheduler();
/* 正常不会执行到这里 */
return 0;
}
运行与验证
- 配置要求:在
FreeRTOSConfig.h中确认已定义configGENERATE_RUN_TIME_STATS=1、configUSE_TRACE_FACILITY=1、configUSE_STATS_FORMATTING_FUNCTIONS=1,并实现运行时间计数器(如使用DWT周期计数器或定时器)。 - 编译烧录:将代码编译后烧录至目标板,打开串口终端(波特率与
prvSetupHardware()中配置一致)。 - 观察输出:串口应周期性打印任务状态表与CPU占用百分比。状态码含义:1=就绪,2=运行,3=阻塞。
- 判定通过:
TaskA状态码为3(阻塞),TaskB状态码为1或2(就绪/运行);TaskB的CPU占用百分比显著高于TaskA(因TaskA大部分时间阻塞)。若输出符合上述逻辑,则验证通过。
预期输出示例
=== 任务状态 ===
任务名 状态码 栈高水位(字) 运行计数
TaskA 3 117 12345
TaskB 1 98 987654
=== CPU运行时间统计 ===
TaskA : 1%
TaskB : 99%
以上输出为逻辑推导的示例值,实际数值取决于运行时长与任务调度时序。