FreeRTOS_调试与优化

目录标题

  • 前言
  • 1、vTaskList()
  • 2、vTaskGetRunTimeStats()
    • 2.1、标准库——使用教程
      • 1、初始化一个定时器来提供统计功能所需的时基
      • 2、在FreeRTOSConfig.h中使能相关的宏定义
      • 3、创建一个打印任务信息的任务
      • 输出结果:
    • 2.2、HAL库使用教程
  • 3、uxTaskGetStackHighWaterMark()

前言

在使用FreeRtos进行开发的过程中,我们通常需要了解系统的运行状态、内存、CPU使用情况等信息,来确保系统能够长期稳定的运行。
我们需要了解的一些系统信息:

  • 当前任务的剩余内存;
  • 当前任务历史最小内存;
  • 系统总的剩余内存;
  • 系统运行的总时间;
  • 单个任务的运行时间;
  • 每个任务占用的CPU时间;

1、vTaskList()

函数原型:

void vTaskList( char * pcWriteBuffer )

vTaskList()函数是FreeRTOS中自带的一个用来获取任务信息的函数,该函数会创建一个列表,列表中包含任务名称,任务状态信息,任务优先级,剩余堆栈以及任务编号的信息。
使用这个函数需要在FreeRTOSConfig.h中使能如下几个宏:

#define configUSE_TRACE_FACILITY              1
#define configUSE_STATS_FORMATTING_FUNCTIONS     1

任务的运行状态共有如下几种:

X 运行状态
R Redy就绪状态
B Block阻塞状态
S Suspend挂起状态
D Deletedr任务已经被删除

使用案例:

/* Cpu_task function */
void Cpu_task(void  * argument)
{
  /* USER CODE BEGIN Cpu_task */
    uint8_t CPU_RunInfo[512];
  /* Infinite loop */
  while(1)
  {
      memset(CPU_RunInfo,0,512);
      vTaskList((char *)&CPU_RunInfo); //获取任务运行时间信息
      printf("---------------------------------------------\r\n");
      printf("任务名       任务状态   优先级  剩余栈  任务序号\r\n");
      printf("%s", CPU_RunInfo);
      printf("---------------------------------------------\r\n");
      vTaskDelay(5000); /* 延时500个tick */
  }
  /* USER CODE END Cpu_task */
}

输出结果
FreeRTOS_调试与优化_第1张图片

2、vTaskGetRunTimeStats()

函数原型:

void vTaskGetRunTimeStats( char *pcWriteBuffer )

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

对于vTaskGetRunTimeStats()的使用教程,我们联合着vTaskList()一起来看。因为一般情况下,我们使用vTaskList()不一定使用vTaskGetRunTimeStats(),但是使用vTaskGetRunTimeStats()时一般会和vTaskList()一起使用。

利用vTaskGetRunTimeStats()和vTaskList()可以计算输出RTOS的CPU的使用率及任务栈的使用情况,有助于RTOS的调试开发。可以分析多任务的设计的合理性,如果CPU的利用率为1%,说明CPU 99%的时间运行在空闲任务上,则极大的浪费CPU的性能。

2.1、标准库——使用教程

1、初始化一个定时器来提供统计功能所需的时基

我们在这里用定时器2来提供时基,初始化函数如下:

/*
*函数名称;Timer2_Init
*功能描述:初始化定时器2,并打开定时中断
*传入参数:ARR-计数周期
*         RSC-预分频器值
*/
void Timer2_Init(uint16_t ARR,uint16_t RSC)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	TIM_InternalClockConfig(TIM2);/*开启内部时钟*/
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; /*不分频*/
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;/*向上计数*/
	TIM_TimeBaseInitStructure.TIM_Period = ARR;//ARR-计数周期
	TIM_TimeBaseInitStructure.TIM_Prescaler = ARR;//PSC-预分频数
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; /*重复计数器*/
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
	
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//中断使能
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; /*设置要配置的中断通道为 TIM2 的中断通道。*/
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; /*使能中断通道*/
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;/*抢占优先级*/
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =1;/*响应优先级*/
	NVIC_Init(&NVIC_InitStructure);
	
	TIM_Cmd(TIM2,ENABLE);/*开启定时器*/
}
/*
*函数名称:ConfigureTimerForRunTimeStats
*功能描述:将节拍计数值归零,并调用定时器初始化函数,
          在这里进中断的频率为72 000 000 /72/50 = 20KHZ,
          满足基准的精度是系统节拍精度的10倍以上的要求
*/
volatile unsigned long long FreeRTOSRunTimeTicks = 0;
//用来获取统计任务运行时间信息的计数器值
void ConfigureTimerForRunTimeStats(void)
{
	FreeRTOSRunTimeTicks = 0;
	Timer2_Init(50-1,72-1);
}

