一、基本概念

CPU 使用率其实就是系统运行的程序占用的 CPU 资源,表示机器在某段时间程序运行的情况,如果这段时间中,程序一直在占用 CPU 的使用权,那么可以人为 CPU 的利用率是 100%。CPU 的利用率越高,说明机器在这个时间上运行了很多程序,反之较少。利用率的高低与 CPU 强弱有直接关系,就像一段一模一样的程序,如果使用运算速度很慢的 CPU,它可能要运行 1000ms,而使用很运算速度很快的 CPU 可能只需要 10ms,那么在 1000ms 这段时间中,前者的 CPU 利用率就是 100%,而后者的 CPU 利用率只有 1%,因为 1000ms 内前者都在使用 CPU 做运算,而后者只使用 10ms 的时间做运算,剩下的时间 CPU 可以做其他事情。

FreeRTOS 是多任务操作系统,对 CPU 都是分时使用的:比如 A 任务占用 10ms,然后 B 任务占用 30ms,然后空闲 60ms,再又是 A 任务占 10ms,B 任务占 30ms,空闲 60ms;

二、CPU利用率统计

在调试的时候很有必要得到当前系统的 CPU 利用率相关信息,但是在产品发布的时候,就可以把 CPU 利用率统计这个功能去掉,因为使用任何功能的时候,都是需要消耗系统资源的,FreeRTOS 是使用一个外部的变量进行统计时间的,并且消耗一个高精度的定时器,其用于定时的精度是系统时钟节拍的 10-20 倍,比如当前系统时钟节拍是 1000HZ,那么定时器的计数节拍就要是 10000-20000HZ。而且 FreeRTOS 进行 CPU 利用率统计的时候,也有一定缺陷,因为它没有对进行 CPU 利用率统计时间的变量做溢出保护,我们使用的是 32 位变量来系统运行的时间计数值,而按 20000HZ 的中断频率计算,每进入一中断就是 50us,变量加一,最大支持计数时间:2^32 * 50us / 3600s = 59.6 分钟,运行时间超过了 59.6 分钟后统计的结果将不准确,除此之外整个系统一直响应定时器 50us 一次的中断会比较影响系统的性能。

三、配置选项

FreeRTOSConfig.h 配置与系统运行时间和任务状态收集有关的配置选项,并且实现
portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()portGET_RUN_TIME_COUNTER_VALUE() 这两个宏定义

/********************************************************************
FreeRTOS 与运行时间和任务状态收集有关的配置选项
**********************************************************************/
//启用运行时间统计功能
#define configGENERATE_RUN_TIME_STATS 1
//启用可视化跟踪调试
#define configUSE_TRACE_FACILITY 1
/* 与宏 configUSE_TRACE_FACILITY 同时为 1 时会编译下面 3 个函数
* prvWriteNameToBuffer()
* vTaskList(),
* vTaskGetRunTimeStats()
*/
#define configUSE_STATS_FORMATTING_FUNCTIONS 1extern volatile uint32_t CPU_RunTime; #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() (CPU_RunTime = 0ul)
#define portGET_RUN_TIME_COUNTER_VALUE() CPU_RunTime

然后需要实现一个中断频率为 20000HZ 定时器,用于系统运行时间统计,其实很简单,只需将 CPU_RunTime 变量自加即可,这个变量是用于记录系统运行时间的,中断服务函数见下

/* 用于统计运行时间 */
volatile uint32_t CPU_RunTime = 0UL;void BASIC_TIM_IRQHandler (void)
{if(TIM_GetITStatus( BASIC_TIM, TIM_IT_Update) != RESET ) {CPU_RunTime++; TIM_ClearITPendingBit(BASIC_TIM , TIM_FLAG_Update);}
}

然后我们就可以在任务中调用 vTaskGetRunTimeStats()vTaskList() 函数获得任务的相关信息与 CPU 使用率的相关信息,然后打印出来即可

