StmF103C8T6标准库使用FreeRtos----任务时间统计

一:任务时间统计理论基础

二:代码部分

1、宏定义修改

 

2、应用程序还必须提供 portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() 和 portGET_RUN_TIME_COUNTER_VALUE 的定义, 以分别配置外设的定时器/计数器和返回定时器的当前计数值。 计数器 的频率应该至少是 tick 计数的 10 倍。

如果不定义函数,出现报错 

 定义完上面两个宏定义之后,在configfreertos.h中定义下列宏

注意:如果仅仅定义上面这些,依然会报错,说找不到这个函数vTaskGetRunTimeStats(WriteBuffer) ;我们在task.c文件中看看这个函数,如下:

#if ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( configUSE_TRACE_FACILITY == 1 ) )

    void vTaskGetRunTimeStats( char * pcWriteBuffer )
    {
        TaskStatus_t * pxTaskStatusArray;
        UBaseType_t uxArraySize, x;
        configRUN_TIME_COUNTER_TYPE ulTotalTime, ulStatsAsPercentage;

他的if里面有三个宏定义要求,我们只定义了两个,所以找不到函数,为了方便,后续我们不在freertos.h中修改宏定义,将宏定义全部定义在configfreertos.h文件中:如下

extern uint32_t VALUE;
#define portGET_RUN_TIME_COUNTER_VALUE() VALUE

#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() TIMER_FOR_RUN_TIME_STATS()
#define configGENERATE_RUN_TIME_STATS 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 1
#define configUSE_TRACE_FACILITY 1

完整代码:

key.h

#ifndef __KEY_H
#define __KEY_H

void Key_Init(void);
uint8_t Key_GetNum(void);

#endif

key.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "FreeRTOS.h"
#include "task.h"
#include "Serial.h"



void Key_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	
}

uint8_t Key_GetNum(void)
{
	taskENTER_CRITICAL();
	uint8_t KeyNum = 0;
	//当按键按下时,为低电平,进入if,因为是上拉模式,按下为低电平,松手为高电平
	if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
	{
		//按下的过程就像弹簧压缩一样,防止震荡,加个延时函数
		vTaskDelay(10);
		//松手时为上拉状态,此时为高电平,退出循环,
		while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0);
		//防止震荡
		vTaskDelay(10);
		//给按键赋值
		KeyNum = 1;
	}
	taskEXIT_CRITICAL();
	return KeyNum;
}


timer.h

#ifndef __TIMER_H
#define __TIMER_H


//void Timer_Init(void);
void Timer_Init(uint16_t TIM_Period,uint16_t TIM_Prescaler);

void TIMER_FOR_RUN_TIME_STATS(void);

#endif

timer.c

#include "stm32f10x.h"                  // Device header
#include "Serial.h"
#include "FreeRTOS.h"
#include "task.h"



uint32_t VALUE;

void Timer_Init(uint16_t TIM_Period,uint16_t TIM_Prescaler)
{
	//RCC打开时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	
	//选择时基单元的时钟,内部时钟一般默认初始化可以写可以不写
	TIM_InternalClockConfig(TIM2);
	
	//配置时基单元
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	//TIM_CKD_DIV1代表1分屏
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	//代表向上计数
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = TIM_Period;
	//72MHZ分频7200,就是10k,10k计10000个数就是1s
	TIM_TimeBaseInitStructure.TIM_Prescaler = TIM_Prescaler;
	//高级定时器才有,现在是通用定时器给0
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
	
	
	
	
	//如果不加入这一句,会导致复位之后从1开始计数
	TIM_ClearFlag(TIM2, TIM_FLAG_Update);
	
	//TIM_IT_Update代表更新中断,中断控制,用来控制某个中断能不能通往NIVC
	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
	
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 4;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_Init(&NVIC_InitStructure);
	
	
	//启动定时器
	TIM_Cmd(TIM2, ENABLE);
	
}

void TIMER_FOR_RUN_TIME_STATS(void)
{
	
	Timer_Init(10-1,72-1);
	
	VALUE=0;
	
}

void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{
		VALUE++;
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}

main.c

#include "stm32f10x.h"     // Device header
#include "Delay.h"
#include "LED.h"
#include "Key.h"

#include "OLED.h"

#include "Serial.h"
#include "FreeRTOS.h"
#include "task.h"
#include "Timer.h"




uint16_t Num=0;
char WriteBuffer[500];

#define START_STK_DEPTH						128
#define START_TASK_PRIO						1
TaskHandle_t start_task_handler;
void start_task(void * pvParameters);

#define LED2_STK_DEPTH						128
#define LED2_TASK_PRIO						2
TaskHandle_t led2_task_handler;
void led2_task(char * pvParameters);

#define LED3_STK_DEPTH						128
#define LED3_TASK_PRIO						3
TaskHandle_t led3_task_handler;
void led3_task(char * pvParameters);



int main(void)
{
	
	LED_Init();
	Serial_Init();
	Key_Init();
	
	xTaskCreate(            (TaskFunction_t) start_task,		//创建开始任务
							(const char *  ) "start_task",
							(uint16_t      ) START_STK_DEPTH,
							(void *        ) NULL,
							(UBaseType_t   ) START_TASK_PRIO,
							(TaskHandle_t *) &start_task_handler);
	vTaskStartScheduler();  //开启任务调度器			
}

/*******开始任务函数*****/
void start_task(void * pvParameters)
{
	taskENTER_CRITICAL();
	
	xTaskCreate((TaskFunction_t) led2_task,
							(const char *  ) "led2_task",
							(uint16_t      ) LED2_STK_DEPTH,
							(void *        ) NULL,
							(UBaseType_t   ) LED2_TASK_PRIO,
							(TaskHandle_t *) &led2_task_handler); 			
							
	xTaskCreate((TaskFunction_t) led3_task,
							(const char *  ) "led3_task",
							(uint16_t      ) LED3_STK_DEPTH,
							(void *        ) NULL,
							(UBaseType_t   ) LED3_TASK_PRIO,
							(TaskHandle_t *) &led3_task_handler); 	
	
							
	vTaskDelete(start_task_handler);
							
  taskEXIT_CRITICAL();					
}

void led2_task(char * pvParameters)
{
	for(;;)
	{
		
		LED1_Turn();
		vTaskDelay(200);
	} 
}

void led3_task(char * pvParameters)
{
	for(;;)
	{	
		Num=Key_GetNum();
		if(Num==1)
		{
			
			vTaskGetRunTimeStats(WriteBuffer) ;
			Serial_Printf("%s\r\n",WriteBuffer);
			
			
		} 
		vTaskDelay(10);
	}
}

注意:我们这里的任务堆栈大小为128,我之前设置的64,但是我发现设置64在实际操作中会出现错误,例如:我第一次按下按键,能够正常显示任务时间,第二次按下led灯闪烁那个任务会死机,后面怎么按都无效,现在改为128就可以正常运行了。

实验结果:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值