在使用FreeRtos进行开发的过程中,我们通常需要了解系统的运行状态、内存、CPU使用情况等信息,来确保系统能够长期稳定的运行。
我们需要了解的一些系统信息:
函数原型:
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 */
}
函数原型:
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来提供时基,初始化函数如下:
/*
*函数名称;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
要使用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
/*用来获取统计任务运行时间信息的计数器值,利用此计数值来计算各任务运行时间的占空比*/
/*定义一个打印任务信息的任务*/
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();/*启动任务调度*/
}
日后再出,…
函数原型:
UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask );
函数功能:获取指定任务历史最小剩余堆栈,返回的值越小,任务越容易内存溢出