【STM32】在FreeRTOS中调用vTaskList()和vTaskGetRunTimeStats()函数获取各个任务状态信息及运行时间

使用到的软件

  • STM32CubeMX
  • Keil5
  • xcom串口助手
  • (使用的HAL库)

FreeRTOS介绍

RTOS(Real Time OS)实时操作系统逻辑图:
在这里插入图片描述

  • 注:图片来源为正点原子教学视频

FreeRTOS由美国的Richard Barry于2003年发布,是目前市场占有率最高的RTOS系统。

FreeRTOS是一个可裁剪、可剥夺型的多任务内核,而且没有任务数限制。FreeRTOS提供了实时操作系统所需的所有功能,包括资源管理、同步、任务通信等。

FreeRTOS是用 C 和汇编来写的,其中绝大部分都是用 C 语言编写的,只有极少数的与处理器密切相关的部分代码才是用汇编写的,FreeRTOS 结构简洁,可读性很强。

FreeRTOS源码获取:
最新版:www.freertos.org
以往版本:https://sourceforge.net/projects/freertos/files/FreRTOS/

  • PS:笔者使用了STM32CubeMX来生成FreeRTOS的源文件,如果不想使用Cube来生成,可以从上面的FreeRTOS官网地址下载。

关于vTaskList()函数

vTaskList()函数是FreeRTOS中自带的一个用来获取任务信息的函数,该函数会创建一个列表,列表中包含任务名称,任务状态信息,任务优先级,剩余堆栈以及任务编号的信息。

函数原型为:

void vTaskList( char * pcWriteBuffer )

关于vTaskGetRunTimeStats()函数

vTaskGetRunTimeStats()函数是FreeRTOS中自带的一个用来统计各个Task占用CPU时间的函数,使用这个功能我们可以清晰地看到每个任务所占用时间、百分比以及CPU整体的占用率,任务的运行时间信息提供了每个任务获取到的CPU使用权总的时间。

函数vTaskGetRunTimeStats()会将统计到的信息填充到另一个列表里,这样我们就可以随时知道所有任务抢占CPU的结果,便于我们合理规划安排这些任务。

函数原型为:

void vTaskGetRunTimeStats( char *pcWriteBuffer )

如何使用

虽然说vTaskList()函数和vTaskGetRunTimeStats()函数都是FreeRTOS中已经给出的,但是我们无法直接使用。使用这两个函数之前我们需要使能以下这四个宏:

  • configUSE_TRACE_FACILITY
  • configGENERATE_RUN_TIME_STATS
  • configUSE_STATS_FORMATTING_FUNCTIONS
  • configSUPPORT_DYNAMIC_ALLOCATION

在FreeRTOSConfig.h中加入下列代码以启用这四个宏:

#define configUSE_TRACE_FACILITY                 1
#define configGENERATE_RUN_TIME_STATS            1
#define configUSE_STATS_FORMATTING_FUNCTIONS     1
#define configSUPPORT_DYNAMIC_ALLOCATION         1

启用这四个宏之后我们还必须要定义下面两个宏:

  • portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()

  • portGET_RUN_TIME_COUNTER_VALUE()

第一个宏用来初始化一个外设来提供统计功能所需的时基。这个时基的分辨率一定要比FreeRTOS的系统时钟高,一般高出10~20倍。

在FreeRTOSConfig.h中加入如下代码定义这两个宏:

#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()   ConfigureTimerForRunTimeStates()
#define portGET_RUN_TIME_COUNTER_VALUE()           FreeRTOSRunTimeTicks

下一步我们需要编写ConfigureTimerForRunTimeStates()函数以及定义变量FreeRTOSRunTimeTicks。FreeRTOSRunTimeTicks用于节拍计数。

在tim.c中加入如下代码:

  • 注:这里因为笔者的定时器初始化在tim.c中,只是为了方便所以把下列代码也放到了tim.c中
volatile unsigned long long FreeRTOSRunTimeTicks=0;
void ConfigureTimerForRunTimeStates(void)
{
	FreeRTOSRunTimeTicks= 0;
	MX_TIM3_Init();
}

因为之后还需要在其他C文件中调用,所以别忘了在tim.h中再次声明。

extern volatile unsigned long long FreeRTOSRunTimeTicks;
void ConfigureTimerForRunTimeStates(void);

笔者这里使用的是stm32f427的板子以及定时器3(TIM3),定时器3是挂在APB1上的,f427的APB1频率为90MHz。
在这里插入图片描述
所以此处分频系数设置为90,重装载值设为50。此时中断频率=90M/90/50=20kHz,满足是FreeRTOS系统节拍频率1000Hz的20倍的条件。具体定时器初始化配置可参考如下代码:

void MX_TIM3_Init(void)
{
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 90-1;
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 50-1;
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
  {

之后在main.c中的定时器中断中加入下列代码,每进一次中断,FreeRTOSRunTimeTicks变量+1:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  /* USER CODE BEGIN Callback 0 */

  /* USER CODE END Callback 0 */
  
  /* USER CODE BEGIN Callback 1 */
  if (htim->Instance == TIM3) {
    HAL_IncTick();
	FreeRTOSRunTimeTicks++;
	}
  /* USER CODE END Callback 1 */
}

完成以上步骤后,笔者这里会出现一个 error: A1586E: Bad operand types (UnDefOT, Constant) for operator (。

这里只需要在port.c中按照这个路径:configMAX_SYSCALL_INTERRUPT_PRIORITY -> configPRIO_BITS -> __NVIC_PRIO_BITS 一路F12到__NVIC_PRIO_BITS将4U改为4即可。

到了这里,基本的配置已经完毕。接下来需要新建一个统计任务时间的任务:

osThreadDef(CPU_RunTime, CPU_RunTime, osPriorityHigh, 0, 128);
CPU_RunTimeHandle = osThreadCreate(osThread(CPU_RunTime), NULL);
uint8_t InfoBuffer[1000];

void CPU_RunTime(void)
{
	portTickType xLastWakeTime;
	xLastWakeTime = xTaskGetTickCount();
	while(1)
		{
			
		  osDelayUntil(&xLastWakeTime,1);//1000HZ
		  vTaskList((char *)&InfoBuffer);
		  vTaskGetRunTimeStats((char *)&InfoBuffer); 
	   if(RC_Ctl.rc.s1 == 2)
		   {
				 printf("=================================================\r\n");
				 printf("任务名        任务状态 优先级  剩余栈  任务号 \r\n");
				 printf("=================================================\r\n");
                 printf("%s\r\n", InfoBuffer);
				 printf("  B:阻塞  R:就绪  D:删除  S:暂停  X:运行 \r\n");
				 printf("=================================================\r\n");
				 printf("=================================================\r\n");
			     printf("任务名         运行计数        CPU使用率 \r\n");
				 printf("=================================================\r\n");
		  	     printf("%s\r\n",InfoBuffer);
				 printf("=================================================\r\n");
				 printf("=================================================\r\n\n\n");
				 vTaskDelay(1300);
		   }//获取CPU使用权总
    }	
}

最后,将数据通过串口输出到电脑即可,这里还需要对printf函数进行重定向操作,具体可以参考笔者之前的一篇博客,这里就不再赘述。
【STM32】如何将数据通过printf打印到串口_大忽悠的博客-CSDN博客

效果演示

请添加图片描述第一个表是vTaskList()函数列出的任务状态信息表,第二个表是vTaskGetRunTimeStats()函数列出的CPU使用率信息。

  • 8
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值