FreeRTOS系列第5篇---任务运行时间统计

前言

FreeRTOS 可以通过函数 vTaskGetRunTimeStats()来统计每个任务使用 CPU 的时间,以及所使用的时间占总时间的比例。在调试代码的时候我们可以根据这个时间使用值来分析哪个任务的 CPU 占用率高,然后合理的分配或优化任务。

使用

相关宏的设置

要使用此功能的话宏 configGENERATE_RUN_TIME_STATS 必须为 1,还需要在定义其他两个宏:portCONFIGURE_TIMER_FOR_RUN_TIME_STATS():配置一个高精度定时器/计数器提供时基。
portGET_RUN_TIME_COUNTER_VALUE():读取时基的时间值。具体代码如下:
这三个宏在 FreeRTOSConfig.h 中定义:

/***************************************************************************************************************/
/*                                FreeRTOS与运行时间和任务状态收集有关的配置选项                                 */
/***************************************************************************************************************/
#include "timer.h"
#define configGENERATE_RUN_TIME_STATS	        1                       //为1时启用运行时间统计功能
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()  ConfigureTimeForRunTimeStats()//定时器3提供时间统计的时基,频率为10K,即周期为100us
#define portGET_RUN_TIME_COUNTER_VALUE()		FreeRTOSRunTimeTicks	//获取时间统计时间值

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

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

函数 ConfigureTimeForRunTimeStats()其实就是初始化定时器,因为时间统计功能需要用户提供一个高精度的时钟,这里使用定时器 3。这个时钟的精度要比 FreeRTOS 的系统时钟高,大约 10~20 倍即可。举例来讲:FreeRTOS 系统时钟我们配置的是 1000HZ,周期 1ms,这里我们将定时器 3 的中断频率配置为 20KHZ,周期 50us,刚好是系统时钟频率的 20 倍。
系统时钟频率确定方法:
在delay.c中有关于滴答定时器的配置,如下:

void delay_init()
{
	u32 reload;
	SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);//选择外部时钟  HCLK
	fac_us=SystemCoreClock/1000000;				//不论是否使用OS,fac_us都需要使用
	reload=SystemCoreClock/1000000;				//每秒钟的计数次数 单位为M  
	reload*=1000000/configTICK_RATE_HZ;			//根据configTICK_RATE_HZ设定溢出时间
												//reload为24位寄存器,最大值:16777216,在72M下,约合0.233s左右	
	fac_ms=1000/configTICK_RATE_HZ;				//代表OS可以延时的最少单位	   

	SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;   	//开启SYSTICK中断
	SysTick->LOAD=reload; 						//每1/configTICK_RATE_HZ秒中断一次	
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk;   	//开启SYSTICK    
}	

在FreeRTOSConfig.h文件中,有关于时钟节拍频率的宏定义。

#define configTICK_RATE_HZ						(1000)                  //时钟节拍频率,这里设置为1000,周期就是1ms

关于定时器3的初始化函数和中断服务函数如下:

//通用定时器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 = 1;  //先占优先级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);  //清除中断标志位
}

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

vTaskGetRunTimeStats函数使用

相关宏配置好之后,就可以在任务中使用vTaskGetRunTimeStats来统计任务的运行时间。
该函数原型如下:

void vTaskGetRunTimeStats( char *pcWriteBuffer ) // 该函数耗时较长,因此用于调试软件,软件正式版,需要将其屏蔽掉。

在使用该函数时,需要有一段缓冲区来存储信息,该缓冲区最好定义为全局的,如果定义在任务块中,则会消耗任务堆栈大小。用法示例如下:

char RunTimeInfo[400];		//保存任务运行时间信息
//RunTimeStats任务
void RunTimeStats_task(void *pvParameters)
{
	u8 key=0;
	while(1)
	{
		key=KEY_Scan(0);
		if(key==WKUP_PRES)
		{
			memset(RunTimeInfo,0,400);				//信息缓冲区清零
			vTaskGetRunTimeStats(RunTimeInfo);		//获取任务运行时间信息
			printf("任务名\t\t\t运行时间\t运行所占百分比\r\n");
			printf("%s\r\n",RunTimeInfo);
		}
		vTaskDelay(10);                           	//延时10ms,也就是1000个时钟节拍	
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值