9-FreeRTOS API获取任务使用CPU时间
获取CPU时间的API:
vTaskGetRunTimeStats() 获取任务运行时间信息,此函数会统计任务的运行时间,并且将统计到的运行时间信息按照表格的形式组织在一起并存放在用户设置的缓冲区里面,缓冲区的首地址通过参数传递给函数 vTaskGetRunTimeStats()。
获取前期准备:
(1)开启宏configGENERATE_RUN_TIME_STATS 1
(2)实现两个宏
① 配置一个高精度定时器/计数器提供时基,因为时间统计功能需要用户提供一个高精度的时钟,这里使用定时器 3。这个时钟的精度要比 FreeRTOS 的系统时钟高,大约 10~20 倍即可
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() ConfigureTimeForRunTimeStats() //函数 ConfigureTimeForRunTimeStats()其实就是初始化定时器
② 读取时基时间值
#define portGET_RUN_TIME_COUNTER_VALUE() FreeRTOSRunTimeTicks
实验代码:
①时基的实现:
//FreeRTOS时间统计所用的节拍计数器 volatile unsigned long long FreeRTOSRunTimeTicks; //初始化TIM3使其为FreeRTOS的时间统计提供时基 void ConfigureTimeForRunTimeStats(void) { //为72M/72=1M,自动重装载为50-1,那么定时器周期就是50us FreeRTOSRunTimeTicks=0; TIM6_Time_Init(50-1,72-1); //初始化TIM6 } //1/(72 000 000÷psc)×arr~5ms void TIM6_Time_Init(u16 arr,u16 psc)//如arr=49 psc=7199 ---10khz(0.1ms)--5ms { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6,ENABLE); //72M NVIC_InitStructure.NVIC_IRQChannel =TIM6_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 4; //抢占优先级 NVIC_InitStructure.NVIC_IRQChannelSubPriority= 0; //响应优先级 NVIC_InitStructure.NVIC_IRQChannelCmd =ENABLE; NVIC_Init(&NVIC_InitStructure); TIM_TimeBaseStructure. TIM_Period = arr;//自动重装值 TIM_TimeBaseStructure.TIM_Prescaler =psc; //时钟预分频数 TIM_TimeBaseInit(TIM6,&TIM_TimeBaseStructure); //初始化TIM6 TIM_ClearFlag(TIM6,TIM_FLAG_Update); //清除计数器中断标志位 TIM_ITConfig(TIM6,TIM_IT_Update, ENABLE );//TIM中断使能 TIM_Cmd(TIM6, ENABLE); //使能定时器 } void TIM6_IRQHandler(void) { if(TIM_GetITStatus(TIM6, TIM_IT_Update)) //是否产生中断 { FreeRTOSRunTimeTicks++; //FreeRTOS时间统计所用的节拍计数器 TIM_ClearITPendingBit(TIM6,TIM_IT_Update);//清除中断标志位 } }
②基本功能,按下按键串口打印出每个任务所占用的CPU时间
//----------------------------------------任务优先级 #define START_TASK_PRIO 1 #define TASK1_PRIO 2 #define TASK2_PRIO 3 //优先级高 //----------------------------------------任务堆栈大小 #define START_STK_SIZE 128 #define TASK1_STK_SIZE 128 #define TASK2_STK_SIZE 256 //----------------------------------------任务句柄 TaskHandle_t Task1_Handler; TaskHandle_t Task2_Handler; TaskHandle_t StartTask_Handler; //----------------------------------------任务函数 void start_task(void *pvParameters); void task1_task(void *pvParameters); void task2_task(void *pvParameters); char InfoBuffer[1000]; //保存信息的数组 int main(void) { BaseType_t OS; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); User_GPIO_Init(); Delay_init(); USART_Config(); OS= xTaskCreate( (TaskFunction_t ) start_task, //任务函数 (const char * ) "start_task", //任务名 (configSTACK_DEPTH_TYPE) START_STK_SIZE, //堆栈大小 (void * )NULL, //传递给任务函数的参数 (UBaseType_t ) START_TASK_PRIO, //任务优先级 (TaskHandle_t * ) &StartTask_Handler //任务句柄 ); if(OS==pdPASS) GPIO_SetBits(GPIOA, GPIO_Pin_8); 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_PRIO, //任务优先级 (TaskHandle_t* )&Task1_Handler); //任务句柄 xTaskCreate((TaskFunction_t )task2_task, //任务函数 (const char* )"task2_task", //任务名称 (uint16_t )TASK2_STK_SIZE, //任务堆栈大小 (void* )NULL, (UBaseType_t )TASK2_PRIO, //任务优先级 (TaskHandle_t* )&Task2_Handler); //任务句柄 vTaskDelete(StartTask_Handler); //vTaskDelete(NULL)也可以 删除开始任务 taskEXIT_CRITICAL(); //退出临界区 } //任务1 void task1_task(void *pvParameters) { while(1) { vTaskDelay(5000); //vTaskDelay delay_xms不发生任务切换 } } //任务2 void task2_task(void *pvParameters) { uint8_t key=0; while(1) { key=KEY_Scan(); if(key==TASK2_SUSPEND) { printf("按下\n"); memset(InfoBuffer,0,1000); //信息缓冲区清零 vTaskGetRunTimeStats(InfoBuffer); //获取任务运行时间信息 printf("任务名\t\t运行时间\t运行所占百分比\r\n"); printf("%s\r\n",InfoBuffer); } vTaskDelay(10); //延时10ms,也就是1000个时钟节拍 } }
执行结果:
vTaskGetRunTimeStats()相对来说会很耗时间,所以不要太过于频繁的调用此函数,测试阶段可以使用此函数来分析任务的运行情况。 还有就是运行时间不是真正的运行时间,真正的时间值要乘以 100us
因为上面实现的时基为100us, FreeRTOS的时基为1ms,正好是其精度的10倍。
posted on 2021-01-12 16:06 Darren_pty 阅读(1993) 评论(0) 编辑 收藏 举报