0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

浅析STM32代码运行时间的技巧

STM32嵌入式开发 来源:STM32嵌入式开发 作者:STM32嵌入式开发 2021-11-09 09:52 次阅读

前言

测试代码的运行时间的两种方法:

  • 使用单片机内部定时器,在待测程序段的开始启动定时器,在待测程序段的结尾关闭定时器。为了测量的准确性,要进行多次测量,并进行平均取值。

  • 借助示波器的方法是:在待测程序段的开始阶段使单片机的一个GPIO输出高电平,在待测程序段的结尾阶段再令这个GPIO输出低电平。用示波器通过检查高电平的时间长度,就知道了这段代码的运行时间。显然,借助于示波器的方法更为简便。

借助示波器方法的实例

Delay_us函数使用STM32系统滴答定时器实现:

#include "systick.h"
/* SystemFrequency / 1000    1ms中断一次 * SystemFrequency / 100000     10us中断一次 * SystemFrequency / 1000000 1us中断一次 */
#define SYSTICKPERIOD                    0.000001#define SYSTICKFREQUENCY            (1/SYSTICKPERIOD)
/**  * @brief  读取SysTick的状态位COUNTFLAG  * @param  * @retval The new state of USART_FLAG (SET or RESET).  */static FlagStatus SysTick_GetFlagStatus(void) {if(SysTick->CTRL&SysTick_CTRL_COUNTFLAG_Msk)     {return SET;    }else    {return RESET;    }}
/**  * @brief  配置系统滴答定时器 SysTick  * @param  无  * @retval 1 = failed, 0 = successful  */uint32_t SysTick_Init(void){/* 设置定时周期为1us  */if (SysTick_Config(SystemCoreClock / SYSTICKFREQUENCY))     { /* Capture error */return (1);    }
/* 关闭滴答定时器且禁止中断  */    SysTick->CTRL &= ~ (SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_TICKINT_Msk);                                                  return (0);}
/**  * @brief   us延时程序,10us为一个单位  * @param  *        @arg nTime: Delay_us( 10 ) 则实现的延时为 10 * 1us = 10us  * @retval  无  */void Delay_us(__IO uint32_t nTime){     /* 清零计数器并使能滴答定时器 */    SysTick->VAL   = 0;      SysTick->CTRL |=  SysTick_CTRL_ENABLE_Msk;     
for( ; nTime > 0 ; nTime--)    {/* 等待一个延时单位的结束 */while(SysTick_GetFlagStatus() != SET);    }
/* 关闭滴答定时器 */    SysTick->CTRL &= ~ SysTick_CTRL_ENABLE_Msk;}

检验Delay_us执行时间中用到的GPIO(gpio.h、gpio.c)的配置:


		
#ifndef __GPIO_H#define    __GPIO_H
#include "stm32f10x.h"
#define     LOW          0#define     HIGH         1
/* 带参宏,可以像内联函数一样使用 */#define TX(a)                if (a)                                                GPIO_SetBits(GPIOB,GPIO_Pin_0);else                                                    GPIO_ResetBits(GPIOB,GPIO_Pin_0)void GPIO_Config(void);
#endif
#include "gpio.h"
/**  * @brief  初始化GPIO  * @param  无  * @retval 无  */void GPIO_Config(void){        /*定义一个GPIO_InitTypeDef类型的结构体*/        GPIO_InitTypeDef GPIO_InitStructure;
/*开启LED的外设时钟*/        RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE); 
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;             GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;         GPIO_Init(GPIOB, &GPIO_InitStructure);    }

在main函数中检验Delay_us的执行时间:

dce66dd8-3fbe-11ec-9195-dac502259ad0.png

示波器的观察结果:

dd590280-3fbe-11ec-9195-dac502259ad0.png

dd8a5a10-3fbe-11ec-9195-dac502259ad0.png

可见Delay_us(100),执行了大概102us,而Delay_us(1)执行了2.2us。

更改一下main函数的延时参数

ddbb944a-3fbe-11ec-9195-dac502259ad0.png

示波器的观察结果:

de23e14e-3fbe-11ec-9195-dac502259ad0.png

de616afa-3fbe-11ec-9195-dac502259ad0.png

可见Delay_us(100),执行了大概101us,而Delay_us(10)执行了11.4us。

结论:此延时函数基本上还是可靠的。

使用定时器方法的实例

Delay_us函数使用STM32定时器2实现:

