FreeRTOS 学习:(二十四)任务状态与信息查询 API 函数

上一篇 下一篇
时间片调度实验


任务相关 -- 辅助 API 函数

除了前面讲解的核心任务相关函数,其实 FreeRTOS 还有很多与任务相关的 API 函数,不过这些 API 函数大多都是辅助函数:

还有很多很多,这里就不一一列出了,请参考手册或 FreeRTOS 官网。

1)任务状态与信息查询 API 函数

1.1)函数

  1. uxTaskPriorityGet()

    • 声明:UBaseType_t uxTaskPriorityGet ( const TaskHandle_t xTask )
    • 功能:此函数用于 获取指定任务的任务优先级使用该函数需将宏 INCLUDE_uxTaskPriorityGet 置 1(默认为 1 )
    • 形参
      • xTask任务句柄,NULL 代表任务自身(任务自身的句柄也可以作为参数)
    • 返回值
      • 任务优先级数值(整数)
  2. vTaskPrioritySet()

    • 声明:void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority )
    • 功能:此函数用于 改变某个任务的任务优先级使用该函数需将宏 INCLUDE_vTaskPrioritySet 为 1(默认为 1 )
    • 形参
      • xTask任务句柄,NULL 代表任务自身(任务自身的句柄也可以作为参数)
      • uxNewPriority需要设置的任务优先级
    • 无返回值
  3. uxTaskGetNumberOfTasks()

    • 声明:UBaseType_t uxTaskGetNumberOfTasks( void )
    • 功能:此函数用于 获取系统中任务的任务数量
    • 无形参
    • 返回值
      • 系统中任务的数量(整数)
    • 注意:启动任务调度器之后,会自动创建空闲任务和软件定时器任务,这俩也算在内
  4. uxTaskGetSystemState()

    • 声明:

      c 复制代码
      UBaseType_t  uxTaskGetSystemState ( TaskStatus_t * const pxTaskStatusArray, 
                                         const UBaseType_t uxArraySize, 
                                         uint32_t * const pulTotalRunTime )
    • 功能:此函数用于 获取系统中所有任务的状态信息 ,存储信息用的是结构体数组(是一个数组,每个成员都是 TaskStatus_t 类型的结构体,数组大小取决于任务数量),一般也是**调试用**。使用该函数需将宏 configUSE_TRACE_FACILITY 置 1(默认为1)

    • 形参

      • xTaskStatusArray指向 TaskStatus_t 结构体数组的首地址的指针

        c 复制代码
        // 保存信息用的结构体数组的成员结构体组成如下:
        typedef struct xTASK_STATUS
        {
            TaskHandle_t 					xHandle;                    /* 任务句柄 */ 
            const char *		 			pcTaskName;             	/* 任务名 */ 
            UBaseType_t						xTaskNumber;                /* 任务编号(创建顺序) */ 
            eTaskStat						eCurrentState;           	/* 任务状态 */ 
            UBaseType_t 					uxCurrentPriority;          /* 任务优先级 */ 
            UBaseType_t 					uxBasePriority;             /* 任务原始优先级*/ 
            configRUN_TIME_COUNTER_TYPE 	ulRunTimeCounter; 			/* 任务运行时间,太短会显示0*/
            StackType_t * 					pxStackBase;                /* 任务栈基地址 */ 
            configSTACK_DEPTH_TYPE 			usStackHighWaterMark;  		/* 任务栈历史剩余最小值,字 */ 
        } TaskStatus_t;
      • uxArraySize:接收信息的数组大小

      • pulTotalRunTime:系统总运行时间,为 NULL 则省略总运行时间值

    • 返回值

      • 获取信息的任务数量(整数)
  5. vTaskGetInfo()

    • 声明:

      c 复制代码
      void vTaskGetInfo( TaskHandle_t 	xTask, 
      				   TaskStatus_t * 	pxTaskStatus, 
      				   BaseType_t 		xGetFreeStackSpace, 
      		    	   eTaskState 		eState )
    • 功能:此函数用于 获取指定的单个任务的状态信息 ,存储信息用的是 TaskStatus_t 类型的结构体。使用该函数需将宏 configUSE_TRACE_FACILITY 置 1(默认为1)

    • 形参

      • xTask:指定获取信息的任务的任务句柄

      • pxTaskStatus:指向存储任务状态信息的结构体变量( TaskStatus_t 结构体类型)的首地址的指针

      • xGetFreeStackSpace:任务栈历史剩余最小值,为 pdFALSE 则跳过这个步骤,为 pdTRUE 则检查历史剩余最小堆栈,并将查询结果包含在结构体中

      • eState:任务状态,可直接赋值,如想获取则代入 eInvalid

        这个任务状态其实是包含在 TaskStatus_t 结构体类型中的,也就是说查询的状态信息中有这个任务状态,但是查询任务状态会比较花时间,所以我们要是知道任务处于什么状态的话,就可以直接给这个变量赋值,然后查询信息时就会跳过任务状态的查询,从而节省时间。如果我们就是想查询一下任务状态,那么可以给 eState 赋值 eInvalid。

        任务状态(枚举类型)具体如下:

        c 复制代码
        typedef enum
        {   
        	eRunning = 0,	/* 运行态 */ 
        	eReady			/* 就绪态 */ 
        	eBlocked, 		/* 阻塞态 */ 
        	eSuspended, 	/* 挂起态 */ 
        	eDeleted, 		/* 任务被删除 */ 
        	eInvalid		/* 无效 */ 
        } eTaskState;

        因为 eRunning = 0,所以后面的按顺序为 1,2,...,5。

    • 无返回值

  6. xTaskGetCurrentTaskHandle()

    • 声明:TaskHandle_t xTaskGetCurrentTaskHandle( void )
    • 功能:此函数用于 获取当前任务的任务句柄使用该函数需将宏 INCLUDE_xTaskGetCurrentTaskHandle 置 1(默认为1)
    • 无形参
    • 返回值
      • TaskHandle_t当前任务的任务句柄( TCB 的首地址)
  7. xTaskGetHandle()

    • 声明:TaskHandle_t xTaskGetHandle(const char * pcNameToQuery)
    • 功能:此函数用于 通过任务名获取任务句柄使用该函数需将宏 INCLUDE_xTaskGetHandle 置 1(默认为1)
    • 形参
      • pcNameToQuery任务名,C语言字符串,其实就是创建任务的时候给的任务名
    • 返回值
      • TaskHandle_t:任务句柄( TCB 的首地址),为 NULL 就代表没有该任务名对应的任务
  8. uxTaskGetStackHighWaterMark()

    • 声明:UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask )
    • 功能:此函数用于 获取指定任务的历史最小剩余堆栈使用该函数需将宏 INCLUDE_uxTaskGetStackHighWaterMark 置 1
    • 形参
      • xTask:任务句柄
    • 返回值
      • UBaseType_t:任务栈的历史剩余最小值(以字为单位,STM32中,1字=4字节),值越小说明堆栈快不够了,如果已经溢出了,则会返回 0 。
  9. eTaskGetState()

    • 声明:eTaskState eTaskGetState(TaskHandle_t xTask)

    • 功能:此函数用于 查询某个任务的运行状态使用此函数需将宏 INCLUDE_eTaskGetState 置1(默认为1)

    • 形参

      • xTask:待获取状态任务的任务句柄
    • 返回值

      • eTaskState:任务状态

        任务状态(枚举类型)具体如下:

        c 复制代码
        typedef enum
        {   
        	eRunning = 0,	/* 运行态 */ 
        	eReady			/* 就绪态 */ 
        	eBlocked, 		/* 阻塞态 */ 
        	eSuspended, 	/* 挂起态 */ 
        	eDeleted, 		/* 任务被删除 */ 
        	eInvalid		/* 无效 */ 
        } eTaskState;

        因为 eRunning = 0,所以后面的按顺序为 1,2,...,5。

  10. vTaskList()

    • 声明:void vTaskList(char * pcWriteBuffer)

    • 功能:此函数用于 以表格的形式获取系统中任务的信息,比较简单、方便使用此函数需将宏 configUSE_TRACE_FACILITY 和configUSE_STATS_FORMATTING_FUNCTIONS 置 1(默认都是1)

    • 形参

      • pcWriteBuffer:指向保存任务信息的存储区的指针(数组名调用时为指针),保存任务壮态信息表的存储区,要足够大。

        保存的内容为:

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

        可直接使用 printf 打印(%s)

    • 无返回值

