你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

有哪些技巧可以获取STM32代码运行时间?

[复制链接]
攻城狮Melo 发布时间:2024-5-24 18:15
前言    ' j- |/ g& S- M
测试代码的运行时间的两种方法:
  • 使用单片机内部定时器,在待测程序段的开始启动定时器,在待测程序段的结尾关闭定时器。为了测量的准确性,要进行多次测量,并进行平均取值。
  • 借助示波器的方法是:在待测程序段的开始阶段使单片机的一个GPIO输出高电平,在待测程序段的结尾阶段再令这个GPIO输出低电平。用示波器通过检查高电平的时间长度,就知道了这段代码的运行时间。显然,借助于示波器的方法更为简便。
    4 a' Z* R- O% ]" D+ O- o

: d2 C$ S: F  B9 N# ]" S  J1 |5 r3 K) W4 V- i
. H  Q* A" {% ?2 M$ T$ U& ^5 ]
借助示波器方法的实例   
1 f) y, I! V7 ~( }9 P5 J: m. [, {# B1 |5 @0 n" `- f! \
# q  U8 v0 q, F. _6 N! n5 W( i
Delay_us函数使用STM32系统滴答定时器实现:
1 Z/ f+ K7 z, A; N+ `+ L+ e
  1. #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;}
复制代码

' Z' J% o. E; [8 P3 O  x2 u: L& M# N' a7 I* o8 A8 b
' C3 F: ]. }; V$ `& [
检验Delay_us执行时间中用到的GPIO(gpio.h、gpio.c)的配置:
( u: J# W1 t' g1 y
  1. #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);    }
复制代码

2 Y. ^/ k& l% I7 k: D
+ c4 |0 r* A% W* C在main函数中检验Delay_us的执行时间:# w1 e. g2 G5 i$ |

4 j" W- C' |& C8 O* }/ ~2 ?
! J. `4 O( G: C0 G) @) r
微信图片_20240524181424.png . v( `: }7 o. q2 p9 L* q

5 f* X. N' X2 C# w8 v
% q+ W3 H. t" t* W
" Y' E4 e) R4 p% B- a* A
    示波器的观察结果:. z) c+ x: E8 f$ [# w
微信图片_20240524181439.png
, Q4 r1 ^5 O+ H7 H, }* S
8 K" Q7 l  j# B$ ^4 o0 @5 ~  J! Y; v$ w
微信图片_20240524181443.png % S6 z3 u' D4 _' Q
( i( R, G+ E! a3 k! m: _8 a* o# ^5 k
    可见Delay_us(100),执行了大概102us,而Delay_us(1)执行了2.2us。   
7 s4 {0 E- z" w. \# f4 e; z" Y& U. y! e( q% h! }
3 s* A0 @6 y. d- T7 \5 l0 B
更改一下main函数的延时参数:  s- z% f' j/ ]: w
" W% S" H6 p: @$ k, _7 K7 S

5 g  y4 }8 [; D! _* M0 b! ? 微信图片_20240524181448.png - z# ]# l6 I) H5 a
3 p4 g' \. K2 x, v: u# `
, f! V& r5 L3 H; D/ m/ i

1 H3 Q: V  O6 V" j- u# C5 f4 G4 y1 m    示波器的观察结果:
5 L. j2 E- D- w
微信图片_20240524181451.png
" ?1 f$ s+ s6 J* v. t5 ]$ M
微信图片_20240524181454.png 0 B. l5 z: q) r" Q4 g

+ B* S" x9 ], Y5 C    可见Delay_us(100),执行了大概101us,而Delay_us(10)执行了11.4us。   
1 a+ z8 T% i0 F- @
5 g+ m$ f. O' o9 V
2 p2 S; Q- J/ B: D
结论:此延时函数基本上还是可靠的。
( l4 o) i3 o1 R  ^9 N, E1 B& l9 T* a
' t: V+ _; E9 a* N4 d  M
使用定时器方法的实例    4 F* r, ^3 j5 m

7 E- C6 C  s" \' c7 d

4 _# G. H4 {- iDelay_us函数使用STM32定时器2实现:
( n/ U% W' R6 o3 d" d, N
  1. #include "timer.h"7 b( e( \& e! |0 e# w7 S

  2. , \# ~3 o/ f  q! U% n2 c8 j6 r; r
  3. /* SystemFrequency / 1000            1ms中断一次# ~' f; _* t3 F& E) y
  4. * SystemFrequency / 100000     10us中断一次
    * M- F! A( y& s, s4 E% J, |, n
  5. * SystemFrequency / 1000000         1us中断一次
    " l8 s1 D: D4 N4 K2 l( U8 c- a. ~
  6. */
    & [& `8 p$ ?, Y2 E/ S
  7. $ F. I7 y" w% w) T5 X* @8 K. e4 `2 p
  8. #define SYSTICKPERIOD                    0.000001
    8 E; d4 ?( r1 a* i3 O9 x. f5 @  X
  9. #define SYSTICKFREQUENCY            (1/SYSTICKPERIOD)
    / x( F3 o" ]8 t! B0 B9 j  o* N) l

  10. 2 P+ n' i- W4 u$ Y/ l
  11. /**
    9 _8 i3 u  j5 O/ c( f2 ?
  12.   * @brief  定时器2的初始化,,定时周期1uS3 v( C& P( M$ P! w  [; X9 p
  13.   * @param  无
    0 J9 N( i! g/ Y
  14.   * @retval 无
    9 `# W, m& j4 o' j; E
  15.   */: ~& R' x/ W/ a( j) g
  16. void TIM2_Init(void)
    ! h' r0 h( Z3 u8 C% A5 a
  17. {
    5 \1 @% g2 }7 d! j* f! k
  18.     TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;; ?+ J" X# J0 m  ]& c- g6 n

  19. 1 q* a& q$ d. j; Z3 z) i
  20. /*AHB = 72MHz,RCC_CFGR的PPRE1 = 2,所以APB1 = 36MHz,TIM2CLK = APB1*2 = 72MHz */1 _! n, _, y/ K
  21.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);! i: i, i0 H7 L

  22. 5 |) |7 [2 ~  C
  23. /* Time base configuration */
    4 _# R( m3 m( q3 n" N6 {& e
  24.     TIM_TimeBaseStructure.TIM_Period = SystemCoreClock/SYSTICKFREQUENCY -1;* F  }; f1 W& J) {/ d+ q" t- {% {
  25.     TIM_TimeBaseStructure.TIM_Prescaler = 0;) N8 ]" M/ i; N) o' b( ?
  26.     TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    * z* V( I8 ~0 ?. q/ B! K( [5 O7 a
  27.     TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);+ v, f. m  t" g
  28. " F1 v5 W7 e+ d# i0 R
  29.     TIM_ARRPreloadConfig(TIM2, ENABLE);
    / a8 J, O' O- h1 D/ r

  30. 1 p" q; C9 a1 Q' M' d: y/ Q# `
  31. /* 设置更新请求源只在计数器上溢或下溢时产生中断 */3 g' B, o: ~4 e8 y
  32.     TIM_UpdateRequestConfig(TIM2,TIM_UpdateSource_Global);
    / y/ }! K' e# n  r+ v. o2 b
  33.     TIM_ClearFlag(TIM2, TIM_FLAG_Update);
    * L2 O9 v+ M7 f, M$ g" H) O, w
  34. }
    1 `6 H; `+ H3 g: d
  35. - @7 `# |( ]" a" T" l6 r
  36. /**+ \" b  W# ^/ R3 J1 [6 g& |
  37.   * @brief   us延时程序,10us为一个单位+ ~; y2 Y5 g" J$ p( x6 V/ H
  38.   * @param  
    + q4 |- W2 V1 b# |/ a! {9 t
  39.   *        @arg nTime: Delay_us( 10 ) 则实现的延时为 10 * 1us = 10us
    4 Z" F5 i  u* e- \: S) k
  40.   * @retval  无4 f8 r* v) J. q
  41.   */( u+ i# _( x9 ^2 g9 w' w
  42. void Delay_us(__IO uint32_t nTime)8 U1 M# }. ~  W5 w3 x
  43. {     6 ?$ N4 e- D- `
  44. /* 清零计数器并使能滴答定时器 */$ l+ ~( T( R5 ^9 J. U
  45.     TIM2->CNT   = 0;  
    : E0 \! I- ?  K2 v1 i
  46.     TIM_Cmd(TIM2, ENABLE);     ; D/ z9 Q* ~' g$ d. I& r
  47. 6 f  y2 b5 X% U9 M6 @. m4 @
  48. for( ; nTime > 0 ; nTime--)
    7 V7 j/ o9 V, g' W# s! f$ G% s
  49.     {0 O" l* }/ R1 j$ v
  50. /* 等待一个延时单位的结束 */+ J% ^# x5 f! k  X
  51. while(TIM_GetFlagStatus(TIM2, TIM_FLAG_Update) != SET);
    6 r& H# a5 u  V  e. {; w" Q  c  F
  52.      TIM_ClearFlag(TIM2, TIM_FLAG_Update);4 j% N$ i* @7 U+ n- Z. E& T8 o
  53.     }
    / R: r% _/ M& R6 {$ i( l9 J

  54. $ r- _( k) O+ x. ]/ J5 T: D" Y
  55.     TIM_Cmd(TIM2, DISABLE);, J, J! x; S4 F% a0 S: Z
  56. }
复制代码
! ^/ Z0 D, Q. u( m8 B3 E5 E

7 T& L. ~; v+ {8 p3 \1 w2 \

+ \- ?6 u. Y3 e  r在main函数中检验Delay_us的执行时间:
3 r0 v2 U! w# ]% W
  1. #include "stm32f10x.h"  X3 [' v  L6 W  |
  2. #include "Timer_Drive.h"
    ; f' U, u. ?! m4 M& |9 N+ T
  3. #include "gpio.h"( y  W- a- B; ~- t9 _: u
  4. #include "systick.h"! z! w( f& D* J& R! S/ n
  5. ; j1 x4 V. b, R. F; x% i$ f. k
  6. TimingVarTypeDef Time;; u/ s$ i6 N/ Y' a
  7. ' _7 b% s& ^! T% d4 q; D
  8. int main(void)( d0 u: A, l0 y9 t1 q! q4 _/ J
  9. {    4 ^: h+ L+ U4 q3 }% p
  10.     TIM2_Init();    + `' x/ U$ X, w$ Y; a7 \* L# Y
  11.     SysTick_Init();1 |5 M# j7 A0 W7 |( r' m
  12.     SysTick_Time_Init(&Time);: ~/ {; P. C* A( v+ j

  13. # h0 L, y  M! \8 @& G
  14. for(;;)
    * b7 Y% H: `# {: p! x. y
  15.     {7 z% j7 v6 E4 N$ u) z
  16.         SysTick_Time_Start(); 4 l$ K# e( \6 \
  17.         Delay_us(1000);
    8 M5 F; m0 ?8 U6 Z
  18.         SysTick_Time_Stop();
    & x. R, t* \* l# ~# \* H  I/ r% I
  19.     }     
    ; ?: p6 D  s+ u# \, x! K: B
  20. }
复制代码
& C; l& U0 ^; s  M$ i

1 T+ F4 g; K, j6 b/ C, f" o怎么去看检测结果呢?用调试的办法,打开调试界面后,将Time变量添加到Watch一栏中。然后全速运行程序,既可以看到Time中保存变量的变化情况,其中TimeWidthAvrage就是最终的结果。
& q4 n+ F' `5 c
' }1 t  _4 H! ^8 g# `+ l

# S5 [* p9 q9 T% g 微信图片_20240524181458.png * J$ w7 j( o# k2 E' W

" Y% K1 @5 W6 Q; q0 x7 j% h! b3 T, P
8 _" N& S. T. ~4 J! D' F0 ?8 o
    可以看到TimeWidthAvrage的值等于0x119B8,十进制数对应72120,滴答定时器的一个滴答为1/72M(s),所以Delay_us(1000)的执行时间就是72120*1/72M (s) = 0.001001s,也就是1ms。验证成功。    ' ]) x& w/ B& c9 ?1 k5 O1 b1 `
6 k1 k) H6 q; y" j. s/ y) j
; J2 E( c7 q# G& m" {7 W2 Q
备注:定时器方法输出检测结果有待改善,你可以把得到的TimeWidthAvrage转换成时间(以us、ms、s)为单位,然后通过串口打印出来,不过这部分工作对于经常使用调试的人员来说也可有可无。
. y9 I' e( Q( T/ |7 E# {3 V' ?: d2 b7 N, e6 Q& b5 r/ u; ?
& o1 d! C4 \) G  R8 ]9 |5 [
两种方法对比# R/ W- p3 ]  y/ M& i; G
软件测试方法   
/ k! e5 ^" e# z- p0 F操作起来复杂,由于在原代码基础上增加了测试代码,可能会影响到原代码的工作,测试可靠性相对较低。由于使用32位的变量保存systick的计数次数,计时的最大长度可以达到2^32/72M = 59.65 s。
: d+ n1 x. H4 r  d$ n1 b2 ^* Q
" G& J0 C* D$ ^
  m# G1 J$ j- b# s
示波器方法    + n# T- f+ T4 U" N% J) m
操作简单,在原代码基础上几乎没有增加代码,测试可靠性很高。由于示波器的显示能力有限,超过1s以上的程序段,计时效果不是很理想。但是,通常的单片机程序实时性要求很高,一般不会出现程序段时间超过秒级的情况。9 P( |- e9 d& J+ Y! W
) q( o& C* U& `
! C5 C( g4 A9 M& p& \" }  v+ k+ m$ W
  ]: ~0 p, M% `+ Q6 q$ [- U! ]3 w
转载自:单片机与嵌入式" M, j, l' E' ?" |; A6 b- \
如有侵权请联系删除
0 Z; z$ G9 z3 m! A& b6 j* @+ }# Y# _
$ v$ j7 ^4 R; A* q* I! _: R
赞 收藏 评论0 发布时间:2024-5-24 18:15

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版