欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

FreeRTOS 学习笔记 - 基于 stm32 (7) 任务状态查询和任务时间统计 API 函数

最编程 2024-06-02 16:18:10
...

1、FreeRTOS任务相关API函数

函数 描述
uxTaskPriorityGet() 查询某个任务的优先级
vTaskPrioritySet() 改变某个任务的任务优先级
uxTaskGetSystemState() 获取系统中任务状态
vTaskGetInfo() 获取某个任务信息
xTaskGetApplicationTaskTag() 获取某个任务的标签(Tag)值
xTaskGetCurrentTaskHandle() 获取当前正在运行的任务的任务句柄
xTaskGetHandle() 根据任务名字查找某个任务的句柄
xTaskGetIdleTaskHandle() 获取空闲任务的任务句柄
uxTaskGetStackHighWaterMark() 获取任务的堆栈的历史剩余最小值,FreeRTOS 中叫做“高 水位线”
eTaskGetState() 获取某个任务的壮态,这个壮态是 eTaskState 类型
pcTaskGetName() 获取某个任务的任务名字
xTaskGetTickCount() 获取系统时间计数器值
xTaskGetTickCountFromISR() 在中断服务函数中获取时间计数器值
xTaskGetSchedulerState() 获取任务调度器的壮态,开启或未开启
uxTaskGetNumberOfTasks() 获取当前系统中存在的任务数量
vTaskList() 以一种表格的形式输出当前系统中所有任务的详细信 息
vTaskGetRunTimeStats() 获取每个任务的运行时间
vTaskSetApplicationTaskTag() 设置任务标签(Tag)值。
SetThreadLocalStoragePointer() 设置线程本地存储指针
GetThreadLocalStoragePointer() 获取线程本地存储指针

2、任务相关API函数的使用

        使用每个API函数的时候,都右键转到定义位置,如下图:

        然后查看函数的使用条件,比如这个函数要使用的话必须将宏 INCLUDE_uxTaskPriorityGet 置1;

        然后以同样的操作转到这个宏的位置将其置1。然后再开始调用API函数

        如下为几个常用API函数的使用:

	uint8_t i=0;
	UBaseType_t priority_num=0;
	UBaseType_t task_num=0;
	UBaseType_t task_num2=0;
	TaskStatus_t * status_array=0;
	TaskStatus_t * status_array2=0;
	TaskHandle_t task_handle=0;
	UBaseType_t task_stack_min=0;
	eTaskState task_state=0;
	char pcWriteBuffer[300];
	
	//获取任务优先级
	priority_num = uxTaskPriorityGet( task2_handler );
	printf("task2的任务优先级=%ld\r\n",priority_num);
	
	//设置任务优先级
	vTaskPrioritySet( task2_handler,6 );
	priority_num = uxTaskPriorityGet( task2_handler );
	printf("task2的任务优先级=%ld\r\n",priority_num);
	
	//获取系统任务数量
	task_num = uxTaskGetNumberOfTasks();
	printf("系统任务数量=%ld\r\n",task_num);
	
	//获取系统所有任务的任务状态信息
	status_array=pvPortMalloc(sizeof(TaskStatus_t)*task_num);
	task_num2 = uxTaskGetSystemState(status_array,task_num,NULL);
	printf("任务名\t\t任务优先级\t\t任务编号\r\n");
	for(i=0;i<task_num2;i++){
		printf("%s\t\t%ld\t%ld\r\n",status_array[i].pcTaskName,
									status_array[i].uxCurrentPriority,
									status_array[i].xTaskNumber);
	}
	
	//获取指定任务的任务状态
	status_array2=pvPortMalloc(sizeof(TaskStatus_t));
	vTaskGetInfo(task2_handler,status_array2,pdTRUE,eInvalid);
	printf("任务名:%s\r\n",status_array2->pcTaskName);
	printf("任务优先级:%ld\r\n",status_array2->uxCurrentPriority);
	printf("任务编号:%ld\r\n",status_array2->xTaskNumber);
	printf("任务状态:%d\r\n",status_array2->eCurrentState);
	
	//根据任务名获取任务句柄
	task_handle = xTaskGetHandle("task2");
	printf("任务句柄为:%#x\r\n",(int)task_handle);
	printf("任务句柄为:%#x\r\n",(int)task2_handler);
	
	//查询某个任务的运行状态
	task_state = eTaskGetState(task2_handler);
	printf("task2的任务状态为%d\r\n",task_state);
	
	//获取系统中任务信息
	vTaskList(pcWriteBuffer);
	printf("%s\r\n",pcWriteBuffer);

