STM32兴趣篇三:基于STM32F103C8T6工控板利用定时器计算某段代码的运行时间

记录一下,方便以后翻阅~
本人参考了热心网友分享的一些案例,并增加了一些个人认为比较好的想法,重新整合了一下代码。
在这里插入图片描述
硬件:某宝网上购买的STM32F103C8T6工控板,价格50¥左右;

思路
1)利用通用定时器(选择定时器2)计算某段代码的运行时间;
2)顾名思义,会基于定时器2创建两个函数(TIM2_Clock_Start和TIM2_Clock_End)分别控制定时器2开始计时和结束计时,被测代码放在这两个代码的中间;
3)考虑计时的精度和最大计时长度,创建变量 u8 OverflowNum_cnt用来计算定时器2溢出中断的次数,创建变量u16 cnt_value用来计算最后一次定时器2的cnt值;
4)利用USART1实时读取某段代码的运行时间,并上传至电脑,便于查看。

这个工程较为简单,主要代码如下:

  1. 定时器2的初始化配置代码,注意:初始化后,不使能TIM2!!
/*****************************************************************
函数名称:TIM2_Init(u16 arr, u16 psc)
函数功能:定时器2 初始化函数
入口参数:u16 arr:自动重装载值, u16 psc:时钟预分频数
返回参数:无
开发作者:闲人Ne
******************************************************************/
void TIM2_Init(u16 arr, u16 psc)
{
    
    
  TIM_TimeBaseInitTypeDef TIM_TimeBaseInitTypeStruct;
  TIM_DeInit(TIM2);									               // 定时器 2 复位
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);              // 使能TIM 2 时钟
  // 定时器 2 参数初始化配置
  TIM_TimeBaseInitTypeStruct.TIM_Period=arr;
  TIM_TimeBaseInitTypeStruct.TIM_Prescaler=psc;
  TIM_TimeBaseInitTypeStruct.TIM_CounterMode=TIM_CounterMode_Up;   // 向上计数模式
  TIM_TimeBaseInitTypeStruct.TIM_ClockDivision=TIM_CKD_DIV1; 
  TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitTypeStruct);
  // 定时器 3 中断优先级配置
  NVIC_Configuration();
}
  1. 定时器2开始和结束相关代码,注意:引用了2个放在main.c文件里的变量!!
/*****************************************************************
函数名称:TIM2_Clock_Start()
函数功能:使能定时器 2 函数,开始计时
入口参数:无
返回参数:无
开发作者:闲人Ne
******************************************************************/
extern u8  OverflowNum_cnt;			            // u8 计数器,用来计算溢出中断的次数,初始化值为0000 0000
void TIM2_Clock_Start()
{
    
    
	OverflowNum_cnt = 0;
	TIM2->CNT=0x00;                             // 将定时器 2 的计数器至零
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);    // 针对TIM2_DIER寄存器,[0]位,UIE至1,允许更新中断
	TIM_Cmd(TIM2,ENABLE);  
}
/*****************************************************************
函数名称:u16 TIM2_Clock_End()
函数功能:停止定时器 2 函数,读取CNT数值
入口参数:无
返回参数:u16 cnt_value,返回当前TIM2_CNT的值
开发作者:闲人Ne
******************************************************************/
extern u16 cnt_value;
u16 TIM2_Clock_End()
{
    
    
	cnt_value = TIM2->CNT;
	TIM_Cmd(TIM2,DISABLE);
	return cnt_value;
}
  1. 定时器2的中断服务函数,主要目的是每发生一次溢出中断,OverflowNum_cnt值+1,如果OverflowNum_cnt值溢出,就报错。
/************************************************
函数名称:TIM2_IRQHandler()
函数功能:定时器2中断服务函数
入口参数:无
返回参数:无
开发作者:闲人Ne
*************************************************/
extern u8  OverflowNum_cnt;								  // u8 计数器,用来计算溢出中断的次数,初始化值为0000 0000	    				
void TIM2_IRQHandler(void)
{
    
     
	if(TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)	      // 判断是否发生更新中断
	{
    
    
		if(OverflowNum_cnt==0XFF)    					  // 判断OverflowNum_cnt是否溢出 			
		{
    
    	  
			printf("错误:超出最大计算时间!");
			OverflowNum_cnt = 0;                          // OverflowNum_cnt置零
		}
		else
		{
    
    
			OverflowNum_cnt++;
		}
    	TIM_ClearITPendingBit(TIM2,TIM_IT_Update);       // 清除定时器2中断标志位
	}
}
  1. 主函数,这里注意,当TIM2_arr = 7199,TIM2_psc = 0,那么TIM2 中断时间间隔为0.0001s,又因为u8 OverflowNum_cnt最大值为255,所以所创建的定时器2计算某段代码的运行时间上限是0.0001 X 255 = 0.0255s,即25.5ms。如果被测代码的实际运行时间大于25.5ms,那么就不适用了。
/************************************************
函数名称:int main()
函数功能:主函数入口
入口参数:无
返回参数:int
开发作者:闲人Ne
*************************************************/
u8  OverflowNum_cnt = 0;     // 溢出的次数
u16 cnt_value       = 0;     // 最后一次cnt的数值
u16 TIM2_arr = 7199;  
u16 TIM2_psc = 0;
float TIM2_looptime = 0.0001;    		   // TIM2 中断时间间隔,TIM2_looptime=((TIM2_psc+1)/72000000)*(TIM2_arr+1)
float TIM2_clock = 0.0000000138888888888;  // TIM2 cnt更新周期,TIM2_clock=1/72000000
u16 delay_time_ms=10;                      // 模拟某段代码的运行时间
int main(void)
{
    
    
  float CodeRunTime=0;     	 // 计算某段代码的运行时间
  u8 t=0;                  	 // while循环计数用
  delay_init();
  LED_Init();
  My_USART1_Init();  
  TIM2_Init(TIM2_arr, TIM2_psc);	
  NVIC_Configuration();
  while(1)
  {
    
    
	TIM2_Clock_Start();
    delay_ms(delay_time_ms);             // 某段代码的运行时间
	cnt_value=TIM2_Clock_End();
	CodeRunTime = (float)cnt_value*TIM2_clock+(float)OverflowNum_cnt*TIM2_looptime;		
	t++;
	if(t==100)
	{
    
    
		printf("设定某段代码的运行时间为:%d毫秒\r\n",delay_time_ms);
		printf("实际某段代码的运行时间为:%f秒\r\n\r\n",CodeRunTime);
		D1=!D1;     //提示系统正在运行//	
		t=0;
	}		 
	delay_time_ms=delay_time_ms+1;
	if(delay_time_ms>20)
		delay_time_ms=10;		
  }
}

实验结果
在串口调试助手上显示结果如下:
在这里插入图片描述
经验分享
为什么要测试代码的运算时间?因为有时候,程序没必要运算的非常快,适当的降低运算时间,可以降低功耗。此外,有些功能需要实时的、快速的给与反馈,比如自动驾驶、无人机、主动控制这类工作,如果算法很牛逼,但是运算一次周期长,那也没什么实际用处。

猜你喜欢

转载自blog.csdn.net/Leisure_ksj/article/details/112095764