memset(CPU_RunInfo,0,400); //信息缓冲区清零vTaskList((char *)&CPU_RunInfo); //获取任务运行时间信息 printf("---------------------------------------------\r\n");
printf("任务名 任务状态 优先级 剩余栈 任务序号\r\n");
printf("%s", CPU_RunInfo);
printf("---------------------------------------------\r\n");memset(CPU_RunInfo,0,400); //信息缓冲区清零vTaskGetRunTimeStats((char *)&CPU_RunInfo); printf("任务名 运行计数 使用率\r\n");
printf("%s", CPU_RunInfo);
printf("---------------------------------------------\r\n\n");

四、示例

/* FreeRTOS头文件 */
#include "FreeRTOS.h"
#include "task.h"
/* 开发板硬件bsp头文件 */
#include "bsp_led.h"
#include "bsp_usart.h"
#include "bsp_TiMbase.h"
#include "string.h"/**************************** 任务句柄 ********************************/
/* * 任务句柄是一个指针,用于指向一个任务,当任务创建好之后,它就具有了一个任务句柄* 以后我们要想操作这个任务都需要通过这个任务句柄,如果是自身的任务操作自己,那么* 这个句柄可以为NULL。*//* 创建任务句柄 */
static TaskHandle_t AppTaskCreate_Handle = NULL;
/* LED任务句柄 */
static TaskHandle_t LED1_Task_Handle = NULL;
static TaskHandle_t LED2_Task_Handle = NULL;
static TaskHandle_t CPU_Task_Handle = NULL;/*
*************************************************************************
*                             函数声明
*************************************************************************
*/
static void AppTaskCreate(void);/* 用于创建任务 */static void LED1_Task(void* pvParameters);/* LED1_Task任务实现 */
static void LED2_Task(void* pvParameters);/* LED2_Task任务实现 */
static void CPU_Task(void* pvParameters);/* CPU_Task任务实现 */
static void BSP_Init(void);/* 用于初始化板载相关资源 *//****************************************************************** @brief  主函数* @param  无* @retval 无* @note   第一步:开发板硬件初始化 第二步:创建APP应用任务第三步:启动FreeRTOS,开始多任务调度****************************************************************/
int main(void)
{   BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS *//* 开发板硬件初始化 */BSP_Init();/* 创建AppTaskCreate任务 */xReturn = xTaskCreate((TaskFunction_t )AppTaskCreate,  /* 任务入口函数 */(const char*    )"AppTaskCreate",/* 任务名字 */(uint16_t       )512,  /* 任务栈大小 */(void*          )NULL,/* 任务入口函数参数 */(UBaseType_t    )1, /* 任务的优先级 */(TaskHandle_t*  )&AppTaskCreate_Handle);/* 任务控制块指针 */ /* 启动任务调度 */           if(pdPASS == xReturn){vTaskStartScheduler();   /* 启动任务,开启调度 */}else{return -1;  }while(1);   /* 正常不会执行到这里 */
}/************************************************************************ @ 函数名  : AppTaskCreate* @ 功能说明: 为了方便管理,所有的任务创建函数都放在这个函数里面* @ 参数    : 无  * @ 返回值  : 无**********************************************************************/
static void AppTaskCreate(void)
{BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */taskENTER_CRITICAL();           //进入临界区/* 创建LED_Task任务 */xReturn = xTaskCreate((TaskFunction_t )LED1_Task, /* 任务入口函数 */(const char*    )"LED1_Task",/* 任务名字 */(uint16_t       )512,   /* 任务栈大小 */(void*          )NULL,  /* 任务入口函数参数 */(UBaseType_t    )2,       /* 任务的优先级 */(TaskHandle_t*  )&LED1_Task_Handle);/* 任务控制块指针 */if(pdPASS == xReturn){printf("创建LED1_Task任务成功!\r\n");}/* 创建LED_Task任务 */xReturn = xTaskCreate((TaskFunction_t )LED2_Task, /* 任务入口函数 */(const char*    )"LED2_Task",/* 任务名字 */(uint16_t       )512,   /* 任务栈大小 */(void*          )NULL,  /* 任务入口函数参数 */(UBaseType_t    )3,       /* 任务的优先级 */(TaskHandle_t*  )&LED2_Task_Handle);/* 任务控制块指针 */if(pdPASS == xReturn){printf("创建LED2_Task任务成功!\r\n");}/* 创建LED_Task任务 */xReturn = xTaskCreate((TaskFunction_t )CPU_Task, /* 任务入口函数 */(const char*    )"CPU_Task",/* 任务名字 */(uint16_t       )512,   /* 任务栈大小 */(void*          )NULL,    /* 任务入口函数参数 */(UBaseType_t    )4,       /* 任务的优先级 */(TaskHandle_t*  )&CPU_Task_Handle);/* 任务控制块指针 */if(pdPASS == xReturn){printf("创建CPU_Task任务成功!\r\n");}vTaskDelete(AppTaskCreate_Handle); //删除AppTaskCreate任务taskEXIT_CRITICAL();            //退出临界区
}/*********************************************************************** @ 函数名  : LED_Task* @ 功能说明: LED_Task任务主体* @ 参数    :   * @ 返回值  : 无********************************************************************/
static void LED1_Task(void* parameter)
{   while (1){LED1_ON;vTaskDelay(500);   /* 延时500个tick */printf("LED1_Task Running,LED1_ON\r\n");LED1_OFF;     vTaskDelay(500);   /* 延时500个tick */                printf("LED1_Task Running,LED1_OFF\r\n");}
}static void LED2_Task(void* parameter)
{   while (1){LED2_ON;vTaskDelay(300);   /* 延时500个tick */printf("LED2_Task Running,LED2_ON\r\n");LED2_OFF;     vTaskDelay(300);   /* 延时500个tick */                printf("LED2_Task Running,LED2_OFF\r\n");}
}static void CPU_Task(void* parameter)
{   uint8_t CPU_RunInfo[400];       //保存任务运行时间信息while (1){memset(CPU_RunInfo,0,400);                //信息缓冲区清零vTaskList((char *)&CPU_RunInfo);  //获取任务运行时间信息printf("---------------------------------------------\r\n");printf("任务名      任务状态 优先级   剩余栈 任务序号\r\n");printf("%s", CPU_RunInfo);printf("---------------------------------------------\r\n");memset(CPU_RunInfo,0,400);              //信息缓冲区清零vTaskGetRunTimeStats((char *)&CPU_RunInfo);printf("任务名       运行计数         利用率\r\n");printf("%s", CPU_RunInfo);printf("---------------------------------------------\r\n\n");vTaskDelay(1000);   /* 延时500个tick */     }
}/************************************************************************ @ 函数名  : BSP_Init* @ 功能说明: 板级外设初始化,所有板子上的初始化均可放在这个函数里面* @ 参数    :   * @ 返回值  : 无*********************************************************************/
static void BSP_Init(void)
{/** STM32中断优先级分组为4,即4bit都用来表示抢占优先级,范围为:0~15* 优先级分组只需要分组一次即可,以后如果有其他的任务需要用到中断,* 都统一用这个优先级分组,千万不要再分组,切忌。*/NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );/* LED 初始化 */LED_GPIO_Config();/* 串口初始化  */USART_Config();/* 基本定时器初始化    */BASIC_TIM_Init();
}