3、任务时间统计API函数 vTaskGetRunTimeStats()

void vTaskGetRunTimeStats( char *pcWriteBuffer )

        该函数与获取系统任务信息类似,参数是一个数组用来存放任务信息。如下代码是统计系统任务的运行时间并打印出来。

void task2( void * pvParameters )
{
	u8 key=0;
	while(1)
	{
		key=KEY_Scan(0);
		if(key==KEY1_PRES){
			vTaskGetRunTimeStats(pcWriteBuffer);
			printf("任务名\t\t\t运行时间\t运行所占百分比\r\n");
			printf("%s\r\n",pcWriteBuffer);
		}
		vTaskDelay(100);
	}
}

        使用该函数需要注意的点:

        1、需要将宏 configGENERATE_RUN_TIME_STATS 置1;

        2、需要将宏 configUSE_STATS_FORMATTING_FUNCTIONS 置1;

        3、在将1完成后需要实现 portCONFIGURE_TIMER_FOdR_RUN_TIME_STATS() 宏和 portGET_RUN_TIME_COUNTER_VALUE() 宏;

        portCONFIGURE_TIMER_FOdR_RUN_TIME_STATS() 用来初始化用于配置任务运行时间统计的时基定时器,时基定时器的精度必须高于系统时钟节拍精度的10到100倍。系统时钟节拍如果是1ms,时基定时器节拍就得在10us到100us之间。

        portGET_RUN_TIME_COUNTER_VALUE() 用于获取定时器计数的计数值。

         定时器使用stm32的内部定时器3,在 ConfigureTimeForRunTimeStats() 中初始化定时器并配置为每10us中断一次,然后在中断服务函数中将 FreeRTOSRunTimeTicks++,从而达到计时的目的。宏的实现如下代码:

timer.c:

#include "timer.h"
#include "led.h"
#include "led.h"
#include "usart.h"

volatile unsigned long long FreeRTOSRunTimeTicks;

//初始化TIM3使其为FreeRTOS的时间统计提供时基
void ConfigureTimeForRunTimeStats(void)
{
	//定时器3初始化,定时器时钟为72M,分频系数为72-1,所以定时器3的频率
	//为72M/72=1M,自动重装载为10-1,那么定时器周期就是10us
	FreeRTOSRunTimeTicks=0;
	TIM3_Int_Init(10-1,72-1);	//初始化TIM3
}

//通用定时器3中断初始化
//这里时钟选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
//这里使用的是定时器3!
void TIM3_Int_Init(u16 arr,u16 psc)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
	
	//定时器TIM3初始化
	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
 
	TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断

	//中断优先级NVIC设置
	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 4;  //先占优先级4级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  //从优先级0级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
	NVIC_Init(&NVIC_InitStructure);  //初始化NVIC寄存器

	TIM_Cmd(TIM3, ENABLE);  //使能TIMx					 
}

//定时器3中断服务函数
void TIM3_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET) //溢出中断
	{
		FreeRTOSRunTimeTicks++;
	}
	TIM_ClearITPendingBit(TIM3,TIM_IT_Update);  //清除中断标志位
}

timer.h:

#ifndef __TIMER_H
#define __TIMER_H
#include "sys.h" 

void ConfigureTimeForRunTimeStats(void);
extern volatile unsigned long long FreeRTOSRunTimeTicks;
void TIM3_Int_Init(u16 arr,u16 psc);
void TIM5_Int_Init(u16 arr,u16 psc);
#endif

推荐阅读