1.2)实验

① 实验目的: 学习 FreeRTOS 任务状态与信息的查询 API 函数

② 实验设计: 将设计三个任务:start_task、task1、task2,

这三个任务的功能如下:

  • start_task:用来创建 task1/task2 任务。
  • task1:LED0 每 500ms 闪烁一次,提示程序正在运行。
  • task2:用于展示任务状态信息查询相关 API 函数的使用。

③ 代码:

FreeRTOS_Code.c 文件代码如下:

c 复制代码
#include "sys.h" 
#include "delay.h" 
#include "usart.h" 
#include "led.h" 
#include "key.h"
#include "FreeRTOS.h" 
#include "task.h"
#include "FreeRTOS_Code.h"

/* ----------------------------------------------------------------------------------- */

#define START_TASK_PRIO  1           // 任务优先级 
#define START_STK_SIZE   128         // 任务堆栈大小  
TaskHandle_t StartTask_Handler;      // 任务句柄 
void start_task(void *pvParameters); // 任务函数 
 
#define TASK1_PRIO   2               // 任务优先级 
#define TSAK1_STK_SIZE    100        // 任务堆栈大小  
TaskHandle_t Task1_Handler;          // 任务句柄 
void task1(void *p_arg);             // 任务函数 
 
#define TASK2_PRIO   3               // 任务优先级 
#define TSAK2_STK_SIZE    100        // 任务堆栈大小  
TaskHandle_t Task2_Handler;          // 任务句柄 
void task2(void *p_arg);             // 任务函数 