• 由 Leung 写于 2021 年 1 月 5 日

• 参考:野火FreeRTOS视频与PDF教程

FreeRTOS学习笔记(11)——CPU使用率统计相关推荐

  1. freeRtos学习笔记 (9) 移植和CPU利用率统计

    freeRtos学习笔记 (9) 移植和CPU利用率统计 使用官方固件移植 首先准备一个能跑的裸机工程 注意,freertos需要使用systick定时器,而stm32HAL库默认使用systick作 ...

  2. FreeRtos学习笔记(11)查找就绪任务中优先级最高任务原理刨析

    FreeRtos学习笔记(11)查找就绪任务中优先级最高任务原理刨析 怎么查找就绪任务中优先级最高的? tasks.c中声明了一个全局变量 uxTopReadyPriority,任务从其他状态进入就绪 ...

  3. 1、野火freertos学习笔记

    野火freertos学习笔记 1.任务 1.1 栈 1.2 任务的切换 taskYIELD(); 1.3 临界段 2.空闲任务 3.任务优先级 4.任务延时的表现 5.时间片 5.1抢占式.协做式 6 ...

  4. FreeRTOS学习笔记

    FreeRTOS学习笔记 (这是我自己学习FreeRTOS整理的笔记,仅供参考) 第一部分:实现FreeRTOS内核 变量名: 定义变量时往往会把变量的类型当作前缀加在变量上 变量类型 前缀 char ...

  5. FreeRTOS学习笔记20200526

    FreeRTOS学习笔记-Day1-20200526 nFlag = TRUE; 先立个Flag,是时候点亮嵌入式实时操作系统这个技能了.座右铭:坚持.认真.沉静.笃行. FreeRTOS优势 总结F ...

  6. freeRtos学习笔记 (6)软件定时器

    freeRtos学习笔记 freeRtos软件定时器 软件定时器需要注意事项 软件定时器的精度基于时钟节拍,例如系统时钟节拍为10ms, 软件定时器定时时间必须是10ms的整数倍,因此软件定时器一般用 ...

  7. Hadoop学习笔记—11.MapReduce中的排序和分组

    Hadoop学习笔记-11.MapReduce中的排序和分组 一.写在之前的 1.1 回顾Map阶段四大步骤 首先,我们回顾一下在MapReduce中,排序和分组在哪里被执行: 从上图中可以清楚地看出 ...

  8. 点云学习笔记11——VoxelNet算法+代码运行

    点云学习笔记11--VoxelNet算法+代码运行 一.算法分析 摘要 介绍 相关工作 1.2. 贡献 2.VoxelNet 2.1.特征学习网络 2.1.1 特征学习网络 二.代码复现 2.1.环境 ...

  9. SpringMVC:学习笔记(11)——依赖注入与@Autowired

    SpringMVC:学习笔记(11)--依赖注入与@Autowired 使用@Autowired 从Spring2.5开始,它引入了一种全新的依赖注入方式,即通过@Autowired注解.这个注解允许 ...

  10. freeRtos学习笔记 (8) 任务通知

    freeRtos学习笔记 freeRtos任务通知 任务通知的优缺点 freeRtos任务控制块中包含两个32位的变量,用于任务通知,在一些情况下,任务通知可以替代信号量和事件组,并且比信号量和事件组 ...

