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

获取STM32代码运行时间的技巧

[复制链接]
STMCU小助手 发布时间:2022-10-8 17:28
前言
, X/ S: `6 `% q& g: W    测试代码的运行时间的两种方法:
6 V$ z: w+ U# K, O0 [
2 q2 E9 I+ n0 I. k使用单片机内部定时器,在待测程序段的开始启动定时器,在待测程序段的结尾关闭定时器。为了测量的准确性,要进行多次测量,并进行平均取值。1 s% c% Q1 g4 y5 m8 X
" `* D) f8 i- i% d0 O. U5 N- L6 @
借助示波器的方法是:在待测程序段的开始阶段使单片机的一个GPIO输出高电平,在待测程序段的结尾阶段再令这个GPIO输出低电平。用示波器通过检查高电平的时间长度,就知道了这段代码的运行时间。显然,借助于示波器的方法更为简便。
3 O6 [" Y1 @" p" H" a4 X) o% k" w( A8 ~- i
借助示波器方法的实例
/ m* N$ S3 y2 W5 K7 I( j* n    Delay_us函数使用STM32系统滴答定时器实现:' F2 F- i# u  z5 w9 r

9 p% F! W. Z# E5 ?( K& X
  1. #include "systick.h"
    % A" c- `( P! Y6 l! K
  2. 0 L$ c1 L- \: \& C9 Z! z5 `
  3. /* SystemFrequency / 1000    1ms中断一次
    1 N9 P1 s. Q6 \' H
  4. * SystemFrequency / 100000     10us中断一次
    5 X4 r. c* _' u$ s
  5. * SystemFrequency / 1000000 1us中断一次
    0 P( O. r" j! Q4 Q; C  B
  6. */
      f! l0 O+ c( S# p( Y  F7 O: @3 K

  7. - `4 Q1 u8 N0 a
  8. #define SYSTICKPERIOD                    0.000001
    - h: R( t+ l3 x2 f4 n* n
  9. #define SYSTICKFREQUENCY            (1/SYSTICKPERIOD)
    ' K0 d. S8 d2 _" \5 `1 i( ?

  10. 5 |' q3 V# R2 R7 }: ]; C: _
  11. /**
    2 y- j" c5 M- K6 ~
  12.   * @brief  读取SysTick的状态位COUNTFLAG5 ~  z' M) m2 f5 X9 Y: Z
  13.   * @param  无
    ; G+ _, T: N& Q- m
  14.   * @retval The new state of USART_FLAG (SET or RESET).! `* [5 b' t2 U) ^8 j7 |# Y
  15.   */4 Z5 s2 o/ `2 F5 `, T: {
  16. static FlagStatus SysTick_GetFlagStatus(void) 2 F  w- r, \! u& ^, X+ y7 }
  17. {* A5 v& |# r8 Y, T* @5 f
  18. if(SysTick->CTRL&SysTick_CTRL_COUNTFLAG_Msk) 1 {4 N. b6 \/ h- }/ c1 K
  19.     {
    , G, r9 l! r7 i, v! P3 n
  20. return SET;. D' L1 J* L3 C
  21.     }
    ! z; T# h& _( ?# ~1 Z: E/ U
  22. else
    2 l2 M* X- ?5 z. b" @1 V; g
  23.     {
    1 B  W2 d- h' C1 r1 }# P. a
  24. return RESET;- g! j# r/ m5 g% [) ^" h. n; H( m" q
  25.     }
    / B! s2 G' P# T6 Z# t, q/ v
  26. }
    ) T  @  ~: r8 h3 A* w
  27. 5 F" z+ u! t0 E5 K! @
  28. /**
    2 J# ^2 J- v" A. K4 v4 x
  29.   * @brief  配置系统滴答定时器 SysTick
    : ^+ S3 m8 F- g8 D  M/ S2 ?
  30.   * @param  无
    ) W2 h# X  }! Q! P% v) ?' Y
  31.   * @retval 1 = failed, 0 = successful
    : M/ Q! K- Y  l' r' X2 J' a
  32.   */- a( m' p4 W2 m: I/ Q0 t. E3 ^' D9 o
  33. uint32_t SysTick_Init(void), f7 U  T% f* B3 ]8 |9 o
  34. {6 @7 U+ R9 a- H0 E5 X; z/ ~
  35. /* 设置定时周期为1us  */
    8 `: g4 {$ D# n; |/ i) ?
  36. if (SysTick_Config(SystemCoreClock / SYSTICKFREQUENCY)) 0 D/ k# O; r( C: x9 V9 G
  37.     { . U- [# _" P! U# l1 H$ e
  38. /* Capture error */
    + s/ }% l) L2 N. q0 V8 L
  39. return (1);. f/ O9 I  d- [
  40.     }$ s( E$ r! M. w( O2 d* x1 k) f( o; d
  41.   c+ r  @; Z  m8 d
  42. /* 关闭滴答定时器且禁止中断  */
    $ P) J; n- ?7 A7 m8 d3 `
  43.     SysTick->CTRL &= ~ (SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_TICKINT_Msk);                                                  
    , Y7 ~$ l. i  y9 F( }
  44. return (0);
    + t0 ]' ]! N! b. M, x
  45. }% V: Q7 c$ j+ D1 s8 ?

  46. 7 B/ c8 r' t: e+ C$ F
  47. /**
    * N/ c$ [3 Y3 ^9 [
  48.   * @brief   us延时程序,10us为一个单位5 k) [; K$ A, D& R
  49.   * @param! c0 Y/ j) t. G  ?
  50.   *        @arg nTime: Delay_us( 10 ) 则实现的延时为 10 * 1us = 10us
    + |; L. p, ~) s) V0 R- y
  51.   * @retval  无
    3 H* y  f& K# Y# P
  52.   */' {! E- m" c9 f1 H: d1 M
  53. void Delay_us(__IO uint32_t nTime)
    # I; l% O+ U: v: F0 G* m  |* |
  54. {     
    5 O( p( E% ]3 H2 x6 ^5 v
  55. /* 清零计数器并使能滴答定时器 */
    ' V2 [- ]* g+ N4 @( T& r; ~  ^
  56.     SysTick->VAL   = 0;  
    9 X4 l% g7 E! @1 _8 g
  57.     SysTick->CTRL |=  SysTick_CTRL_ENABLE_Msk;     
    * D" Z# r/ M# L' \) K

  58. 0 x, E$ o; X8 x% o2 Q
  59. for( ; nTime > 0 ; nTime--)' a( w; Y2 f( k& ?
  60.     {4 @/ B+ y* P4 j# ?( P: i
  61. /* 等待一个延时单位的结束 */
    9 v& i* F: i/ K2 e; l
  62. while(SysTick_GetFlagStatus() != SET);
    7 b( J4 z  |4 ~- e2 B
  63.     }
    8 \  a: J. ]$ S+ a: V3 t4 j" a' u
  64. ) ?! j3 N& z& s
  65. /* 关闭滴答定时器 */& H1 }. N7 y6 m3 n8 F
  66.     SysTick->CTRL &= ~ SysTick_CTRL_ENABLE_Msk;
    + _' F  i' T; o! t" ^
  67. }