char task_buff[500];                 // 保存信息存储区


/* ----------------------------------- 主函数 ---------------------------------------- */

void freertos_code(void)
{
    /* 创建开始任务 */
    xTaskCreate((TaskFunction_t  )start_task,           // 任务函数 
                (const char*     )"start_task",         // 任务名称 
                (uint16_t        )START_STK_SIZE,       // 任务堆栈大小 
                (void*           )NULL,                 // 传递给任务函数的参数 
                (UBaseType_t     )START_TASK_PRIO,      // 任务优先级 
                (TaskHandle_t*   )&StartTask_Handler);  // 任务句柄               
    vTaskStartScheduler();                              // 开启任务调度器 
}



/* ---------------------------------- 任务函数 --------------------------------------- */

/**
 * @brief       开始任务函数
 * @param       无
 * @retval      无
 */
void start_task(void *pvParameters) 
{ 
    taskENTER_CRITICAL();           // 进入临界区 -----------

    /* 创建 TASK1 任务 */
    xTaskCreate((TaskFunction_t  )task1,       
                (const char*     )"task1",     
                (uint16_t        )TSAK1_STK_SIZE,  
                (void*           )NULL,     
                (UBaseType_t     )TASK1_PRIO,  
                (TaskHandle_t*   )&Task1_Handler);

    /* 创建 TASK2 任务 */
    xTaskCreate((TaskFunction_t  )task2,       
                (const char*     )"task2",     
                (uint16_t        )TSAK2_STK_SIZE,  
                (void*           )NULL,     
                (UBaseType_t     )TASK2_PRIO,  
                (TaskHandle_t*   )&Task2_Handler);

    vTaskDelete(StartTask_Handler);   // 删除开始任务 
    
    taskEXIT_CRITICAL();            // 退出临界区 -----------
}


