FreeRTOS没有CPU使用率统计功能,在嵌入式系统设计中无法直观的评估CPU的使用情况,所以在此提供一种计算CPU使用率的方法。

原理

此种方法计算CPU使用率原理为:
1.系统启动后,将所有任务都挂起,统计一段时间T(如1S)内空闲任务被调用的次数M,此时可认为这个次数是CPU占用率最小(接近0)时能够调用空闲任务的最大次数。
2.任务开始运行后,每隔一段时间T,记录空闲任务被调用的次数m。
3.CPU的占用率为:(1-m/M) * 100%

这种方法的好处在于:可以忽略硬件中断所占用的时间。

实现

  1. 你自己创建的文件 RtosTask.c
    该函数的执行顺序:
状态 滴答计数器值 所做工作 目的
INIT 0 挂起系统任务 等待挂起后的稳定状态
FIRST_CNT 200 清空空闲任务计数器 开始空闲任务计数
FIRST_CALC 700 赋值空闲任务最大计数,恢复挂起任务,开启看门狗 得到空闲任务计数最大值
EVE_CNT 701 清空空闲任务计数器 开始空闲任务计数
EVE_CALC 1201 计算CPU使用率,跳转状态到EVE_CNT 周期计算CPU使用率

从上表可知,本程序中的固定时间T = 700 - 200 = 1201 - 701 = 500ms
下面是具体的程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
// 定义状态枚举类型
typedef enum
{
E_INIT = 0u,
E_FIRST_CNT = 200u,
E_FIRST_CALC = 700u,
E_EVE_CNT = 701u,
E_EVE_CALC = 1201u
}E_USAGE_STATES;

//定义计数变量
UNSIGNED32 g_u32MaxIdleCnt = 0u;
UNSIGNED32 g_u32IdleCnt = 0u;
UNSIGNED32 g_u32TickCnt = 0u;

// 定义滴答时钟钩子函数
void vApplicationTickHook(void)
{
// CPU使用率计算 todo
switch(g_u32TickCnt)
{
case E_INIT: //初始化,等待稳定
{
//挂起三个系统任务 这里的参数是某个任务的句柄
vTaskSuspend(RTOS_GetOSTaskHandle(E_TASK_10MS));
vTaskSuspend(RTOS_GetOSTaskHandle(E_TASK_50MS));
vTaskSuspend(RTOS_GetOSTaskHandle(E_TASK_1MS));

break;
}
case E_FIRST_CNT: //分母开始计数
{
// 空闲任务计数值清空
g_u32IdleCnt = 0u;

break;
}
case E_FIRST_CALC: //计算分母
{
g_u32MaxIdleCnt = g_u32IdleCnt;

//恢复挂起的任务
vTaskResume(RTOS_GetOSTaskHandle(E_TASK_10MS));
vTaskResume(RTOS_GetOSTaskHandle(E_TASK_50MS));
vTaskResume(RTOS_GetOSTaskHandle(E_TASK_1MS));

//开启看门狗,该函数根据硬件平台自定义, 如果你的系统不需要看门狗,也没有喂狗操作,那么此条忽略
WatchDog_Enable();

break;
}
case E_EVE_CNT: //正常计数开始
{
// 空闲任务计数值清空
taskENTER_CRITICAL();

g_u32IdleCnt = 0u;

taskEXIT_CRITICAL();

break;
}
case E_EVE_CALC: // 计算使用率
{
dbgs_f32_cpu_usage_percent = (1.0f - (FLOAT32)g_u32IdleCnt / (FLOAT32)g_u32MaxIdleCnt) * 100.0f;

g_u32TickCnt = E_EVE_CNT - 1;

break;
}
default:
break;
}
g_u32TickCnt++;
}

// 定义空闲任务钩子函数
void vApplicationIdleHook( void )
{
// 空闲任务计数
taskENTER_CRITICAL();

g_u32IdleCnt++;

taskEXIT_CRITICAL();
}

  1. FreeRTOSConfig.h
1
2
3
// 将这两个宏开启,对应的钩子函数才会被调用
#define configUSE_IDLE_HOOK 1
#define configUSE_TICK_HOOK 1
  1. main.c

运行后,变量dbgs_f32_cpu_usage_percent的值就为当前系统CPU使用率。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int main(void)
{
EVMCU50MS_TaskInit();
EVMCU1MS_TaskInit();
EVMCU10MS_TaskInit();
RTOS_TaskCreate(EVMCU10MS_TASK, EVMCU10MS_TaskHandler);
RTOS_TaskCreate(EVMCU50MS_TASK, EVMCU50MS_TaskHandler);
RTOS_TaskCreate(EVMCU1MS_TASK, EVMCU1MS_TaskHandler);
//开启调度器
RTOS_StartScheduler();

// While loop when the OS fail
while(TRUE)
{
;
}

return 0;
}