09-任务状态查询与运行时统计.md 12 KB


tags: [source-summary] type: source source: "尚硅谷嵌入式技术之FreeRTOS实时操作系统 V1.0.3 — 第8章 任务相关API函数" author: "尚硅谷研究院" date: 2026-07-17

created: 2026-07-17

任务状态查询与运行时统计

用生活理解:任务状态查询就像给公司做一次全面盘点——有多少员工(任务数)、每个员工的职级(优先级)、当前在干嘛(运行/就绪/阻塞)、堆栈压力(水位线)一目了然。运行时统计则像月底看考勤——每个员工干了多少活,一目了然。

Concept

Basic concept

FreeRTOS 提供一套丰富的 API 用于查询任务运行时信息,包括:

  • 优先级查询与设置:获取/修改任务的优先级
  • 任务数量统计:系统中当前存在的总任务数
  • 任务详细信息:获取任务名称、编号、状态、优先级等
  • 栈空间使用:查看栈的"水位线"(剩余空间最小值)
  • 任务状态:查询任务当前处于运行/就绪/阻塞/挂起/删除态
  • 任务列表:以可读文本格式输出所有任务信息
  • 运行时统计:需要额外硬件定时器,统计各任务占用 CPU 的百分比

Working principle

运行时统计(Run Time Stats) 需要额外的硬件定时器作为时钟源:

配置步骤:
1. 启用 configGENERATE_RUN_TIME_STATS = 1
2. 配置一个硬件定时器(如 TIM6/TIM7)产生高频计时
3. 实现 portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() 初始化定时器
4. 实现 portGET_RUN_TIME_COUNTER_VALUE() 返回定时器计数值

统计结果以表格形式输出:

Task           Abs Time    % Time
--------------------------------
task1          12345       45.2
task2          9876        36.1
IDLE           5120        18.7

Experiment

Requirements

P06(状态查询 API)

  • task2 一次性调用所有状态查询 API 并打印结果:
    • uxTaskPriorityGet() / vTaskPrioritySet()
    • uxTaskGetNumberOfTasks()
    • uxTaskGetSystemState() / vTaskGetInfo()
    • xTaskGetCurrentTaskHandle() / xTaskGetHandle()
    • uxTaskGetStackHighWaterMark()
    • eTaskGetState()
    • vTaskList()

P07(运行时统计)

  • task2 每隔 500ms 打印 vTaskGetRunTimeStats() 结果
  • 需要 TIM6 提供高频计时

Code Implementation

P06:任务状态查询

File: 06_任务状态查询/Core/Src/freertos_demo.c

#include "freertos_demo.h"
#include "FreeRTOS.h"
#include "task.h"
#include "LED.h"
#include "Key.h"

#define START_TASK_STACK 128
#define START_TASK_PRIORITY 1
TaskHandle_t start_task_handle;
void start_task(void *pvParameters);

#define TASK1_STACK 128
#define TASK1_PRIORITY 2
TaskHandle_t task1_handle;
void task1(void *pvParameters);

/* task2栈空间更大,因为要调用多个API和打印 */
#define TASK2_STACK 256
#define TASK2_PRIORITY 3
TaskHandle_t task2_handle;
void task2(void *pvParameters);

void freertos_start(void)
{
    xTaskCreate((TaskFunction_t)start_task,
                (char *)"start_task",
                (configSTACK_DEPTH_TYPE)START_TASK_STACK,
                (void *)NULL,
                (UBaseType_t)START_TASK_PRIORITY,
                (TaskHandle_t *)&start_task_handle);

    vTaskStartScheduler();
}

void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();

    xTaskCreate((TaskFunction_t)task1, (char *)"task1",
                (configSTACK_DEPTH_TYPE)TASK1_STACK, (void *)NULL,
                (UBaseType_t)TASK1_PRIORITY, (TaskHandle_t *)&task1_handle);
    xTaskCreate((TaskFunction_t)task2, (char *)"task2",
                (configSTACK_DEPTH_TYPE)TASK2_STACK, (void *)NULL,
                (UBaseType_t)TASK2_PRIORITY, (TaskHandle_t *)&task2_handle);

    vTaskDelete(NULL);
    taskEXIT_CRITICAL();
}

void task1(void *pvParameters)
{
    while (1)
    {
        printf("task1正在运行...\r\n");
        LED_Toggle(LED1_Pin);
        vTaskDelay(500);
    }
}

char task_info[500];

/**
 * @description: task2——演示所有任务状态查询API的使用
 */