复制代码

0 W' Z8 Z, G/ W5 K    检验Delay_us执行时间中用到的GPIO(gpio.h、gpio.c)的配置:
' T& b3 H2 H" u6 p2 |
! d, ~: J* M$ u2 E
  1. #ifndef __GPIO_H  s# c0 M0 G. _6 ~! `! x
  2. #define    __GPIO_H8 F7 \  G7 l3 E! r1 e6 d0 t) G

  3. 6 z; \9 J. L$ B6 i5 Z- W
  4. #include "stm32f10x.h") j: \0 A, m6 d, T" g2 E

  5. ! p  x' Y$ [! `3 p0 J
  6. #define     LOW          0
    2 i; W" e: G# y/ }1 v1 Z; `; r- F% s
  7. #define     HIGH         1
    4 h, o% U' z# O1 k) H9 W' @

  8. ; s' V' q/ P) R+ V
  9. /* 带参宏,可以像内联函数一样使用 */+ `9 ?1 y0 R1 Y: t: L7 t  _4 g1 C
  10. #define TX(a)                if (a)    \- b, u. m5 y/ G. F9 S/ Z6 X+ y
  11.                                             GPIO_SetBits(GPIOB,GPIO_Pin_0);\
    / G( t( }3 e7 L# J% B
  12. else        \
    / j/ a& Q7 J/ n, w) U
  13.                                             GPIO_ResetBits(GPIOB,GPIO_Pin_0)
    & ^  t& R5 U. R. d* O
  14. void GPIO_Config(void);& l( p9 i& W5 O4 p
  15. 3 w0 D. p% i8 O  ?( a
  16. #endif. T8 k, y& q& U8 B( p- y
  17. 9 p$ R2 g) u3 f
  18. #include "gpio.h"
    0 r$ x. m! n) \5 Y

  19. 3 G) E. Q3 _' T( N" |$ y/ H' m
  20. /**
    ) k4 x9 t1 x# z. d$ k- Z. W) f8 ?
  21.   * @brief  初始化GPIO0 I4 N/ \/ j3 S! u1 s' o
  22.   * @param  无
    & p4 Y/ b  X2 y9 `6 A  a4 d' a
  23.   * @retval 无
    3 M8 u. m6 ~* {% }/ y8 e3 {# g
  24.   */" f% e, g9 U& h" b" ~* g
  25. void GPIO_Config(void)' s( Y' D+ ]( T3 i) C& V! z1 v0 j# L
  26. {        7 J6 D0 B* Z1 T5 ^6 X* f6 m
  27. /*定义一个GPIO_InitTypeDef类型的结构体*/8 b( F! l4 i2 W; e0 m
  28.         GPIO_InitTypeDef GPIO_InitStructure;3 t" ^! `' x0 d0 ~- n  ]
  29. 5 ]( U- F- S; }
  30. /*开启LED的外设时钟*/
    ) M! Z8 T, {% B
  31.         RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE); " Z: }$ a( J. \4 r( I  T6 k
  32. ( D7 ?3 W9 @0 |$ j0 ^2 I
  33.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;   
    4 o, x0 R$ ?" i8 o) I5 G+ P
  34.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;     
    + t6 U8 v9 w, h4 J3 e4 q4 h
  35.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 0 i2 {) P, Y4 `1 V; g7 _
  36.         GPIO_Init(GPIOB, &GPIO_InitStructure);   
    8 n' v5 j* M& Z7 ]0 w8 F4 T3 v, Q
  37. }
复制代码

# ~* `7 v: ^0 O    在main函数中检验Delay_us的执行时间:5 ~) t7 b" A  [! ]$ p