中断处理函数:

void TIM2_IRQHandler(void)
{
	if(TIM_GetFlagStatus(TIM2,TIM_FLAG_Update)==SET)/*检查TIM2的更新事件标志位*/
	{
		FreeRTOSRunTimeTicks++;/*节拍计数值++*/
		TIM_ClearFlag(TIM2,TIM_FLAG_Update);/*清除更新事件标志位*/
	}
}

timer.h文件内容

#ifndef __TIMER_H__
#define __TIMER_H__
#include "stm32f10x.h"                  // Device header

void ConfigureTimerForRunTimeStats(void);

#endif

2、在FreeRTOSConfig.h中使能相关的宏定义

要使用vTaskGetRunTimeStats()和vTaskList(),我们首先需要在FreeRTOSConfig.h中使能如下几个宏:

#define configUSE_TRACE_FACILITY  1   /*为1时启用可视化跟踪调试*/
#define configUSE_STATS_FORMATTING_FUNCTIONS  1  
/* configUSE_TRACE_FACILITY和 configUSE_STATS_FORMATTING_FUNCTIONS都设置为 1,则再构建中包含编译  vTaskList()和 vTaskGetRunTimeStats()函数;*/ 
#define configGENERATE_RUN_TIME_STATS   1 //为1时打开运行时间统计功能

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

extern volatile unsigned long long FreeRTOSRunTimeTicks;
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()  ConfigureTimerForRunTimeStats()
/*用来初始化任务运行时间信息统计功能的时间基准,时间基准一般由定时器来提供,并且要求此基准的精度是系统节拍精度的10倍以上*/
#define portGET_RUN_TIME_COUNTER_VALUE()  FreeRTOSRunTimeTicks
/*用来获取统计任务运行时间信息的计数器值,利用此计数值来计算各任务运行时间的占空比*/

3、创建一个打印任务信息的任务

/*定义一个打印任务信息的任务*/
void Cpu_task(void  * argument)
{
    uint8_t CPU_RunInfo[512];
  while(1)
  {
      memset(CPU_RunInfo,0,512);
      vTaskList((char *)&CPU_RunInfo); //获取任务运行时间信息
      printf("---------------------------------------------\r\n");
      printf("任务名       任务状态   优先级  剩余栈  任务序号\r\n");
      printf("%s", CPU_RunInfo);
      printf("---------------------------------------------\r\n");
      memset(CPU_RunInfo,0,512);
      vTaskGetRunTimeStats((char *)&CPU_RunInfo);
      printf("任务名          运行计数       使用率\r\n");
      printf("%s", CPU_RunInfo);
      printf("---------------------------------------------\r\n\n");
      vTaskDelay(5000); /* 延时5000个tick */

  }
}

/*创建任务,启动任务调度*/
int main(void)
{
	Hardware_Init();
	xTaskCreate(menu_task,"menu_task",128,NULL,5,NULL);
	xTaskCreate(key_task,"keytask",128,NULL,7,NULL);
	xTaskCreate(Cpu_task,"cputask",128*8,NULL,3,NULL);
	vTaskStartScheduler();/*启动任务调度*/
}

输出结果:

FreeRTOS_调试与优化_第2张图片

2.2、HAL库使用教程

日后再出,…

3、uxTaskGetStackHighWaterMark()

函数原型:

UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask )

函数功能:获取指定任务历史最小剩余堆栈,返回的值越小,任务越容易内存溢出

你可能感兴趣的:(FreeRTOS,STM32,单片机,stm32)