最新文章

  1. opencv-python之机器视觉
  2. C语言博客作业--嵌套循环
  3. Java Web 之Token+Cookie+Session
  4. php access allow,PHP标头不适用于Access-Control-Allow-Origin
  5. 微软游戏开发工具XNA 2.0[转自驱动之家]
  6. C语言课后习题(37)
  7. git clone 添加代理_用树莓派3搭建私有git代码仓库
  8. JavaScript之子类构建工具
  9. php onchange,将PHP变量传递给ONCHANGE事件上的javascript
  10. window10设置文件夹备注
  11. uniapp 发布网站遇到的问题(跨域,nginx代理失败,index无法打开,手机端无法访问等)
  12. python实现带头结点的单链表的就地逆置_带头结点的单链表就地逆置 (10 分)...
  13. FileNet小错误汇总
  14. 计算机控制系统在电厂的应用,计算机控制系统在电厂中的应用.doc
  15. code review流程规范
  16. Window取消快捷方式箭头(脚本方式)
  17. Qt QSetting 读写ini配置文件(简单明了,多图)
  18. python中用于绘制各种图形、标注文本_在python中的图形上绘制常量文本-问答-阿里云开发者社区-阿里云...
  19. 贪心——绝对值不等式——货仓选址
  20. 免费cocos2dx3.x视频教程

热门文章

  1. 基于拉格朗日差值算法的BMP图像缩放
  2. B024 – STM32温湿度控制体温检测烟雾报警系统
  3. Flutter(十七) 实现国际化
  4. [日常] 修改编辑word中的页眉页脚
  5. 【教程】用微信创建生日提醒
  6. Python初学者之路--range函数、切片、if-elif语句
  7. Mac下的平铺式桌面 - Yabai
  8. 我的Python心路历程 第十期 (10.5 股票实战之数据可视化曲线)
  9. [COGS2479]偏序
  10. Learn Git Branching 笔记