#include "timer.h"
/* SystemFrequency / 1000            1ms中断一次 * SystemFrequency / 100000     10us中断一次 * SystemFrequency / 1000000         1us中断一次 */
#define SYSTICKPERIOD                    0.000001#define SYSTICKFREQUENCY            (1/SYSTICKPERIOD)
/**  * @brief  定时器2的初始化,,定时周期1uS  * @param  无  * @retval 无  */void TIM2_Init(void){    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
/*AHB = 72MHz,RCC_CFGR的PPRE1 = 2,所以APB1 = 36MHz,TIM2CLK = APB1*2 = 72MHz */    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
/* Time base configuration */    TIM_TimeBaseStructure.TIM_Period = SystemCoreClock/SYSTICKFREQUENCY -1;    TIM_TimeBaseStructure.TIM_Prescaler = 0;    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
    TIM_ARRPreloadConfig(TIM2, ENABLE);
/* 设置更新请求源只在计数器上溢或下溢时产生中断 */    TIM_UpdateRequestConfig(TIM2,TIM_UpdateSource_Global);     TIM_ClearFlag(TIM2, TIM_FLAG_Update);}
/**  * @brief   us延时程序,10us为一个单位  * @param    *        @arg nTime: Delay_us( 10 ) 则实现的延时为 10 * 1us = 10us  * @retval  无  */void Delay_us(__IO uint32_t nTime){     /* 清零计数器并使能滴答定时器 */    TIM2->CNT   = 0;      TIM_Cmd(TIM2, ENABLE);     
for( ; nTime > 0 ; nTime--)    {/* 等待一个延时单位的结束 */while(TIM_GetFlagStatus(TIM2, TIM_FLAG_Update) != SET);     TIM_ClearFlag(TIM2, TIM_FLAG_Update);    }
    TIM_Cmd(TIM2, DISABLE);}

在main函数中检验Delay_us的执行时间:

#include "stm32f10x.h"#include "Timer_Drive.h"#include "gpio.h"#include "systick.h"
TimingVarTypeDef Time;
int main(void){        TIM2_Init();        SysTick_Init();    SysTick_Time_Init(&Time);
for(;;)    {        SysTick_Time_Start();         Delay_us(1000);        SysTick_Time_Stop();    }     }

怎么去看检测结果呢?用调试的办法,打开调试界面后,将Time变量添加到Watch一栏中。然后全速运行程序,既可以看到Time中保存变量的变化情况,其中TimeWidthAvrage就是最终的结果。

deae81be-3fbe-11ec-9195-dac502259ad0.png

可以看到TimeWidthAvrage的值等于0x119B8,十进制数对应72120,滴答定时器的一个滴答为1/72M(s),所以Delay_us(1000)的执行时间就是72120*1/72M (s) = 0.001001s,也就是1ms。验证成功。

备注:定时器方法输出检测结果有待改善,你可以把得到的TimeWidthAvrage转换成时间(以us、ms、s)为单位,然后通过串口打印出来,不过这部分工作对于经常使用调试的人员来说也可有可无。相关推荐:学习STM32单片机,绕不开的串口

两种方法对比

软件测试方法

操作起来复杂,由于在原代码基础上增加了测试代码,可能会影响到原代码的工作,测试可靠性相对较低。由于使用32位的变量保存systick的计数次数,计时的最大长度可以达到2^32/72M = 59.65 s。

示波器方法

操作简单,在原代码基础上几乎没有增加代码,测试可靠性很高。由于示波器的显示能力有限,超过1s以上的程序段,计时效果不是很理想。但是,通常的单片机程序实时性要求很高,一般不会出现程序段时间超过秒级的情况。

编辑:jq
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 单片机
    +关注

    关注

    5991

    文章

    43904

    浏览量

    619626
  • 示波器
    +关注

    关注

    110

    文章

    5563

    浏览量

    181471
  • 函数
    +关注

    关注

    3

    文章

    3845

    浏览量

    61225
  • GPIO
    +关注

    关注

    16

    文章

    1124

    浏览量

    50414

原文标题:获取STM32代码运行时间的技巧

