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

STM32经验分享:如何测量代码运行时间

[复制链接]
STMCU小助手 发布时间:2021-9-6 16:03
01示波器
, b9 |0 S" `; f& X
" V7 n% j' W0 E. h测量一段代码运行时间第一时间想到的当然是示波器了,在测量开始的代码前面拉高某个GPIO,在结束测量的位置拉低这个GPIO,直接使用示波器查看这个GPIO的高电平时间长度即可,就是我们要测量的这段代码的运行时间。
- O6 f" m* T) f+ g3 I) N
0 |8 ]! a5 A. X# f% ^1 J那么直接上示例,为了模拟代码运行一段时间,这里我直接采用之前文章《STM32的四种延时方法》直接延时。7 x3 y- L- T4 F. V% W
  1. while (1)% j" L4 H% c/ }+ \
  2.   {
    * X9 E, p$ M7 f" E! e2 O
  3.     GPIO_SetBits(GPIOE,GPIO_Pin_4);  //熄灭LED灯                     
    ' m9 X  f5 Y' D: v* c
  4.     delay_ms(500);//延时500ms
    ) \- N' Z: a- G
  5.     GPIO_ResetBits(GPIOE,GPIO_Pin_4);//点亮LED灯                     
    ! v8 i- o' o7 |- u( p+ {% ]
  6.     delay_ms(500);//延时500ms& T3 k& u% R! x5 [
  7.   }
复制代码
延时500ms时波形如下
8 b# Q6 a# l0 g" g$ c
12.png
当修改代码,延时100ms时& N* H' v2 c8 _( y5 {
  1.   while (1)
    : b+ H5 Q: E/ s: T1 I; n# h
  2.   {4 e$ [5 U# U2 `) J/ ~9 q, l% s& m
  3.     GPIO_SetBits(GPIOE,GPIO_Pin_4);  //熄灭LED灯                     . B) a* w* J0 M  ^4 T
  4.     delay_ms(100);//延时100ms9 X  K* [( b/ a0 `1 O5 ]
  5.     GPIO_ResetBits(GPIOE,GPIO_Pin_4);//点亮LED灯                     
    * [; J& d' T/ P! o6 t' |
  6.     delay_ms(100);//延时100ms
    3 U0 g- g2 [. O  M6 J, F" l" I
  7.   }
复制代码
波形如下
) S$ Z$ K' E6 \) a
13.png
测量准确无误,但是他的缺点也很明显啊,需要示波器,示波器一般很笨重的,即使是轻便的示波器,也需要接硬件,还是很麻烦的,而且需要一个空闲的GPIO,测量的这段代码中,不能使用到这个GPIO。
+ B. m; f7 R$ ~. c* H1 @
+ _* `  e  Y% z& h/ F8 F# s/ M02定时器测量2 i  A. b; p% F+ R, y9 Q/ D( n

8 o4 x# K$ u% v定时器不仅仅我们可以实现我们之前讲解的《基础定时功能》《PWM输出功能》《输入捕获功能》《触摸按键功能》,还可以用于测量一段代码的运行时间。在学习使用定时器测量代码运行时间之前,如果对定时器不了解的同学先看刚刚提到的定时器的文中,重点文章《STM32基础定时器简介》。本篇文章不再讲解定时器的基础功能。
2 M: l8 I$ f; L$ w4 [定时器本质上就是向上累加的计数器(如果配置成向上计数时),所以我们在测量开始的代码前面读取定时器的计数器,在结束测量的位置再读取定时器的计数器,获得两次的差值,这样就可以计算出这段代码的运行的时间。这就是简单的原理,下面直接撸代码。
# `. ~" B: n6 G1 a0 B
! o/ m0 O3 ~8 \  E0 F; @( n* u首先配置定时器,这里我使用定时器3,配置定时器的计数器每增加1,表示100us。并且将溢出值设置为最大。
- a+ J3 T! I, s8 _

  1. # Y5 m& W1 ]; D) T2 q/ O
  2. void TIM_Config(void)( S; Q; J: X" g/ G  J; }8 |
  3. {
    7 S  c  o( y1 s. {
  4.   TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    ' a% i/ T5 Z/ ?( I
  5.   /* TIM3 clock enable */* }% }3 e/ n3 a6 _5 O4 e
  6.   RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    4 e$ c$ x+ W5 l+ p4 K
  7.   
    7 d  a# o3 A* i2 {0 K: ?' p
  8.   TIM_TimeBaseStructure.TIM_Period = 0xFFFF-1;
    / b; K" `- T+ U. I5 c
  9.   TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t) ((SystemCoreClock / 2) / 10000) - 1;, }3 F; t& w- @. |7 P/ S9 K) a
  10.   TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV2;) |/ W8 Y9 g' \4 T; T9 I# q" p
  11.   TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    6 X. h- l' H9 R2 S
  12.   TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
    ( S8 ?/ v( o1 m8 @1 Z0 N: O
  13.   TIM_Cmd(TIM3, ENABLE);
    8 Y# f! g. _) j) [. ?7 c! \+ w
  14. }
复制代码
测量代码运行时间的代码如下,这里进行了防溢出的处理
5 c3 G4 U% o7 w, C
  1. while (1)# t4 t7 s) R! s6 m$ h
  2.   {
    $ [% v. G  U, R. K. P7 u
  3.     GPIO_SetBits(GPIOE,GPIO_Pin_4);  //熄灭LED灯                     
    6 Y  }/ y9 R, b1 I! B; a
  4.     delay_ms(100);//延时100ms
    7 C4 a  k! j  `) N0 u5 R
  5.     GPIO_ResetBits(GPIOE,GPIO_Pin_4);//点亮LED灯4 `; j7 _% [' y  q
  6.     old_counter = TIM_GetCounter(TIM3);
    : Y4 [! Y/ {& S( E# C3 O! J
  7.     delay_ms(100);//延时100ms! g$ M9 N; G* v
  8.     couter_current = TIM_GetCounter(TIM3);
    ) T, C( [- P7 o& s+ |
  9.     if(couter_current > old_counter)& K% C+ O+ a: Q" e: |/ F' }3 y0 m, \
  10.       counter = couter_current - old_counter;
    ; W3 G9 T) e3 D2 I) ^0 h  i
  11.     else
    , w2 J6 B4 G% f: B& Z7 g! d
  12.       counter = couter_current + 0XFFFF - old_counter;
    3 [' O7 A  x% k9 h: b4 A
  13.     time_ms = counter / 10;  j4 S% H$ m& r
  14.   }
复制代码
上述代码延时100ms,通过定时器测量结果同样为100ms,准确无误。如下所示:
$ |* C1 Y" e9 r
14.png
这样有的同学可能已经联想到了,上述代码完全可以封装成一个函数如下
6 a: }0 r9 y7 k& n- {
  1. ; b" k; J+ E& V
  2. float Time_Difference_ms(void)
    " }3 q1 w5 X4 f, H8 V- J
  3. {1 @$ d9 G+ q! i0 s
  4.   static uint32_t old_counter;
    7 h6 R7 h! X. y$ ?! u; w
  5.   uint32_t counter,couter_current;1 D; o) x- S1 g' e6 G* y7 K8 w
  6.   couter_current = TIM_GetCounter(TIM3);
    $ C) j/ P# H& r* `$ I6 f5 m, T
  7.   if(couter_current > old_counter)7 ]4 ^3 W  @. T" {/ h0 J
  8.     counter = couter_current - old_counter;: m' I9 x* ?$ E0 x) A0 l) e
  9.   else
    + }, G$ b% x$ y) i; K
  10.     counter = couter_current + 0XFFFF - old_counter;
    4 \9 F2 g3 e7 i
  11.   old_counter = couter_current;
    8 R) f  \; }0 u
  12.   return (counter / 10);
    8 H; o+ f7 \7 L6 U
  13. }
