单片机测量代码运行时间方法-STM32
Posted Z小旋
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单片机测量代码运行时间方法-STM32相关的知识,希望对你有一定的参考价值。
在实际程序的编写中,我们经常会对程序进行一个整体的复盘、优化,或者对算法的运行时间进行测量等等,那么怎么精确的测量我们程序的运行时间呢?
下面我们给出几种方法:
- 1 使用Keil Debug功能
- 2 使用逻辑分析仪或示波器等设备测量
- 3 使用STM32自带定时器进行测量
1 使用Keil Debug功能
我们可以使用J-LINK或者ST-link 等仿真器,实现对代码运行时间的测量,首先要设置仿真器仿真的实际频率
首先点击Settings设置
然后点击Trace 设置我们芯片的系统频率,点击Teace Enable 使能
如果工作频率设置不正确,则会造成测量的时间不正确。
仿真器默认采用的是10MHz的工作频率
首先我们点击DEBUG模式
1.然后会跳转到main.c
我们可以看到从系统启动到main.c所需要的时间是0.00000367秒
2.我们在需要测量的程序段开始和结束的地方设置断点
3 通过起始断点和结束断点处读取到的时间,结束时间-起始时间,即可判断代码段执行的时间。
我们用500ms延时的流水灯来举例:
测量代码:
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET); //PB0置0
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET); //PB1置0
delay_ms(500);
点击RUN 运行代码 到起始断点处停止
记录下此时时间 t1=0.00008590s
再次点击RUN 运行代码 到结束断点处停止
记录下此时时间 t2=0.50014558s
代码运行时间是: t2-t1=0.50014558-0.00008590=0.50005968s≈500ms
最后的0.00005968s 是运行上面两个LED高电平函数,所需要的CPU指令时间以及误差时间
总结:
使用keil的debug模式进行测量,非常方便,可以很随意的对任意段代码进行测量,并且误差很小,操作方便。
2 使用逻辑分析仪或示波器等设备测量
在待测程序段的开始阶段使单片机的一个GPIO输出高电平,在待测程序段的结尾阶段再令这个GPIO输出低电平。用示波器或者逻辑分析仪通过检查高电平的时间长度,就知道了这段代码的运行时间。
while(1)
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_SET); //PB1置1
delay_ms(500);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET); //PB1置0
delay_ms(500);
延时500ms时波形如下:
修改延时为100ms:
while(1)
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_SET); //PB1置1
delay_ms(100);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET); //PB1置0
delay_ms(100);
波形如下
总结:
使用示波器测量较为准确,缺点是需要单独的示波器或者逻辑分析仪等,示波器一般体积较大的还需要供电,并且还要连接GPIO口,还是有点麻烦的
3 使用STM32自带定时器进行测量
定时器本质上就是向上累加的计数器(如果配置成向上计数时),所以我们在测量开始的代码前面读取定时器的计数器,在结束测量的位置再读取定时器的计数器,获得两次的差值,这样就可以计算出这段代码的运行的时间。 这就是其原理
这里我们使用TIM3定时器
定时器初始化:
- 定时器3初始化,我们使用STM32H7,定时器时钟为200M,分频系数为20000-1,
- 所以定时器3的频率为200M/20000=10KHz 周期是T=1/F=1/10000=100us ,自动重装载为65535-1,
- 那么定时器周期就是T=65535*100us=6.5535s
void TIM3_Init(u16 arr,u16 psc)
TIM3_Handler.Instance=TIM3; //通用定时器3
TIM3_Handler.Init.Prescaler=psc; //分频
TIM3_Handler.Init.CounterMode=TIM_COUNTERMODE_UP; //向上计数器
TIM3_Handler.Init.Period=arr; //自动装载值
TIM3_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;//时钟分频因子
HAL_TIM_Base_Init(&TIM3_Handler);
HAL_TIM_Base_Start_IT(&TIM3_Handler); //使能定时器3和定时器3更新中断:TIM_IT_UPDATE
TIM3_Init(65535-1,20000-1); //定时器3初始化,定时器时钟为200M,分频系数为20000-1,
//所以定时器3的频率为200M/20000=10KHz 周期是T=1/F=1/10000=100us ,自动重装载为65535-1,
//那么定时器周期就是T=65535*100us=6.5535s
代码测试:
我们还是以LED流水灯翻转200ms为例,看下定时器测得的时间:
int Start_count=0; //开始计时定时器值
int End_count=0; //结束计时定时器值
int Time; //代码运行时间
int main(void)
Cache_Enable(); //打开L1-Cache
HAL_Init(); //初始化HAL库
Stm32_Clock_Init(160,5,2,4); //设置时钟,400Mhz
LED_Init(); //初始化LED
TIM3_Init(65535-1,20000-1); //定时器3初始化,定时器时钟为200M,分频系数为20000-1,
//所以定时器3的频率为200M/20000=10KHz 周期是T=1/F=1/10000=100us ,
//自动重装载为65535-1,那么定时器周期就是6.5535S
//计数1次等于100us 单位0.1ms
while(1)
//开始计时
Start_count=__HAL_TIM_GET_COUNTER(&TIM3_Handler); //获取定时器的值,开始计时
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_SET); //PB1置1
delay_ms(100);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET); //PB1置0
delay_ms(100);
//结束计时
End_count=__HAL_TIM_GET_COUNTER(&TIM3_Handler); //获取定时器的值,结束计时
Time=(End_count-Start_count)/10; //时间(ms)=结束值-开始值+定时器溢出次数*65535
上面代码的思想就是在代码开始运行前,测得定时器的初始值,然后在代码结束的位置,再测得定时器的值,最终的代码运行时间:
Time=(End_count-Start_count)/10; //时间(ms)=结束值-开始值
测得时间为200ms
当然,如果我们的代码运行时间超过了6.5535秒,就要考虑定时器中断溢出的情况,我们的代码如下:
int COUNT=0; //定时器溢出次数
int Start_count=0; //开始计时定时器值
int End_count=0; //结束计时定时器值
int Time;
int main(void)
Cache_Enable(); //打开L1-Cache
HAL_Init(); //初始化HAL库
Stm32_Clock_Init(160,5,2,4); //设置时钟,400Mhz
delay_init(400); //延时初始化
LED_Init(); //初始化LED
TIM3_Init(65535-1,20000-1); //定时器3初始化,定时器时钟为200M,分频系数为20000-1,
//所以定时器3的频率为200M/20000=10KHz 周期是T=1/F=1/10000=100us ,
//自动重装载为65535-1,那么定时器周期就是6.5535S
//计数1次等于100us 单位0.1ms
while(1)
//开始计时
COUNT=0; //每次开始计时将COUNT清零
__HAL_TIM_SET_COUNTER(&TIM3_Handler,0); //获取定时器的值,开始计时
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_SET); //PB1置1
delay_ms(100);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET); //PB1置0
delay_ms(100);
//结束计时
End_count=__HAL_TIM_GET_COUNTER(&TIM3_Handler); //获取定时器的值,结束计时
Time=(End_count+COUNT*65535)/10; //时间(ms)=结束值-开始值+定时器溢出次数*65535
//定时器3中断服务函数调用
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
if(htim==(&TIM3_Handler))
COUNT++;
上面代码的思想就是在代码开始运行前,定时器的计数值设置为0,然后在代码结束的位置,再测得定时器的值,如果代码运行时间过长,定时器中断中COUNT就加1,最终的代码运行时间:
Time=(End_count+COUNT65535)/10; //时间(ms)=结束值+定时器溢出次数65535
测得时间为200ms
总结:
这种方法比较方便的是代码的运行时间是一个变量,我们可以在程序中使用这个变量,这是很方便的,但是要占用一个定时器。
以上是关于单片机测量代码运行时间方法-STM32的主要内容,如果未能解决你的问题,请参考以下文章
STM32实现六轴姿态测量陀螺仪模块JY61P(标准库与HAL库实现)