1 任务运行时间信息统计函数
FreeRTOS 提供了一个用于统计系统中任务运行时间信息的函数vTaskGetRunTimeStats()。该函数的原型如下。
void vTaskGetRunTimeStats( char *pcWriteBuffer );
参数说明如下。
pcWriteBuffer: 保存任务运行时间信息的存储区。
返回值:无。
使用 vTaskGetRunTimeStats()函数需要将宏 configGENERATE_RUN_TIME_STATS、configUSE_TRACE_FACILITY 及 configUSE_STATS_FORMATTING_FUNCTIONS都设置为1,同时用户还需在FreeRTOSConfig.h头文件中实现如下两个宏。
pOrtCONFIGURE_TIMIER_FOR_RUN_TIMESTATS():用于初始化任务运行时间信息统计功能的时间基准。时间基准一般使用定时器来提供,并且要求这个定时器的精度是系统时钟节拍精度的10倍以上。
portGET_RUN_TIME_COUNTER_VALUE():用于获取统计任务运行时间信息的计数器值,利用这个计数值来计算各任务运行时间百分比。
注意 :使用vTaskGetRunTimeStats()函数会降低系统的实时性。一般用于代码调式阶段。
2 任务运行时间信息统计示例
本示例在任务状态信息获取示例的基础上,增加任务运行时间信息统计功能。通过appStartTask()函数,创建3个FreeRTOS任务。
任务1的任务函数为Led0Task(),其功能是使LEDO每秒闪烁1次,优先级为3。
任务2的任务函数为Led1Task(),其功能是使LED1每秒闪烁2次,优先级为2。
任务3的任务函数为getTaskInfo(),其功能是当Key1按键被按下时,获取所有任务状态信息并通过串口发送;当Key1按键被按下时,获取所有任务运行时间信息并通过串口发送,优先级为4。
2.1 配置时间基准
要使用任务运行时间信息统计功能,需要一个精度是系统时钟节拍精度10倍以上的时间基准。本示例使用基本定时器TIM2来提供这个时间基准。
代码配置:
#include "stm32f10x.h" // Device header
#include "Timer.h"
volatile unsigned long long ullTimerCount = 0; //用于任务运行时间信息统计的计数器
void Timer_Init(){
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=100 -1 ;//ARR
TIM_TimeBaseInitStructure.TIM_Prescaler=90 -1 ;//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;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM2,ENABLE);//开启定时器
}
在定时中断中添加任务运行时间信息统计值加1的代码。
void TIM2_IRQHandler(void){
if(TIM_GetFlagStatus(TIM2,TIM_FLAG_Update)==SET)
{
ullTimerCount++; //任务运行时间信息统计值加1
TIM_ClearFlag(TIM2,TIM_FLAG_Update);
}
}
2.2 配置任务运行时间信息统计功能
开启任务运行时间信息统计功能,需要设计一些宏,并实现2个用于初始化计数器及获取统计值的宏。
#define configUSE_TRACE_FACILITY 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 1
#define configGENERATE_RUN_TIME_STATS 1
//用于初始化计数器以及获取统计值的宏
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() (ullTimerCount = 0)
#define portGET_RUN_TIME_COUNTER_VALUE() ullTimerCount
2.3 任务函数
/**********************************************************************
函 数 名:Led0Task
形 参:pvParameters 是在创建该任务时传递的参数
返 回 值:无
优 先 级: 3
**********************************************************************/
static void Led0Task(void *pvParameters)
{
uint32_t testArray[128] ; //任务中的局部变量
while(1)
{
GPIO_WriteBit(GPIOA,GPIO_Pin_4,(BitAction)(1 - GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_4))); //LED0闪烁
vTaskDelay(pdMS_TO_TICKS(500));//每秒闪1次
}
}
/**********************************************************************
函 数 名:Led1Task
形 参:pvParameters 是在创建该任务时传递的参数
返 回 值:无
优 先 级: 2
**********************************************************************/
static void Led1Task(void *pvParameters)
{
uint32_t testArray[128] = {0}; //任务中的局部变量
while(1)
{
GPIO_WriteBit(GPIOA,GPIO_Pin_5,(BitAction)(1 - GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_5))); //LED1闪烁
vTaskDelay(pdMS_TO_TICKS(250));//每秒闪2次
}
}
/**********************************************************************
函 数 名:getTaskInfo
功能说明:获取任务状态信息并通过串口发送
形 参:pvParameters 是在创建该任务时传递的参数
返 回 值:无
优 先 级: 1
**********************************************************************/
void getTaskInfo(void *pvParameters)
{
char pcTaskInfo[800]; //用于保存任务状态信息
uint8_t ucKeyValue = 0;
while(1)
{
ucKeyValue = Key_getNum();
if(ucKeyValue == 1)
{
vTaskList(pcTaskInfo);
printf("任务名 任务状态 优先级 剩余堆栈大小 任务号 \r\n");
printf("%s\r\n",pcTaskInfo);
}else if(ucKeyValue == 2)
{
vTaskGetRunTimeStats(pcTaskInfo);
printf("任务名\t\t运行时间\t\t百分比\t\t \r\n");
printf("%s\r\n",pcTaskInfo);
}
vTaskDelay(pdMS_TO_TICKS(100)); //阻塞100ms
}
}
2.4 任务创建
/**********************************************************************
函 数 名:appStartTask
功能说明:任务开始函数,用于创建其他函数并且开启调度器
形 参:pvParameters 是在创建该任务时传递的参数
返 回 值:无
**********************************************************************/
void appStartTask(void)
{
taskENTER_CRITICAL(); /*进入临界段,关中断*/
xTaskCreate(Led0Task,"Led0Task",256,NULL,3,&Led0TaskHandle);
xTaskCreate(Led1Task,"Led1Task",256,NULL,2,&Led1TaskHandle);
xTaskCreate(getTaskInfo,"getTaskInfo",512,NULL,4,&tskInfoTaskHandle);
taskEXIT_CRITICAL(); /*退出临界段,关中断*/
vTaskStartScheduler();/*开启调度器*/
}
2.5 下载测试
图中的运行时间不是真是任务运行时间,再乘以时间基准才是真实的任务运行时间,本例要乘120us。
3 总结
任务管理是FreeRTOS的核心功能,FreeRTOS提供了很多任务函数,比较常用的任务函数有延时函数,优先级控制函数,任务状态信息以及任务运行时间信息获取函数等。