. W( T* h7 [3 y) I- f
  1. #include "systick.h"
    & L/ @0 C- w! ]
  2. #include "gpio.h"
    5 D; t3 ^. ]6 O* C8 P) c9 z
  3. 4 l( t0 ]' a+ k+ o
  4. /**( ~. k" s) r% S% P+ C
  5.   * @brief  主函数- L# M4 H" Z2 Y6 g1 O' _9 L
  6.   * @param  无  
    ( Q, R! t0 d/ g5 d
  7.   * @retval 无
    % u3 }3 @' a) [  @/ x1 H! A" C
  8.   */
    + V- B' I% P. e$ Z+ i
  9. int main(void)3 V  y. P- n% [
  10. {   
    + P) {1 r. I+ G/ r9 h) c
  11.     GPIO_Config();6 s" c+ [9 j5 q+ H. G' b4 t

  12. : A4 J6 H! |) G
  13. /* 配置SysTick定时周期为1us */
    " Z; [9 _5 f* V
  14.     SysTick_Init();; o2 P  z) N) x0 D  d+ O+ s

  15. 8 Y5 Y  T. B. m) Y
  16. for(;;)" v8 S" _6 l4 |
  17.     {
    7 C1 j% E2 J  L& c! F
  18.         TX(HIGH);
    # D9 y! b& y$ P  K+ C
  19.         Delay_us(1);
    , G7 d( x& s7 O; U; L
  20.         TX(LOW);
    ( v' }6 x% ?8 ]& Y* T6 z/ t* {
  21.         Delay_us(100);
    % E  I% L- U3 }6 x! }
  22.     }     % \" i2 }; a+ G
  23. }