复制代码
这样就可以实现,测量两次调用这个接口的是时间差,如下,可以准确测得两次调用Time_Difference_ms这个函数的时间差是100ms。; H! ?/ Z' y% e" @* F" U' U" p) B
15.png
上述代码经过封装,可以测量代码两次运行到相同位置的时间差。将程序再进化一下
3 n7 t" Q8 k$ v* P2 v
  1. & O- o6 Q- p  X4 _0 f2 T
  2. float Time_Difference_ms(uint8_t flg)0 X3 v7 G% K5 l0 n( t  L; V
  3. {9 x, k% P, `) k+ l: ?  p
  4.   static uint32_t old_counter[5];
    8 [' K3 s' u& S( E' w
  5.   uint32_t counter,couter_current;
    7 D5 b' |6 x0 |! D4 e
  6.   couter_current = TIM_GetCounter(TIM3);/ z7 O: |; V" P2 k
  7.   if(couter_current > old_counter[flg])
    4 ?* c( v0 W6 v8 E6 K  u. }
  8.     counter = couter_current - old_counter[flg];8 t  {2 c2 n) \/ z! {
  9.   else
    1 t8 l- F. ]: a' ]8 e6 @% u
  10.     counter = couter_current + 0XFFFF - old_counter[flg];; C2 |6 }8 }& w1 ?% Y: X# y
  11.   old_counter[flg] = couter_current;
    7 k. h7 Y1 a* a. W) `5 P% d
  12.   return (counter / 10);' [& L8 ~) a) X0 g+ a7 n4 i) Y
  13. }
复制代码
这样就可以得到多个位置两次运行到相同位置的时间差。
; I4 ?% v9 @3 h) _- L  O% H
& a  v9 i% i! T3 ?7 j当然,这样也存在缺点:. x6 m$ O0 Y$ C4 m1 q0 k
5 h: l% U/ y. Y" W$ y
1、需要占用一个定时器
  E8 M9 g' r# L2、按上述配置,最长测量时间为0XFFFF*0.1=6553.5ms=6.553.5s。
4 t( D6 _/ F; h' B7 m. V2 }$ p$ \* L& I1 e
Keil和IAR的工程文件下载地址:8 p$ L3 ]7 Y5 A( z/ Q' p
PCB和工程代码开源地址:  j# }" h  z5 ^& _# s
https://github.com/strongercjd/STM32F207VCT6
# \( e& R( A- G$ @: |6 D" ^2 ?2 Q0 C0 f" \) d

! M: w4 C# Y7 q! D
赞 收藏 评论0 发布时间:2021-9-6 16:03

举报

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