void task2(void *pvParameters)
{
    UBaseType_t task_priority = 0;
    UBaseType_t task_num = 0;
    TaskStatus_t task_status[10] = {0};          // 最多10个任务的状态信息
    TaskStatus_t task_state;
    TaskHandle_t task_handle = NULL;
    UBaseType_t task_stack_remain_min = 0;
    eTaskState e_task_state = 0;

    /* 1. 获取task1的优先级 */
    task_priority = uxTaskPriorityGet(task1_handle);
    printf("task1当前优先级=%d\r\n", task_priority);

    /* 2. 设置task1的优先级为4 */
    vTaskPrioritySet(task1_handle, 4);
    task_priority = uxTaskPriorityGet(task1_handle);
    printf("task1修改后优先级=%d\r\n", task_priority);

    /* 3. 获取系统中任务总数 */
    task_num = uxTaskGetNumberOfTasks();
    printf("当前系统中任务数量=%d\r\n", task_num);

    /* 4. 获取所有任务状态信息 */
    uxTaskGetSystemState(task_status, task_num, NULL);
    printf("任务名\t\t任务号\t\t状态\t\t当前优先级\t\t基础优先级\r\n");
    for (uint8_t i = 0; i < task_num; i++)
    {
        printf("%s\t\t%d\t\t%d\t\t%d\t\t%d\r\n",
               task_status[i].pcTaskName,
               task_status[i].xTaskNumber,
               task_status[i].eCurrentState,
               task_status[i].uxCurrentPriority,
               task_status[i].uxBasePriority);
    }

    /* 5. 获取任务详细信息 */
    vTaskGetInfo(
        task1_handle,      // 要查询的任务句柄
        &task_state,       // 用于接收任务信息的结构体
        pdTRUE,            // 是否获取栈状态
        eInvalid);         // 任务状态(入参被忽略)
    printf("任务名称: %s\r\n", task_state.pcTaskName);
    printf("任务编号: %d\r\n", task_state.xTaskNumber);
    printf("任务状态: %d\r\n", task_state.eCurrentState);
    printf("当前优先级: %d\r\n", task_state.uxCurrentPriority);

    /* 6. 获取当前正在运行的任务句柄 */
    task_handle = xTaskGetCurrentTaskHandle();
    printf("当前运行任务句柄=%p, task2句柄=%p\r\n", task_handle, task2_handle);

    /* 7. 通过任务名获取句柄 */
    task_handle = xTaskGetHandle("task1");
    printf("通过名称获取task1句柄=%p, task1原始句柄=%p\r\n", task_handle, task1_handle);

    /* 8. 获取栈空间水位线(栈剩余的最小值→反映栈峰值使用量) */
    task_stack_remain_min = uxTaskGetStackHighWaterMark(task2_handle);
    printf("task2栈剩余空间最小值=%d\r\n", task_stack_remain_min);

    /* 9. 获取任务状态(运行/就绪/阻塞/挂起/删除) */
    e_task_state = eTaskGetState(task1_handle);
    printf("task1当前状态=%d\r\n", e_task_state);

    /* 10. 打印可读格式的任务列表 */
    vTaskList(task_info);
    printf("%s\r\n", task_info);

    while (1)
    {
        vTaskDelay(500);
    }
}

P07:运行时统计

File: 07_任务运行时间统计/Core/Src/freertos_demo.c

#include "freertos_demo.h"
#include "FreeRTOS.h"
#include "task.h"
#include "LED.h"

#define START_TASK_STACK 128
#define START_TASK_PRIORITY 1
TaskHandle_t start_task_handle;
void start_task(void *pvParameters);

#define TASK1_STACK 128
#define TASK1_PRIORITY 2
TaskHandle_t task1_handle;
void task1(void *pvParameters);

#define TASK2_STACK 128
#define TASK2_PRIORITY 3
TaskHandle_t task2_handle;
void task2(void *pvParameters);

void freertos_start(void)
{
    xTaskCreate((TaskFunction_t)start_task,
                (char *)"start_task",
                (configSTACK_DEPTH_TYPE)START_TASK_STACK,
                (void *)NULL,
                (UBaseType_t)START_TASK_PRIORITY,
                (TaskHandle_t *)&start_task_handle);

    vTaskStartScheduler();
}

