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);
}
}
实验结果