freertos动态测量cpu使用率的方法

freertos提供了vTaskGetRunTimeStats这一方法来测量cpu使用率,具体参见 《安富莱_STM32-V6开发板_FreeRTOS教程》或者网上其教程,不再赘述。

这一方法有几个问题:

1、freerots需要一个频率较高的定时器,在vTaskSwitchContext()函数里(在tasks.c里)

记录一下当前运行的任务所使用的时间

#if ( configGENERATE_RUN_TIME_STATS == 1 )
{
    #ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
        portALT_GET_RUN_TIME_COUNTER_VALUE( ulTotalRunTime );
    #else
        ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();   //获取高分辨率定时器计数值
    #endif
    /* Add the amount of time the task has been running to the
    accumulated time so far.  The time the task started running was
    stored in ulTaskSwitchedInTime.  Note that there is no overflow
    protection here so count values are only valid until the timer
    overflows.  The guard against negative values is to protect
    against suspect run time stat counter implementations - which
    are provided by the application, not the kernel. */
    if( ulTotalRunTime > ulTaskSwitchedInTime )  //给当前任务的计时变量加上这一段的运行时间
    {
        pxCurrentTCB->ulRunTimeCounter += ( ulTotalRunTime - ulTaskSwitchedInTime );
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }
    ulTaskSwitchedInTime = ulTotalRunTime;   //作为下一个任务运行时间的起点
}
#endif /* configGENERATE_RUN_TIME_STATS */

portGET_RUN_TIME_COUNTER_VALUE的原型是

#define portGET_RUN_TIME_COUNTER_VALUE getRunTimeCounterValue

getRunTimeCounterValue这个函数需要用户自己定义,之前能搜到的教程是在定时器中断里整一个自加变量实现的

volatile uint32_t ulHighFrequencyTimerTicks = 0UL;
uint32_t getRunTimeCounterValue(void)
{
  return ulHighFrequencyTimerTicks;
}

void TIM6_IRQHandler( void )
{
if(TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET)
{
ulHighFrequencyTimerTicks++;
TIM_ClearITPendingBit(TIM6, TIM_IT_Update);
} }

其实定时器是需要的,但中断完全没必要。我改成了下面的样子

uint32_t getRunTimeCounterValue(void)  //TIM5不需要开中断
{
  return TIM5->CNT;
}

stm32的TIM5是32位的,我可以把频率设的很高比如1M,从而使时间统计精度更高,也不用担心频繁的中断浪费性能。

2、freertos自带的功能无法处理定时器溢出问题

3、freertos自带的功能其实是统计的从rtos开始运行开始,各任务运行时间的累积。如果我想获得一个时间片内,各任务的cpu占用情况呢?毕竟很多任务的执行需要触发条件。

我是这样做的:

首先使用TIM5,频率1M,无中断。(用16位定时器也没问题,频率稍微低一点,或者统计时间稍微短一点)

void configureTimerForRunTimeStats(void)
{
  HAL_TIM_Base_Start(&htim5);
}

__inline uint32_t getRunTimeCounterValue(void)
{
  return TIM5->CNT;
}

在一个1s为周期的任务里,统计cpu占用。计时周期长短看需求,反正统计的是占用率。

uint8_t u8TaskListBuff[200];
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void *argument)
{
  /* USER CODE BEGIN StartDefaultTask */
  /* Infinite loop */
  for(;;)
  {
    HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
    osDelay(1000);
    HAL_TIM_Base_Stop(&htim5);
    memset(u8TaskListBuff, 0, 200);
    vTaskGetRunTimeStats((char*)u8TaskListBuff);
    HAL_UART_Transmit_IT(phComDbg,u8TaskListBuff,strlen((char*)u8TaskListBuff));
    TIM5->CNT = 0;
    HAL_TIM_Base_Start(&htim5);

  }
  /* USER CODE END StartDefaultTask */
}

如果只是改成这样的话,程序就sb了。。。必须手动给每个任务的ulRunTimeCounter清零。

一开始尝试在vTaskSwitchContext做清零,那些一直挂起的任务不能被正确的清零。

后来我想vTaskGetRunTimeStats执行过程中清零

