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

    关注

    6074

    文章

    45340

    浏览量

    663534
  • 示波器
    +关注

    关注

    113

    文章

    6967

    浏览量

    194693
  • 函数
    +关注

    关注

    3

    文章

    4406

    浏览量

    66838
  • GPIO
    +关注

    关注

    16

    文章

    1313

    浏览量

    55727

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

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

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    Arm Neoverse CPU上大代码量Java应用的性能测试

    Java 是互联网领域广泛使用的编程语言。Java 应用的一些特性使其性能表现与提前编译的原生应用(例如 C 程序)大相径庭。由于 Java 字节无法直接在 CPU 上执行,因此通常运行时
    的头像 发表于 11-05 11:25 371次阅读
    Arm Neoverse CPU上大<b class='flag-5'>代码</b>量Java应用的性能测试

    使用Nuclei Studio IDE计算程序运行时间

    在使用Nuclei Studio IDE进行程序运行时,我们想知道我们编写的程序运行时间有多长怎么办呢?可以选择调用IDE里面时间记录函数_gettimeofday(),该函数用于记录程序运行
    发表于 10-28 08:25

    怎么实现一套容器运行时,并符合OCI规范?

    如题,怎么实现一套容器运行时,并符合OCI规范
    发表于 10-10 07:35

    装置日常运行时的安全防护检查有哪些注意事项?

    装置日常运行时的安全防护检查,核心原则是 “安全优先、不影响生产、快速识别风险”—— 既要避免因检查操作引发触电、停机等事故,也要高效捕捉运行中的动态隐患(如过热、防护松动)。以下是需重点关注的 8
    的头像 发表于 09-23 16:33 749次阅读

    rt-thread线程调用rt_thread_mdelay延时后再恢复运行时thread会变,导致mutex释放失败,怎么解决?

    代码片段如下: 运行结果: 可以看到,在线程延时后,再恢复运行时,用rt_thread_self函数获取到的值与没有延时时获取到的值不一样了,导致mutex无法释放,其它等待这个mutex的线程都无法
    发表于 09-09 08:06

    什么是零代码平台?

    代码平台是一种无需编写传统代码,通过可视化拖拽、参数配置、逻辑连线即可快速搭建业务流程与应用系统的工具平台。它将复杂的软件开发过程转化为 “搭积木” 式的操作,让非技术人员(如业务人员、运营人员
    发表于 07-12 20:28

    MTB如何在运行时介入Jlink调试器?

    目前我们的应用程序在运行时会偶发死机现象,有没有办法能够在CYW43907芯片不复位的情况下介入调试器,查看导致死机的问题
    发表于 07-08 07:46

    PLC设备运行时间数据采集到运维管理平台如何实现

    在工厂设备管理工作中,往往需要统计各个设备的运行时间,能够衡量其运行性能,主要为了方便管理人员对设备进行定期维护,以保障设备处于稳定高效的运行状态,减少故障停机导致生产停工的问题。 对此,物通博联
    的头像 发表于 06-20 16:02 575次阅读
    PLC设备<b class='flag-5'>运行时间</b>数据采集到运维管理平台如何实现

    步进电机在高速运行时反电动势波形与其动态响应变化

    步进电机高速运行时,反电动势幅值增大、频率升高,导致电流建立延迟、扭矩下降及动态响应滞后。所以在步进电机高速运行的方案中,我们需要通过优化电机选型(如低电感、适中极数)、升压驱动及BEMF反馈控制,可缓解高速性能衰减,避免PWM饱和导致的扭矩崩溃。
    的头像 发表于 06-10 16:06 1190次阅读
    步进电机在高速<b class='flag-5'>运行时</b>反电动势波形与其动态响应变化

    可以在运行时通过微控制器配置CCG2 C型板吗?

    我可以在运行时通过微控制器配置 CCG2 C 型板吗?
    发表于 05-07 07:24

    使用STM32F407ZGT6芯片做小车主控时,总是在运行时芯片突然被锁,无法下载程序怎么解决?

    在使用STM32F407ZGT6芯片做小车主控时,总是在运行时芯片突然被锁,无法下载程序。 使用STM32 ST-LINK Utility也无法解除保护
    发表于 03-11 06:20

    在Windows上安装OpenVINO™运行时遇到错误怎么解决?

    已在 Windows* 上安装OpenVINO™运行时。 配置环境变量。 遇到错误: Location is not available.
    发表于 03-05 09:13

    无法在ONNX运行时加载OpenVINO™中间表示 (IR),为什么?

    无法在 ONNX运行时加载OpenVINO™中间表示 (IR)
    发表于 03-05 09:07

    运行时OpenVINO™找不到模型优化器,为什么?

    运行时OpenVINO™找不到模型优化器,运行模型下载程序命令并收到错误消息: omz_downloader:找不到命令
    发表于 03-05 08:16

    智能电机控制装置如何最大限度地提高恢复能力和正常运行时间

    机器恢复能力和正常运行时间的智能电机控制装置。 这些应用中的电机控制装置必须能够控制并保护 75 马力 (HP) 至 700 马力的电机。为实现弹性运行,需要对机器进行全方位的保护,包括过载保护、接地故障保护和相位不平衡保护等。 同时还应包括触点磨损自诊断和线圈过
    的头像 发表于 01-25 16:40 1274次阅读
    智能电机控制装置如何最大限度地提高恢复能力和正常<b class='flag-5'>运行时间</b>