【FreeRtos任务运行时间统计】

本文详细介绍如何在FreeRTOS中利用vTaskGetRunTimeStats统计任务CPU使用时间,并通过配置高精度定时器优化任务调度。通过实例演示了宏设置、定时器配置和任务优先级管理,以提升代码调试效率。
摘要由CSDN通过智能技术生成

FreeRtos任务运行时间统计

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

1.相关宏设置

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

当我们将 configGENERATE_RUN_TIME_STATS 设置为1 后进行编译会报错提示我们要进行定义另外两个后

在这里插入图片描述

添加相关配置

在这里插入图片描述

函数 ConfigureTimeForRunTimeStats()其实就是初始化定时器,因为时间统计功能需要用户提供一个高精度的时钟,这里使用定时器 3。
这个时钟的精度要比 FreeRTOS 的系统时钟高,大约 10~20 倍即可。FreeRTOS 系统时钟我们配置的是 1000HZ,周期 1ms,这里我们将定时器 3 的中断频率配置为 20KHZ,周期 50us,刚好是系统时钟频率的 20 倍

2.定时器三配置

/*---------------------------TIME.C--------------------------*/
#include "time.h"
//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 
} 


//通用定时器 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; 
 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; 
 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM 向上计数模式 
 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); 
 
 TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的 TIM3 中断,允许更新中断 
 
 //中断优先级 NVIC 设置 
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3 中断 
 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //先占优先级 1 级 
 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //从优先级 0 级 
 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道被使能 
 NVIC_Init(&NVIC_InitStructure); //初始化 NVIC 寄存器 
 
 TIM_Cmd(TIM3, ENABLE); //使能 TIM3 
} 
 
//定时器 3 中断服务函数 
void TIM3_IRQHandler(void) 
{ 
	 if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET) //溢出中断 
	 { 
			FreeRTOSRunTimeTicks++; //运行时间统计时基计数器加一 
	 } 
	 TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //清除中断标志位 
} 
/*-------------------------------TIME.H---------------------------*/
#ifndef _TIME_H_
#define _TIME_H_

#include "stm32f10x.h"
void TIM3_Int_Init(u16 arr,u16 psc) ;

void ConfigureTimeForRunTimeStats(void) ;
extern volatile unsigned long long FreeRTOSRunTimeTicks;
#endif

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

通过上面定时器三的配置及中断功能就将获取时间所需的准备完成了,下面在主函数进行任务时间统计输出。

main.c

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"
#include "time.h"


//任务优先级
#define START_TASK_PRIO		1
//任务堆栈大小	
#define START_STK_SIZE 		128  
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);

//任务优先级
#define LED0_TASK_PRIO		2
//任务堆栈大小	
#define LED0_STK_SIZE 		50  
//任务句柄
TaskHandle_t LED0Task_Handler;
//任务函数
void led0_task(void *pvParameters);

//任务优先级
#define RUNTIME_TASK_PRIO		3
//任务堆栈大小	
#define RUNTIME_STK_SIZE 		256
//任务句柄
TaskHandle_t RUNTIMETask_Handler;
//任务函数
void runtime_task(void *pvParameters);

char InfoBuffer[1024];  //缓存读取的任务运行时间

int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4	 
	delay_init();	    				//延时函数初始化	  
	uart_init(115200);					//初始化串口
	LED_Init();		  					//初始化LED
	 
	//创建开始任务
    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();          //开启任务调度
}

//开始任务任务函数
void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           //进入临界区
    //创建LED0任务
    xTaskCreate((TaskFunction_t )led0_task,     	
                (const char*    )"led0_task",   	
                (uint16_t       )LED0_STK_SIZE, 
                (void*          )NULL,				
                (UBaseType_t    )LED0_TASK_PRIO,	
                (TaskHandle_t*  )&LED0Task_Handler);   
    //创建LED1任务
    xTaskCreate((TaskFunction_t )runtime_task,     
                (const char*    )"runtime_task",   
                (uint16_t       )RUNTIME_STK_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )RUNTIME_TASK_PRIO,
                (TaskHandle_t*  )&RUNTIMETask_Handler);         
    vTaskDelete(StartTask_Handler); //删除开始任务
    taskEXIT_CRITICAL();            //退出临界区
}


void led0_task(void *pvParameters)
{

    while(1)
    {
		LED0=~LED0;
       vTaskDelay(500);
			 // printf("led1 is running\r\n");			
    }
}   

//runtime任务函数
void runtime_task(void *pvParameters)
{
	while(1)
    {       
		vTaskGetRunTimeStats(InfoBuffer)
		printf("InfoBuffer:%s\r\n",InfoBuffer);
		delay_ms(1000);
			 
    }
}

实验结果

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小殷学长

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值