文章出处:【微信号:c-stm32,微信公众号:STM32嵌入式开发】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    stm32做https的server ,serverkeychange运行时间10多s怎么优化?

    stm32做https的server ,serverkeychange这一步运行时间10多s,求优化办法
    发表于 03-27 08:03

    如何在运行时擦除/编程UCB?

    我有一个项目需要在现场更新 SOTA。 这需要在运行时更新必要的 UCB 值。 我已经看过擦除/编程 PFLASH 和 DFLASH 的示例代码,但我还没有找到任何特定于 UCB 内存的代码。 我
    发表于 01-22 07:18

    jvm运行时内存区域划分

    JVM是Java Virtual Machine(Java虚拟机)的缩写,它是Java编程语言的运行环境。JVM的主要功能是将Java源代码转换为机器代码,并且在运行时管理Java程序
    的头像 发表于 12-05 14:08 220次阅读

    西门子SCL编程50台电机运行时间累计方法

    当RUN信号为TRUE时,开始计时,为FALSE时停止计时,单次运行时间清零,长按RESET为5秒时,单次和总运行时间都清零。
    发表于 11-27 09:59 636次阅读
    西门子SCL编程50台电机<b class='flag-5'>运行时间</b>累计方法

    如何在 CFD 设计中利用网格维护几何形状并减少运行时间

    如何在 CFD 设计中利用网格维护几何形状并减少运行时间
    的头像 发表于 11-24 17:07 188次阅读
    如何在 CFD 设计中利用网格维护几何形状并减少<b class='flag-5'>运行时间</b>?

    MES如何帮助增加机器正常运行时间

           实施制造执行系统(MES)的好处很多。其中,MES软件可以通过多种方式帮助增加机器的正常运行时间。正常运行时间是指制造机械或设备的效率和可用性。每当机器停机(无论原因如何)时,制造商
    发表于 11-14 15:28 2次下载

    如何保证它们容器运行时的安全?

    紧密耦合的容器运行时继承了主机操作系统的安全态势和攻击面。运行时或主机内核中的任何漏洞及其利用都会成为攻击者的潜在切入点。
    的头像 发表于 11-03 15:24 265次阅读

    MDK中怎么看程序的运行时间

    如何才能观察一段程序的运行时间
    发表于 10-25 08:08

    Melexis推出延长物联网电池运行时间的耗霍尔开关MLX92216

    Melexis推出超低功耗霍尔开关MLX92216和MLX92217,具有功耗仅为1微瓦且误差更小等优势,有助于准确预测电力成本并延长电池运行时间
    的头像 发表于 10-07 15:46 606次阅读

    Xilinx运行时(XRT)发行说明

    电子发烧友网站提供《Xilinx运行时(XRT)发行说明.pdf》资料免费下载
    发表于 09-14 10:01 0次下载
    Xilinx<b class='flag-5'>运行时</b>(XRT)发行说明

    ch32v307记录程序运行时间

    ch32v307记录程序运行时间 在程序开发中,很重要的一项任务就是对程序的运行时间进行评估。对于大型的程序系统来说,它们通常需要处理大量的数据或进行复杂的计算操作。因此,如果程序的运行时间过长
    的头像 发表于 08-22 15:53 426次阅读

    JVM运行时数据区之堆内存

    说一下 JVM 运行时数据区吧,都有哪些区?分别是干什么的?
    的头像 发表于 08-19 14:35 401次阅读
    JVM<b class='flag-5'>运行时</b>数据区之堆内存

    Linux虚拟运行时间的计算

    虚拟运行时间的计算 关于tick: tick是周期性的时钟中断,时钟中断驱动调度器runing,其周期间隔根据硬件频率的设定相关(T=1/f),如下: T=1/250 = 4ms,也就说时钟中断
    的头像 发表于 07-31 11:15 449次阅读
    Linux虚拟<b class='flag-5'>运行时间</b>的计算

    怎样避免电力电容器运行时漏油

    电力电容器运行中,会因为各种因素出现故障。在电力电容器运行时遇到的故障中,出现渗油和漏油的概率非常大。那么如何避免电力电容器运行时漏油呢?库克库伯电气会在接下来的文章中,针对电力电容器漏油的原因进行分析,提出解决电容器漏油的方法
    的头像 发表于 04-07 16:01 527次阅读

    正常运行时间保护底线

    本教程探讨了增加正常运行时间的各种注意事项以及它们如何影响底线。这些包括工业设施的维护方法,例如工厂、商业设施、发电厂或其他安装,在这些设施中,适当的维护方法可以防止灾难性故障。但是,保持底线需要更多。还必须考虑可靠性、安全性、功耗、故障检测和正确设计的设备,以满足行业标准。
    的头像 发表于 04-06 11:10 674次阅读
    正常<b class='flag-5'>运行时间</b>保护底线