单片机测量代码运行时间方法 | 您所在的位置:网站首页 › stm32单片机计数器 › 单片机测量代码运行时间方法 |
在实际程序的编写中,我们经常会对程序进行一个整体的复盘、优化,或者对算法的运行时间进行测量等等,那么怎么精确的测量我们程序的运行时间呢? 下面我们给出几种方法: 1 使用Keil Debug功能 2 使用逻辑分析仪或示波器等设备测量 3 使用STM32自带定时器进行测量 1 使用Keil Debug功能我们可以使用J-LINK或者ST-link 等仿真器,实现对代码运行时间的测量,首先要设置仿真器仿真的实际频率 首先点击Settings设置 如果工作频率设置不正确,则会造成测量的时间不正确。 仿真器默认采用的是10MHz的工作频率 首先我们点击DEBUG模式 我们可以看到从系统启动到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);
记录下此时时间 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
|
CopyRight 2018-2019 实验室设备网 版权所有 |