/**
 * @brief       TASK1 任务函数
 * @param       无
 * @retval      无
 * @note        每500ms翻转一次LED0
 */
void task1(void *pvParameters) 
{ 
    while(1) 
    { 
        LED0=!LED0;
        vTaskDelay(500); 
    } 
}


/**
 * @brief       TASK2 任务函数
 * @param       无
 * @retval      无
 * @note        实现任务状态查询API函数使用
 */
void task2(void *pvParameters) 
{
    /* 局部变量 */
    UBaseType_t task1_priority = 0;     // task1 任务优先级
    UBaseType_t task2_priority = 0;     // task2 任务优先级
    UBaseType_t task_num = 0;           // 任务数量
    TaskStatus_t * status_array = NULL; // 结构体指针(用来指向一块存放结构体数组的连续内存区域的首地址),先初始化为空指针
    UBaseType_t num_tasks = 0;          // 所有任务状态信息查询函数返回结果
    uint8_t i = 0;
    TaskStatus_t * status_single = NULL;// 结构体指针(用来指向一块存放单个结构体的连续内存区域的首地址),先初始化为空指针
    TaskHandle_t task_handle = 0;       // 通过任务名查询的任务句柄
    UBaseType_t task_stack_min = 0;     // 历史剩余最小堆栈
    eTaskState state = eInvalid;        // 任务状态
    char *Task_Status[]={"运行态","就绪态","阻塞态","挂起态","任务被删除","无效"};     // 任务状态显示字符串,只读
    
    printf("\r\n");
    
    /* ========================================== 函数调用 ========================================== */
    
    task1_priority = uxTaskPriorityGet( Task1_Handler );    // 获取 task1 的任务优先级
    printf("task1 任务优先级为:%ld\r\n",task1_priority);
    /* -------------------------------------------------------------------------------------------- */
    task2_priority = uxTaskPriorityGet( NULL );             // 获取当前任务 task2 的任务优先级
    printf("\r\ntask2 任务优先级为:%ld\r\n",task2_priority);
    /* -------------------------------------------------------------------------------------------- */
    vTaskPrioritySet( NULL, 10);                            // 设置 task2 的任务优先级为 10
    task2_priority = uxTaskPriorityGet( NULL );             
    printf("\r\n修改后 task2 的任务优先级为:%ld\r\n",task2_priority);
    /* -------------------------------------------------------------------------------------------- */
    task_num = uxTaskGetNumberOfTasks();                    // 获取任务数量(3+2)
    printf("\r\n任务数量为:%ld\r\n",task_num);
    /* -------------------------------------------------------------------------------------------- */
    status_array = (TaskStatus_t *)pvPortMalloc(sizeof(TaskStatus_t) * task_num);   // 动态分配内存(通过 FreeRTOS 自带的 pvPortMalloc )
    if (status_array != NULL)   // 检查是否分配成功(不再为NULL就是成功)
    {
        num_tasks = uxTaskGetSystemState(status_array, task_num, NULL);  // 获取所有任务的状态信息
        printf("\r\n%-16s %6s %6s %6s\r\n", "任务名", "优先级", "编号", "...");          // 打印前三个信息
        for (i = 0; i < num_tasks; i++)
        {
            // 使用固定宽度的格式化输出对齐
            printf("%-16s %4ld %6ld %8s\r\n", status_array[i].pcTaskName,
                                          status_array[i].uxCurrentPriority,
                                          status_array[i].xTaskNumber,
                                          "...");
        }
        vPortFree(status_array);    // 释放内存(重要!)
    }
    else
    {
        printf("Failed to allocate memory!\r\n"); // 处理内存分配失败
    }
    /* -------------------------------------------------------------------------------------------- */
    status_single = (TaskStatus_t *)pvPortMalloc(sizeof(TaskStatus_t));   // 动态分配内存(通过 FreeRTOS 自带的 pvPortMalloc )
    if (status_single != NULL)   // 检查是否分配成功(不再为NULL就是成功)
    {
        vTaskGetInfo(Task1_Handler, status_single, pdTRUE, eInvalid );          // 获取 task1 的状态信息
        printf("\r\n任务 %s 的优先级为 %ld ,任务编号为 %ld ,任务状态为 %d ,栈历史剩余最小值为 %d 字\r\n",status_single->pcTaskName, 
                                                                                                      status_single->uxCurrentPriority,
                                                                                                      status_single->xTaskNumber,
                                                                                                      status_single->eCurrentState,
                                                                                                      status_single->usStackHighWaterMark);
        vPortFree(status_single);    // 释放内存(重要!)
    }
    else
    {
        printf("Failed to allocate memory!\r\n"); // 处理内存分配失败
    }
    /* -------------------------------------------------------------------------------------------- */
    task_handle = xTaskGetHandle("task1");
    printf("\r\n通过任务名获取到的任务句柄为:%#x\r\n", (int)task_handle);     // %#x 表示以十六进制(小写)输出整数,并自动添加 0x 前缀
    /* -------------------------------------------------------------------------------------------- */
    task_stack_min = uxTaskGetStackHighWaterMark(Task2_Handler);
    printf("\r\ntask2 历史剩余最小堆栈为 %ld 字\r\n",task_stack_min);
    /* -------------------------------------------------------------------------------------------- */
    state = eTaskGetState(Task2_Handler);
    printf("\r\n当前 task2 的任务状态为:%s\r\n",Task_Status[state]);
    /* -------------------------------------------------------------------------------------------- */
    vTaskList( task_buff );
    printf("\r\n%s\r\n",task_buff);
    
    /* ============================================================================================ */
    
    while(1) 
    {
        vTaskDelay(1000);
    }
}

