4. 空闲任务与钩子函数
任务定义
在RTOS中,空闲任务(Idle Task)是系统创建的最低优先级任务,仅在无其他就绪任务时运行。本案例要求在FreeRTOS环境下,利用空闲任务的钩子函数(Idle Hook)统计系统CPU利用率,并通过串口周期性输出结果。
实现原理
CPU利用率定义为:利用率 = (1 - 空闲时间 / 总时间) × 100%。空闲任务钩子函数在每个空闲任务循环中被调用,通过累加空闲计数器来记录空闲时间占比。同时,系统Tick中断周期性累加总时间计数器。统计周期结束后,计算两者比值即可得到CPU利用率。
代码实现
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "uart.h" // 假设已有串口驱动,提供 UART_SendString()
/* 统计周期:5000个Tick(假设Tick周期1ms,即5秒) */
#define STATS_PERIOD_TICKS 5000
static volatile uint32_t ulIdleCount = 0; // 空闲计数器
static volatile uint32_t ulTotalCount = 0; // 总计数器
static volatile uint32_t ulLastIdleCount = 0; // 上次统计时的空闲计数
/* 空闲任务钩子函数:必须在FreeRTOSConfig.h中配置
configUSE_IDLE_HOOK 为 1 */
void vApplicationIdleHook(void)
{
ulIdleCount++;
}
/* 统计任务:周期性计算并输出CPU利用率 */
static void vStatsTask(void *pvParameters)
{
uint32_t ulIdleDelta;
uint32_t ulCpuUsage;
char cBuf[32];
for (;;)
{
/* 等待一个统计周期 */
vTaskDelay(STATS_PERIOD_TICKS);
/* 计算周期内空闲Tick数 */
ulIdleDelta = ulIdleCount - ulLastIdleCount;
ulLastIdleCount = ulIdleCount;
/* 计算CPU利用率(百分比) */
ulCpuUsage = 100UL - (ulIdleDelta * 100UL) / STATS_PERIOD_TICKS;
/* 格式化并输出 */
snprintf(cBuf, sizeof(cBuf), "CPU: %lu%%\r\n", ulCpuUsage);
UART_SendString(cBuf);
}
}
/* 模拟工作任务:占用CPU以产生非零利用率 */
static void vWorkTask(void *pvParameters)
{
volatile uint32_t ulWork;
for (;;)
{
/* 模拟约30% CPU负载:忙等300个Tick后休眠700个Tick */
ulWork = 0;
TickType_t xStart = xTaskGetTickCount();
while ((xTaskGetTickCount() - xStart) < 300)
{
ulWork++;
}
vTaskDelay(700);
}
}
void main(void)
{
/* 初始化硬件(时钟、串口等) */
HardwareInit();
/* 创建统计任务(优先级2) */
xTaskCreate(vStatsTask, "Stats", 128, NULL, 2, NULL);
/* 创建工作任务(优先级1) */
xTaskCreate(vWorkTask, "Work", 128, NULL, 1, NULL);
/* 启动调度器 */
vTaskStartScheduler();
/* 正常不会执行到这里 */
for (;;);
}
关键配置说明
本案例依赖以下FreeRTOS配置项(在FreeRTOSConfig.h中):
configUSE_IDLE_HOOK必须设为1,否则空闲钩子不会被调用。configTICK_RATE_HZ设为1000(即1ms一个Tick),保证统计精度。- 空闲任务栈大小需满足钩子函数调用需求(默认即可)。
验证方法
将代码编译烧录至目标板(如STM32F407),打开串口助手(波特率与UART驱动一致,通常115200)。观察输出:
- 工作任务忙等300ms、休眠700ms,理论CPU利用率为30%。
- 串口每5秒输出一行
CPU: xx%,数值应在30%附近波动(±5%以内)。 - 若注释掉工作任务创建代码,则输出应接近
CPU: 0%或极小值(因中断处理占用少量CPU)。
判定标准:串口输出的CPU利用率与工作任务忙等比例一致(约30%),且无系统崩溃或死机,即验证通过。
代码行为说明
上述代码中,vApplicationIdleHook在空闲任务每次循环时被调用,累加ulIdleCount。统计任务每5秒读取一次该值,计算与上次的差值ulIdleDelta,该差值即为5秒内空闲任务执行的Tick数。由于系统总Tick数为5000,空闲占比即为ulIdleDelta/5000,CPU利用率由此算出。工作任务通过忙等300 Tick再休眠700 Tick的方式,模拟约30%的CPU负载,用于验证统计结果的正确性。