FreeRTOS任务运行时间信息统计

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档



提示:以下是本篇文章正文内容,下面案例可供参考

一、介绍

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

二、实验

1.配置

#define configGENERATE_RUN_TIME_STATS 1 
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()      ConfigureTimeForRunTimeStats()//:配置一个高精度定时器/计数器提供时基。
#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。前面在讲函数 vTaskGetRunTimeStats()的时候说过,
这个时钟的精度要比 FreeRTOS 的系统时钟高,大约 10~20 倍即可。FreeRTOS 系统时钟我们配
置的是 1000HZ,周期 1ms,这里我们将定时器 3 的中断频率配置为 20KHZ,周期 50us,刚好
是系统时钟频率的 20 倍。
定时器 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; 
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); //清除中断标志位
}

2.main.c

start_task:用来创建其他 3 个任务。
task1_task :应用任务 1,控制 LED0 灯闪烁,并且刷新 LCD 屏幕上指定区域的颜色。
task2_task :应用任务 2,控制 LED1 灯闪烁,并且刷新 LCD 屏幕上指定区域的颜色。
RunTimeStats_task:获取按键值,当 KEY_UP 键按下以后就调用函数 vTaskGetRunTimeStats()
获取任务的运行时间信息,并且将其通过串口输出到串口调试助手上。
实验需要一个按键 KEY_UP,用来获取系统中任务运行时间信息。


#define START_TASK_PRIO 1 //任务优先级
#define START_STK_SIZE 128 //任务堆栈大小
TaskHandle_t StartTask_Handler; //任务句柄
void start_task(void *pvParameters); //任务函数
#define TASK1_TASK_PRIO 2 //任务优先级
#define TASK1_STK_SIZE 128 //任务堆栈大小
TaskHandle_t Task1Task_Handler; //任务句柄
void task1_task(void *pvParameters); //任务函数
#define TASK2_TASK_PRIO 3 //任务优先级
#define TASK2_STK_SIZE 128 //任务堆栈大小
TaskHandle_t Task2Task_Handler; //任务句柄
void task2_task(void *pvParameters); //任务函数
#define RUNTIMESTATS_TASK_PRIO 4 //任务优先级
#define RUNTIMESTATS_STK_SIZE 128 //任务堆栈大小
TaskHandle_t RunTimeStats_Handler; //任务句柄
void RunTimeStats_task(void *pvParameters); //任务函数
char RunTimeInfo[400]; //保存任务运行时间信息



int main(void)
{
    
    
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组 4
delay_init(); //延时函数初始化
uart_init(115200); //初始化串口
LED_Init(); //初始化 LED
KEY_Init(); //初始化按键
LCD_Init(); //初始化 LCD
 POINT_COLOR = RED;
LCD_ShowString(30,10,200,16,16,"ATK STM32F103/407");
LCD_ShowString(30,30,200,16,16,"FreeRTOS Examp 11-2");
LCD_ShowString(30,50,200,16,16,"Get Run Time Stats");
LCD_ShowString(30,70,200,16,16,"ATOM@ALIENTEK");
LCD_ShowString(30,90,200,16,16,"2016/11/25");
 //创建开始任务
 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(); //进入临界区
 //创建 TASK1 任务
 xTaskCreate((TaskFunction_t )task1_task, 
 (const char* )"task1_task", 
 (uint16_t )TASK1_STK_SIZE, 
 (void* )NULL, 
 (UBaseType_t )TASK1_TASK_PRIO, 
 (TaskHandle_t* )&Task1Task_Handler); 
 //创建 TASK2 任务
 xTaskCreate((TaskFunction_t )task2_task, 
 (const char* )"task2_task", 
 (uint16_t )TASK2_STK_SIZE,
 (void* )NULL,
 (UBaseType_t )TASK2_TASK_PRIO,
 (TaskHandle_t* )&Task2Task_Handler); 
//创建 RunTimeStats 任务
xTaskCreate((TaskFunction_t )RunTimeStats_task, 
 (const char* )"RunTimeStats_task", 
 (uint16_t )RUNTIMESTATS_STK_SIZE,
 (void* )NULL,
 (UBaseType_t )RUNTIMESTATS_TASK_PRIO,
 (TaskHandle_t* )&RunTimeStats_Handler); 
 vTaskDelete(StartTask_Handler); //删除开始任务
 taskEXIT_CRITICAL(); //退出临界区
}


//task1 任务函数
void task1_task(void *pvParameters)
{
    
    
u8 task1_num=0;
POINT_COLOR = BLACK;
LCD_DrawRectangle(5,110,115,314); //画一个矩形
LCD_DrawLine(5,130,115,130); //画线
POINT_COLOR = BLUE;
LCD_ShowString(6,111,110,16,16,"Task1 Run:000");
while(1)
{
    
    
task1_num++; //任务执 1 行次数加 1 注意 task1_num1 加到 255 的时候会清零!!
LED0=!LED0;
LCD_Fill(6,131,114,313,lcd_discolor[task1_num%14]); //填充区域
LCD_ShowxNum(86,111,task1_num,3,16,0x80); //显示任务执行次数
 vTaskDelay(1000); //延时 1s,也就是 1000 个时钟节拍
}
}


//task2 任务函数
void task2_task(void *pvParameters)
{
    
    
u8 task2_num=0;
POINT_COLOR = BLACK;
LCD_DrawRectangle(125,110,234,314); //画一个矩形
LCD_DrawLine(125,130,234,130); //画线
POINT_COLOR = BLUE;
LCD_ShowString(126,111,110,16,16,"Task2 Run:000");
while(1)
{
    
    
task2_num++; //任务 2 执行次数加 1 注意 task1_num2 加到 255 的时候会清零!!
 LED1=!LED1;
LCD_ShowxNum(206,111,task2_num,3,16,0x80); //显示任务执行次数
LCD_Fill(126,131,233,313,lcd_discolor[13-task2_num%14]); //填充区域
 vTaskDelay(1000); //延时 1s,也就是 1000 个时钟节拍
}
}


//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); //获取任务运行时间信息 (1)
printf("任务名\t\t\t 运行时间\t 运行所占百分比\r\n");
printf("%s\r\n",RunTimeInfo); (2)
}
vTaskDelay(10); //延时 10ms,也就是 1000 个时钟节拍
}
}

3.结果

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/lianghuajunone/article/details/123493437