复制代码

6 n3 y; l( n  a4 r& g% N    示波器的观察结果: 微信图片_20221008173928.png 3 [  M) c, [8 ?0 h+ p+ b5 F+ [
微信图片_20221008172714.png 3 T- U3 Q$ `" |( z& H

4 _- z  y2 [! U7 G4 A9 L: t* S) q( P; P) d9 X9 g
    可见Delay_us(100),执行了大概102us,而Delay_us(1)执行了2.2us。
7 I, f5 }: a, A/ Y. E; M  }$ k, }2 E" F3 S+ Q) S
    更改一下main函数的延时参数:
9 J5 t+ q; _* A; D- d  a/ ~$ I9 p7 e* b5 o# i) S$ @
  1. int main(void)
    1 m( C" M' L8 ]/ V; f
  2. {      P) w0 l3 e+ P' B( c: F
  3. /* LED 端口初始化 */
    # k0 S: H( k# d9 p* g
  4.     GPIO_Config();( B  F  z2 Q8 T: i
  5.   m1 f( J1 }. k1 i# G  x
  6. /* 配置SysTick定时周期为1us */
    & o% d8 _; W5 [; {8 a
  7.     SysTick_Init();* S( A3 F/ @8 J1 Q
  8. 6 r- m# T9 N7 x' D2 O( n
  9. for(;;)
    ; i" V0 m0 ^+ B
  10.     {* @% r* g- n0 n% a9 f1 V9 m  k
  11.         TX(HIGH);
    : }9 H! N5 t7 @8 C. e+ P6 Y
  12.         Delay_us(10);  P) @* l, o7 @* }
  13.         TX(LOW);8 j5 v; }* U4 K( P* q* |9 n
  14.         Delay_us(100);
    ! b, D( B% [* S) _3 H- S1 E" I
  15.     }     1 p$ P4 i* M8 ~/ c/ I0 b% e
  16. }
    , E- U+ }  l  x! t) Q1 `( q
复制代码

$ F3 C  a9 Q- T5 L& P" U1 ^% P9 ~    示波器的观察结果:
9 e& K1 H  P1 [- y/ ^3 O6 U8 ?* y2 v# I
微信图片_20221008174025.png * J& f1 v" S0 a) \; B# h5 j8 A
微信图片_20221008172709.png
7 |0 G8 X" x$ X
! t: d: g  q/ A7 P% H' x- g: ]    可见Delay_us(100),执行了大概101us,而Delay_us(10)执行了11.4us。9 Q5 y* j4 n4 `+ ^! z
; q, i! ?2 l9 P$ s
    结论:此延时函数基本上还是可靠的。
# q7 o# E8 C9 c* T6 k2 J* H9 ~) G; U* c. e2 E
使用定时器方法的实例" N0 t" g) Y) |
    Delay_us函数使用STM32定时器2实现:
7 w; c) Y; I  [- e2 X5 [8 c
! j5 K5 `0 B' B
  1. #include "timer.h": {9 ~' Z( p9 a

  2. 7 G# H0 w5 q: \1 C/ D" p0 p
  3. /* SystemFrequency / 1000            1ms中断一次( H# Y& y" W5 t
  4. * SystemFrequency / 100000          10us中断一次
    ( U; E9 x0 u7 F" f% T1 s
  5. * SystemFrequency / 1000000         1us中断一次( V* O. L4 V& y) I
  6. */' B/ ?7 F7 I1 q' Z* y: I$ d

  7. $ U( [: ^* u2 Q7 C) x  w
  8. #define SYSTICKPERIOD                    0.0000017 e0 E& k8 H- p) X/ L
  9. #define SYSTICKFREQUENCY            (1/SYSTICKPERIOD)
    * c" G: w  A) _! a% o$ d. h/ X

  10. ! }# n/ Z4 q0 X% P3 d" H. X
  11. /**' S* t. s7 ]/ S/ ]7 [
  12.   * @brief  定时器2的初始化,,定时周期1uS
    3 `& N9 ~3 @0 `& ?, R. I
  13.   * @param  无
    7 \4 L/ L: I# D$ h
  14.   * @retval 无  N' I+ R* \4 w
  15.   */
    - J, q1 o2 E4 U& Q+ w: t) e
  16. void TIM2_Init(void)
    ' E5 [0 |: d/ V7 O
  17. {
    % g7 O% q; z- y
  18.     TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;% _( U9 D9 K* O0 M7 ]2 W
  19. $ T8 [5 A. K( @0 n! h1 p" n
  20. /*AHB = 72MHz,RCC_CFGR的PPRE1 = 2,所以APB1 = 36MHz,TIM2CLK = APB1*2 = 72MHz */
    # P/ x2 v5 g3 p0 ~+ K& x" h! f
  21.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    0 Z1 D' q( V1 Z7 I
  22. ) d) F3 p* J" R6 {! ]5 F( V
  23. /* Time base configuration */+ v; w9 M+ ~  n$ a) M
  24.     TIM_TimeBaseStructure.TIM_Period = SystemCoreClock/SYSTICKFREQUENCY -1;
    4 u% M8 ^" r# h9 \4 x. w6 o0 E' F
  25.     TIM_TimeBaseStructure.TIM_Prescaler = 0;
    ! K' f, C' E+ C9 _8 Y1 V/ k
  26.     TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    . i% I& Z1 u; D1 \& B
  27.     TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
    " V0 {" A: T2 G
  28. $ t3 N1 r! j; }- }7 B7 d
  29.     TIM_ARRPreloadConfig(TIM2, ENABLE);
    , i2 J+ f* F+ w  Q9 d. H
  30. ) X6 F6 L) M7 z1 t
  31. /* 设置更新请求源只在计数器上溢或下溢时产生中断 */1 d  P  c  l& w3 g- C1 \
  32.     TIM_UpdateRequestConfig(TIM2,TIM_UpdateSource_Global);
    - V  G8 e& t( Z7 L+ H
  33.     TIM_ClearFlag(TIM2, TIM_FLAG_Update);
    # _( Q! |1 S. `
  34. }: e+ d( q0 B: a# ?! {/ [

  35. # f7 Y9 g. I! S& `  ^# a
  36. /**
    + z# d2 v( c" I/ k% u8 F3 f
  37.   * @brief   us延时程序,10us为一个单位4 |: \) f- T$ F- K  J" \' S% z
  38.   * @param  
    5 e' Q% Y3 W9 c" m
  39.   *        @arg nTime: Delay_us( 10 ) 则实现的延时为 10 * 1us = 10us" ~6 x; J$ R1 x% D+ P+ F
  40.   * @retval  无# j( g4 O+ i- n
  41.   */5 f) ^5 c9 G, L2 ^
  42. void Delay_us(__IO uint32_t nTime)
    7 Y9 B7 ]$ _. a7 r7 v- R; u
  43. {     % W6 v+ z0 `( r( B3 f- i, \
  44. /* 清零计数器并使能滴答定时器 */
    + [) s4 a- v8 `
  45.     TIM2->CNT   = 0;  * ^( v2 h6 ?4 s7 M  X3 O
  46.     TIM_Cmd(TIM2, ENABLE);     
    8 }2 t7 C+ W* W* [; @
  47. , b- R0 n# S# j: l  a, }
  48. for( ; nTime > 0 ; nTime--)1 a# t2 M( t# F
  49.     {
    9 z+ J$ i3 J; |& @) |* w
  50. /* 等待一个延时单位的结束 */
      w( y% u9 z/ t0 k) \0 k1 c
  51. while(TIM_GetFlagStatus(TIM2, TIM_FLAG_Update) != SET);
    7 N- ~1 t. M9 i: b
  52.      TIM_ClearFlag(TIM2, TIM_FLAG_Update);% D2 f. E4 n8 m2 a0 M
  53.     }
    4 @+ X# |& K" M# j5 b( \* C. _: x

  54. $ b" P2 G/ z; ?, g. T4 B' u
  55.     TIM_Cmd(TIM2, DISABLE);
    4 `5 c6 ~8 q3 R0 N3 |) w
  56. }
复制代码
/ h0 `! ^+ n$ \. w( o
    在main函数中检验Delay_us的执行时间:! f" L1 j' N# R. v
2 t$ z& ]" P) `& n% B3 D
微信图片_20221008172702.png ' z$ a5 h5 N1 b9 a" `! Y
    怎么去看检测结果呢?用调试的办法,打开调试界面后,将Time变量添加到Watch一栏中。然后全速运行程序,既可以看到Time中保存变量的变化情况,其中TimeWidthAvrage就是最终的结果。& u$ |( a0 E0 V! v3 l

! {, }! C: m3 v 微信图片_20221008172650.png 3 i( v( h# `' J. N8 }4 s

7 I. l0 G; [9 `4 x! f7 J    可以看到TimeWidthAvrage的值等于0x119B8,十进制数对应72120,滴答定时器的一个滴答为1/72M(s),所以Delay_us(1000)的执行时间就是72120*1/72M (s) = 0.001001s,也就是1ms。验证成功。6 E) `. m  S9 D4 p% i0 ^

  R# V( x$ T$ e: }  x: d1 k( \7 ]    备注:定时器方法输出检测结果有待改善,你可以把得到的TimeWidthAvrage转换成时间(以us、ms、s)为单位,然后通过串口打印出来,不过这部分工作对于经常使用调试的人员来说也可有可无。
# G. X6 U  ?2 r5 _/ {- Q# ^4 U" C- s9 X. ~
两种方法对比
) V1 L  S' B. K1 A软件测试方法
5 d; ~1 y: B$ ?- [9 u0 h9 ?5 b
; ^' u; ?% y, ?# h8 n) j, t# N
    操作起来复杂,由于在原代码基础上增加了测试代码,可能会影响到原代码的工作,测试可靠性相对较低。由于使用32位的变量保存systick的计数次数,计时的最大长度可以达到2^32/72M = 59.65 s。
: X8 w. ~' c. |. N8 }2 I* F2 M. [' @! S& J- g& O- `$ j/ a$ j
示波器方法
- j$ u1 k! D0 K; m  d" n2 m
3 y% }! j$ @# z2 f* Z# T% d. h3 ^    操作简单,在原代码基础上几乎没有增加代码,测试可靠性很高。由于示波器的显示能力有限,超过1s以上的程序段,计时效果不是很理想。但是,通常的单片机程序实时性要求很高,一般不会出现程序段时间超过秒级的情况。
# m& y! i3 p5 O% i5 x$ ~3 l3 @6 U% A! G+ e# m" ~
! k1 Q  R! l" {  p
转载自:EE时间
2 |/ l3 f1 ], o; w' s
赞 收藏 评论0 发布时间:2022-10-8 17:28

举报

0个回答

所属标签

相似技术帖

官网相关资源

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