vTaskGetRunTimeStats调用了uxTaskGetSystemState获取任务信息列表,继续调用prvListTasksWithinSingleList获取各个状态下的任务信息列表。所以在rvListTasksWithinSingleList 或被它调用的vTaskGetInfo里对ulRunTimeCounter清零就好。

注意:对pxTaskStatusArray里的任务的ulRunTimeCounter清零没用,它只是被复制出来的任务信息,不是任务本身的指针。

我在vTaskGetInfo下添加了清零代码(不管任务处于什么状态,都会被清零)

void vTaskGetInfo( TaskHandle_t xTask, TaskStatus_t *pxTaskStatus, BaseType_t xGetFreeStackSpace, eTaskState eState )
	{
/******省略****/

		#if ( configGENERATE_RUN_TIME_STATS == 1 )
		{
			pxTaskStatus->ulRunTimeCounter = pxTCB->ulRunTimeCounter;
			pxTCB->ulRunTimeCounter=0;  //清零
		}
		#else
...

现在好使了

注意cubemx重新生成代码的话,上面那个清零动作记得重新加。测量cpu占用一般也都是调试时使用。

<think>嗯,用户想了解如何在STM32上使用FreeRTOS计算CPU使用率。这个问题看起来挺常见的,但具体怎么实现呢?首先,我得回忆一下FreeRTOS的相关机制。FreeRTOS没有内置的CPU使用率统计功能,所以可能需要自己实现或者利用一些已有的方法。 首先,用户可能知道,计算CPU使用率通常需要测量空闲任务的时间。因为当系统没有其他任务运行时,空闲任务就会执行,所以空闲任务的运行时间占比大致反映了CPU的空闲时间。那怎么测量这个时间呢?可能需要一个高精度的定时器来记录空闲任务的运行时间。 对了,我记得FreeRTOS有一个配置选项configUSE_IDLE_HOOK,可以启用空闲任务的钩子函数。这样的话,用户可以在空闲任务运行时执行一些自定义的代码,比如记录时间。不过,钩子函数是在空闲任务上下文中运行的,所以不能阻塞,这点需要注意。 另一个配置是configGENERATE_RUN_TIME_STATS,启用后可以生成运行时间统计信息。这需要用户自己实现portCONFIGURE_TIMER_FOR_RUN_TIME_STATS和portGET_RUN_TIME_STATS_COUNTER这两个宏,用来初始化定时器和获取当前时间计数器的值。通过这两个宏,可以获取每个任务的运行时间,从而计算总运行时间和空闲任务的时间,进而得出CPU使用率。 不过,用户可能需要更详细的步骤。比如,首先配置FreeRTOS,启用相关的宏,然后设置一个定时器,比如SysTick或者通用定时器,来提供高精度的时间计数。然后,在代码中定期获取空闲任务的运行时间,计算CPU使用率。需要注意的是,定时器的分辨率要足够高,否则统计结果可能不准确。 可能还需要考虑如何避免中断对统计的影响,或者如何处理计数器溢出的问题。比如,使用32位的定时器计数器,或者处理溢出后的数值。此外,计算的时间窗口也很重要,可能需要定期重置统计值,避免长期累积导致的误差。 用户可能还想知道具体的代码示例。比如,如何定义portCONFIGURE_TIMER_FOR_RUN_TIME_STATS和portGET_RUN_TIME_STATS_COUNTER,如何使用vTaskGetRunTimeStats函数来获取各个任务的运行时间,然后计算总的运行时间和空闲任务的时间,最后用公式:CPU使用率 = (1 - 空闲任务时间 / 总时间) * 100%。 另外,用户可能需要知道如何将统计结果输出,比如通过串口打印或者显示在屏幕上。同时,需要注意实时统计可能会对系统性能产生一定影响,尤其是在资源有限的STM32上,需要权衡精度和性能消耗。 可能还有一些常见问题,比如统计结果不准确,或者计数器溢出导致的数据错误。这时候需要检查定时器的配置是否正确,计数器是否足够长,或者调整统计的时间间隔。 总结一下,步骤大概是:配置FreeRTOS启用统计功能,实现定时器相关的宏,获取任务运行时间数据,计算CPU使用率,然后输出结果。同时要注意定时器的选择和配置,以及如何处理可能的溢出问题。</think>在STM32平台上结合FreeRTOS计算CPU使用率,需通过统计**空闲任务运行时间占比**实现。以下是分步实现方案: --- ### 一、基本原理 1. **空闲任务特性** FreeRTOS空闲任务(IDLE任务)优先级最低,**仅当无其他任务运行时才执行**。 CPU使用率 = `(1 - 空闲任务运行时间 / 总统计时间) × 100%` 2. **统计方法** 利用高精度定时器记录空闲任务运行时间,通过差值计算总CPU负载。 --- ### 二、FreeRTOS配置 在`FreeRTOSConfig.h`中添加以下配置: ```c #define configUSE_IDLE_HOOK 1 // 启用空闲任务钩子函数 #define configGENERATE_RUN_TIME_STATS 1 // 启用运行时间统计 #define configUSE_STATS_FORMATTING_FUNCTIONS 1 // 启用统计格式化函数 // 实现定时器计数器(以SysTick为例) extern volatile uint32_t ulHighFrequencyTimerTicks; #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() (ulHighFrequencyTimerTicks = 0) #define portGET_RUN_TIME_STATS_COUNTER() ulHighFrequencyTimerTicks ``` --- ### 三、硬件定时器配置(以STM32为例) 1. **选择定时器** 使用通用定时器(如TIM2)或系统滴答定时器(SysTick),配置为**1MHz频率**以提供微秒级精度。 2. **示例代码(HAL库)** ```c volatile uint32_t ulHighFrequencyTimerTicks = 0; void TIM2_IRQHandler(void) { if (__HAL_TIM_GET_FLAG(&htim2, TIM_FLAG_UPDATE) != RESET) { ulHighFrequencyTimerTicks++; __HAL_TIM_CLEAR_FLAG(&htim2, TIM_FLAG_UPDATE); } } void MX_TIM2_Init(void) { htim2.Instance = TIM2; htim2.Init.Prescaler = (SystemCoreClock / 1000000) - 1; // 1MHz计数 htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 0xFFFFFFFF; // 32位最大值 HAL_TIM_Base_Start_IT(&htim2); } ``` --- ### 四、CPU使用率计算 1. **定义全局变量** ```c static uint32_t ulIdleTaskTime = 0; // 空闲任务累计时间 static uint32_t ulLastIdleTime = 0; // 上次统计时的空闲时间 static uint32_t ulLastTotalTime = 0; // 上次统计时的总时间 ``` 2. **空闲任务钩子函数** ```c void vApplicationIdleHook(void) { ulIdleTaskTime = ulHighFrequencyTimerTicks - ulLastIdleTime; ulLastIdleTime = ulHighFrequencyTimerTicks; } ``` 3. **计算函数** ```c float GetCPUUsage(void) { uint32_t ulCurrentTotalTime = ulHighFrequencyTimerTicks; uint32_t ulElapsedTotalTime = ulCurrentTotalTime - ulLastTotalTime; ulLastTotalTime = ulCurrentTotalTime; if (ulElapsedTotalTime == 0) return 0.0f; // 避免除以0 float fUsage = 100.0f * (1.0f - (float)ulIdleTaskTime / (float)ulElapsedTotalTime); return fUsage > 100.0f ? 100.0f : fUsage; // 钳制最大值 } ``` --- ### 五、使用注意事项 1. **定时器精度** 定时器频率建议≥1MHz,低精度会导致统计误差增大。 2. **统计周期** 建议每1秒调用一次`GetCPUUsage()`,避免短期波动。 3. **中断影响** 若高优先级中断占用大量时间,此方法无法统计(需结合中断执行时间修正)。 --- ### 六、扩展:任务级详细统计 ```c void PrintTaskStats(void) { char pcBuffer[512]; vTaskGetRunTimeStats(pcBuffer); // 获取任务运行时间 printf("%s\n", pcBuffer); // 通过串口输出 } ``` 需实现`vTaskGetRunTimeStats()`依赖的格式化函数。 --- ### 七、验证与调试 1. 使用逻辑分析仪或调试器观察定时器中断频率。 2. 创建高低优先级任务,观察CPU使用率变化是否符合预期。 通过以上步骤,即可在STM32+FreeRTOS系统中实现准确的CPU使用率统计。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值