FreeRTOS_Code.h 文件代码如下:

c 复制代码
#ifndef __FREERTOS_CODE_H
#define __FREERTOS_CODE_H

void freertos_code(void);

#endif

main.c 文件代码如下:

c 复制代码
#include "sys.h" 
#include "delay.h" 
#include "usart.h" 
#include "led.h" 
#include "key.h"
#include "timer.h"
#include "FreeRTOS.h" 
#include "task.h"
#include "FreeRTOS_Code.h"

int main(void) 
{ 
    HAL_Init();
    sys_stm32_clock_init(RCC_PLL_MUL9);        // 设置时钟,72M
    delay_init(72);       // 延时函数初始化    
    usart_init(115200);   // 初始化串口 
    LED_Init();           // 初始化LED 
    KEY_Init();           // 按键初始化
//    TIM6_Init(4999,7199); // TIM6初始化,溢出时间为1s
//    TIM7_Init(4999,7199); // TIM7初始化,溢出时间为1s
 
    freertos_code();      //FreeRTOS代码
} 

④ 实验结果为:


相关推荐
Y1rong3 小时前
STM32之GPIO
stm32·单片机·嵌入式硬件
宵时待雨3 小时前
STM32笔记归纳2:GPIO
笔记·stm32·嵌入式硬件
π同学3 小时前
基于RT-Thread的STM32开发第十二讲SD卡篇——DFS文件系统
stm32·dfs·rtthread·sdio
一路往蓝-Anbo4 小时前
第37期:启动流程(二):C Runtime (CRT) 初始化与重定位
c语言·开发语言·网络·stm32·单片机·嵌入式硬件
c++逐梦人6 小时前
进程虚拟地址空间
linux·操作系统·进程
三伏5226 小时前
HAL_I2C_ER_IRQHandler函数解析
stm32·单片机·hal库
明洞日记6 小时前
【软考每日一练007】位图计算与内存管理深度全解
c++·算法·ai·操作系统·进程
想放学的刺客7 小时前
单片机嵌入式试题(第19期)嵌入式系统故障诊断与固件升级设计
c语言·stm32·嵌入式硬件·物联网·51单片机
一路往蓝-Anbo8 小时前
第46期:低功耗设计:软硬件协奏曲
驱动开发·stm32·单片机·嵌入式硬件