void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();

    xTaskCreate((TaskFunction_t)task1, (char *)"task1",
                (configSTACK_DEPTH_TYPE)TASK1_STACK, (void *)NULL,
                (UBaseType_t)TASK1_PRIORITY, (TaskHandle_t *)&task1_handle);
    xTaskCreate((TaskFunction_t)task2, (char *)"task2",
                (configSTACK_DEPTH_TYPE)TASK2_STACK, (void *)NULL,
                (UBaseType_t)TASK2_PRIORITY, (TaskHandle_t *)&task2_handle);

    vTaskDelete(NULL);
    taskEXIT_CRITICAL();
}

void task1(void *pvParameters)
{
    while (1)
    {
        printf("task1正在运行...\r\n");
        LED_Toggle(LED1_Pin);
        vTaskDelay(500);
    }
}

char task_time_info[500];

/**
 * @description: task2——每隔500ms打印各任务运行时间统计
 */
void task2(void *pvParameters)
{
    while (1)
    {
        printf("task2正在运行...\r\n");
        /* 获取各任务的运行时间统计表(需要硬件定时器支持) */
        vTaskGetRunTimeStats(task_time_info);
        printf("%s\r\n", task_time_info);
        vTaskDelay(500);
    }
}

Key Config

P06 FreeRTOSConfig.h(启用查询功能):

#define configUSE_TRACE_FACILITY             1     // 启用任务跟踪功能
#define configUSE_STATS_FORMATTING_FUNCTIONS 1     // 启用格式化输出函数
#define INCLUDE_xTaskGetHandle              1     // 启用通过名称获取句柄
#define INCLUDE_uxTaskGetStackHighWaterMark 1     // 启用栈水位线查询

P07 FreeRTOSConfig.h(启用运行时统计 + 硬件定时器配置):

#define configGENERATE_RUN_TIME_STATS    1     // 生成运行时统计

#if configGENERATE_RUN_TIME_STATS
extern volatile unsigned long ulHighFrequencyTimerTicks;  // 高频定时器计数值
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() ( ulHighFrequencyTimerTicks = 0UL )  // 初始化定时器
#define portGET_RUN_TIME_COUNTER_VALUE()    ulHighFrequencyTimerTicks  // 读取当前计数值
#endif

#define configUSE_TRACE_FACILITY               1
#define configUSE_STATS_FORMATTING_FUNCTIONS   1

Core API Reference Table

Function Parameters Return Description
uxTaskPriorityGet xTask UBaseType_t 获取任务优先级
vTaskPrioritySet xTask, uxNewPriority void 设置任务优先级
uxTaskGetNumberOfTasks UBaseType_t 获取系统中任务总数
uxTaskGetSystemState pxTaskStatusArray, uxArraySize, pulTotalRunTime UBaseType_t 获取所有任务的状态
vTaskGetInfo xTask, pxTaskStatus, xGetFreeStackSpace, eState void 获取任务详细信息
xTaskGetCurrentTaskHandle TaskHandle_t 获取当前运行任务的句柄
xTaskGetHandle pcNameToQuery TaskHandle_t 通过任务名获取句柄
uxTaskGetStackHighWaterMark xTask UBaseType_t 获取栈剩余空间下限(以 word 计)
eTaskGetState xTask eTaskState 获取任务状态(running/ready/blocked/suspended/deleted)
vTaskList pcWriteBuffer void 将任务列表格式化输出为可读字符串
vTaskGetRunTimeStats pcWriteBuffer void 获取任务运行时统计信息

Common Issues & Pitfalls

  1. configUSE_TRACE_FACILITY 必须开启vTaskList()uxTaskGetSystemState()eTaskGetState() 等函数都需要此宏为 1。
  2. configUSE_STATS_FORMATTING_FUNCTIONS 与 vTaskListvTaskList() 需要同时开启 configUSE_TRACE_FACILITYconfigUSE_STATS_FORMATTING_FUNCTIONS
  3. 运行时统计需要硬件定时器vTaskGetRunTimeStats() 依赖一个比 SysTick 更高分辨率的硬件定时器。如果不配置该定时器,统计结果无意义。使用 TIM6/TIM7 等基本定时器即可。
  4. 栈水位线(High Water Mark)的含义:返回的是任务运行以来栈剩余空间的最小值,用这个值可以判断栈配置是否合理。如果返回值接近 0,说明栈空间紧张,需要增大栈大小。
  5. 缓冲区大小vTaskList()vTaskGetRunTimeStats() 输出的文本内容随任务数量变化,确保提供的缓冲区足够大(每个任务约 40~60 字节)。
  6. vTaskPrioritySet 修改优先级后的调度:当提高一个低优先级任务的优先级时,如果新优先级高于当前运行任务的优先级,会立即触发一次任务切换。