单片机测量代码运行时间方法 您所在的位置:网站首页 stm32单片机计数器 单片机测量代码运行时间方法

单片机测量代码运行时间方法

2023-04-04 13:43| 来源: 网络整理| 查看: 265

在实际程序的编写中,我们经常会对程序进行一个整体的复盘、优化,或者对算法的运行时间进行测量等等,那么怎么精确的测量我们程序的运行时间呢?

下面我们给出几种方法:

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

总结: 这种方法比较方便的是代码的运行时间是一个变量,我们可以在程序中使用这个变量,这是很方便的,但是要占用一个定时器。

请添加图片描述 请添加图片描述

您可能感兴趣的内容: “Exploring PWM and HAL Library Applications with STM32: A Comprehensive Guide” “构建STM32单片机温湿度检测系统:集成DTH11、OLED和LCD1602显示屏” 《蓝桥杯嵌入式编程:快速入门》 FOC无刷电机控制:六步换向、FOC STM32cubemx从零开始搭建BLDC六步换相代码、FOC代码(基于霍尔传感器) 【基于STM32的TFT-LCD显示:内容丰富、代码实例齐全】


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有