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

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

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

. k" f- g& G* f5 _
4 l) h' [  `5 _4 u

* f' g+ ~" \$ {8 Q8 J5 B( }! w借助示波器方法的实例   
9 y# W! C2 c) _. z2 m( D4 r& u1 P) T: P' |% O% R+ w* f

* N) S/ \$ y$ ]/ I' |, d% tDelay_us函数使用STM32系统滴答定时器实现:% j) _8 C9 C* m
  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;}
复制代码
( l. H( P$ @/ X9 r- e5 d
* z& F% r6 o- J, Y7 I
& t" d+ E( ^# i4 D. t1 Z6 V
检验Delay_us执行时间中用到的GPIO(gpio.h、gpio.c)的配置:, S; D' I6 j8 m# I: x
  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);    }
复制代码
% p7 e- ?( T+ m. t' ?

, q- K. ~( P3 a: I$ r) _+ E$ s在main函数中检验Delay_us的执行时间:. q+ A! o6 Q, J/ u( L  t3 u
) U5 [) Z% ]8 m' ]8 F

: {  Y3 a5 b1 l 微信图片_20240524181424.png
; }6 a8 K# Q1 t) b  j# p5 m9 H4 V

9 h1 h) [7 {7 M8 r9 W: Y, C: u3 t" v3 {) H5 H. o, `% Q4 V6 M

! s- Z, C' V5 U8 d9 p    示波器的观察结果:
9 u; c6 \$ {( o- }
微信图片_20240524181439.png
( p& q" _9 c; K! w3 d; A

+ w3 J0 j" m1 }8 E& {; e/ {; V
微信图片_20240524181443.png ' ]/ Z0 a5 [! a0 }
2 i8 B* ~! @# N" A0 @
    可见Delay_us(100),执行了大概102us,而Delay_us(1)执行了2.2us。   
9 A. R0 Q# \1 S/ }% U! s4 v" A& C* x+ H# q3 x: I! B
9 J4 U; l* Q; M( G* U! r
更改一下main函数的延时参数:5 \0 f* \9 u+ S) u' C  D3 E+ Y

: x$ ^/ ?" ], x1 g+ M

* J" S' A8 T7 l/ ? 微信图片_20240524181448.png / i. @- E; F- p3 K7 h

& J) d3 B: I5 _0 }  |& A6 P0 U' v" [% m6 s- @
( L7 Q) A. ~: d4 E
    示波器的观察结果:
5 Q$ a+ n4 b' ~5 d& k5 b
微信图片_20240524181451.png
- d6 a) s% o/ O$ T$ J1 f
微信图片_20240524181454.png : l/ f! k9 |" d. B9 H& D

+ f, {; }* h6 c# N  X2 f. \! k    可见Delay_us(100),执行了大概101us,而Delay_us(10)执行了11.4us。   
' S  ^8 Y9 S% V7 U# A- L+ O
! q$ ?* v' w2 B  J

7 Y: d7 ~7 R1 {, D  B结论:此延时函数基本上还是可靠的。
  \7 x2 h* `. v+ f- D* K
% z2 l, X6 a6 I* L

( M/ s  b& N# v  e使用定时器方法的实例    4 o% F2 q* Q* q$ t1 W

+ O! g; ^: j. \; r1 w; M  s  h

+ G1 o# j& I+ o1 }* [* {Delay_us函数使用STM32定时器2实现:
8 j  {  A" D. I8 ^6 ^4 p/ U$ @' i( C; A
  1. #include "timer.h"2 d' m* |- b% U

  2. + z* }8 N9 U/ ]4 G' L1 u- Y
  3. /* SystemFrequency / 1000            1ms中断一次
    4 J2 g* @4 r2 i$ n! i. \
  4. * SystemFrequency / 100000     10us中断一次
    ! N! D7 C' q0 @% w. r* W" h
  5. * SystemFrequency / 1000000         1us中断一次& c5 K9 _  d, X4 t: V
  6. */' l- n9 P2 l' J1 `/ {: e

  7. 7 c9 j% Z, j3 ?# B) z4 C* X* l5 @
  8. #define SYSTICKPERIOD                    0.000001' D- v- B4 x" B0 Q# D
  9. #define SYSTICKFREQUENCY            (1/SYSTICKPERIOD)
    * _/ _# e% T; b
  10. ! ^% E/ Q. k: x( k: X! @
  11. /**
      X; H" H, \" g1 b  L6 ^+ B2 N1 F
  12.   * @brief  定时器2的初始化,,定时周期1uS5 O9 H4 c( N$ ?
  13.   * @param  无2 f' c) S, i) J4 \
  14.   * @retval 无4 @8 }4 {" p  o  {
  15.   */: F; R. f0 R  _+ U) Q/ v; S
  16. void TIM2_Init(void)3 Y* w" e7 s) X# Y+ K2 |3 K
  17. {
    0 [. {. p4 Z  Z0 I$ |
  18.     TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    1 n3 T% z- W; D2 [  I# w( x
  19. 0 J3 C+ `4 j- ~+ ]1 B
  20. /*AHB = 72MHz,RCC_CFGR的PPRE1 = 2,所以APB1 = 36MHz,TIM2CLK = APB1*2 = 72MHz */7 h( z9 G) \4 b* |
  21.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    . w2 w% z' x5 j

  22. 4 G# d$ F5 y: Q$ r
  23. /* Time base configuration */( r, [" ?& T9 Y3 ?9 l3 _
  24.     TIM_TimeBaseStructure.TIM_Period = SystemCoreClock/SYSTICKFREQUENCY -1;
    : f3 l% P) y, {! Y8 d
  25.     TIM_TimeBaseStructure.TIM_Prescaler = 0;
    ; H5 v( u6 ?* w8 |3 x
  26.     TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  a9 K: _' S5 J2 a6 _/ }
  27.     TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);( w. Q2 m/ ?5 j
  28.   g* l: g" t! B) p3 U# F2 r0 M' @1 \
  29.     TIM_ARRPreloadConfig(TIM2, ENABLE);
    , ?( ~: V+ w+ _+ K6 m5 Y

  30. 2 u( }) V4 N8 O& k
  31. /* 设置更新请求源只在计数器上溢或下溢时产生中断 */! `% P: e- {5 i8 `/ o
  32.     TIM_UpdateRequestConfig(TIM2,TIM_UpdateSource_Global); : p7 m: `) c+ t8 x1 t# j" J
  33.     TIM_ClearFlag(TIM2, TIM_FLAG_Update);
    + ~1 D, P% t2 m* P0 o
  34. }
    0 s3 j; K' i' K9 j6 D
  35. : O  P: G  w1 U4 n$ v8 H" g
  36. /**
    ! M% W9 k7 E9 A( A1 I% ~$ b
  37.   * @brief   us延时程序,10us为一个单位
    : b$ t; F# q2 w2 B. L
  38.   * @param  
    5 b# F! P  O4 ~$ u
  39.   *        @arg nTime: Delay_us( 10 ) 则实现的延时为 10 * 1us = 10us- H* r. D4 a9 p+ M' e$ t) Y
  40.   * @retval  无7 @& Z7 V7 m  B- m  `; K
  41.   */
    8 z3 B# p4 {2 `, o- R. }
  42. void Delay_us(__IO uint32_t nTime)
    & G# A. U* o) w* P* M
  43. {     ' ~3 `! z  H: M+ ^0 L/ X% o6 ]
  44. /* 清零计数器并使能滴答定时器 */: u  z, Q, Z. S1 J
  45.     TIM2->CNT   = 0;  
    % S( c! y3 C% z- x9 k% R$ d$ Q" K
  46.     TIM_Cmd(TIM2, ENABLE);     , d0 Q" O+ R3 Q4 p% `( F' G! v
  47. 9 z1 q, s% K1 f% r
  48. for( ; nTime > 0 ; nTime--)9 l+ ?+ V+ i  l: J6 {! Q
  49.     {
    / \* T- A" ~# m8 c& T
  50. /* 等待一个延时单位的结束 */
    & }( Y5 w* Q( f4 D9 s# L% d, [6 ^  t9 B
  51. while(TIM_GetFlagStatus(TIM2, TIM_FLAG_Update) != SET);7 j$ m  p: B( N) m" y
  52.      TIM_ClearFlag(TIM2, TIM_FLAG_Update);
    2 G* G9 M+ _% H3 c$ f. @
  53.     }
    + i. v7 E5 Z# b! w0 a
  54. ) W! z. Y& [2 X1 g9 v' a" d1 o
  55.     TIM_Cmd(TIM2, DISABLE);% Y, C& }( q( x5 b
  56. }
复制代码
, s0 t( T0 ^2 b8 j( w; F+ y
' l7 z, C$ |, Y
3 [* x9 X( v7 I* m1 I2 Z" h/ u
在main函数中检验Delay_us的执行时间:& s& O# H5 T8 }. |& p7 y5 P
  1. #include "stm32f10x.h"
    ( ~. {( Z2 J# M) K) g7 i+ k
  2. #include "Timer_Drive.h"% o- O4 N5 ]+ `- l9 x
  3. #include "gpio.h"
    4 m  o' {- b$ U2 T: o% G
  4. #include "systick.h"
    ; r! |: @  b& S  X/ w. b$ D. W. }
  5. 5 j. T/ W( y0 J8 x- j6 @
  6. TimingVarTypeDef Time;
    . _/ i' p9 f' @& r+ b
  7. 3 c% \+ _/ L, B3 _' v7 r- s6 L" G
  8. int main(void)
    2 x: ^7 C, c# q. b  ~
  9. {   
    * l, ^2 o- V: @8 h) ~' Y+ E! N' P( O
  10.     TIM2_Init();   
    ; P/ H5 C* }% `  `# S8 l
  11.     SysTick_Init();
    ' Q+ y5 c# n+ J
  12.     SysTick_Time_Init(&Time);( I2 r3 I- T( l$ r4 e' a
  13. 2 n; `7 b4 l* u3 y
  14. for(;;)
    ( q8 C# H5 X- d$ O& V; D" }/ t
  15.     {1 I- w$ P' E0 p& U: C* H
  16.         SysTick_Time_Start();
    ! p- G5 k% R1 w! N$ p6 E4 w
  17.         Delay_us(1000);. T$ F# x1 Z2 |9 m+ t/ K9 N
  18.         SysTick_Time_Stop();) @6 N5 o( T1 A( t5 f6 P3 [' j' Z
  19.     }     0 e4 F) c8 x' g8 g1 h
  20. }
复制代码
8 R' R( K: r4 b0 H+ l0 k
. y( j# |+ q) w* k+ l+ `
怎么去看检测结果呢?用调试的办法,打开调试界面后,将Time变量添加到Watch一栏中。然后全速运行程序,既可以看到Time中保存变量的变化情况,其中TimeWidthAvrage就是最终的结果。8 M" j2 }! d& ]9 R
  x- E. X( ]0 `

) z! y, b2 M1 X 微信图片_20240524181458.png
0 q, ?( J8 m& L

, K# g6 X& D# j' _# M, y% O' R( v: A

2 v' Q( N3 W9 Q9 p; @* A3 s( d    可以看到TimeWidthAvrage的值等于0x119B8,十进制数对应72120,滴答定时器的一个滴答为1/72M(s),所以Delay_us(1000)的执行时间就是72120*1/72M (s) = 0.001001s,也就是1ms。验证成功。    5 c0 E; r  v. f& x1 Y
8 m# u! N2 F$ J

7 J! M! i7 }3 e, e( F% Y备注:定时器方法输出检测结果有待改善,你可以把得到的TimeWidthAvrage转换成时间(以us、ms、s)为单位,然后通过串口打印出来,不过这部分工作对于经常使用调试的人员来说也可有可无。
) {: [% k8 e. T9 p# x/ g8 T. R1 s$ D5 c
' A$ b: n" C% F- `
两种方法对比
3 S0 ~$ C/ G" a: z. @软件测试方法    % P3 _& {" t$ I+ u. \% V" w
操作起来复杂,由于在原代码基础上增加了测试代码,可能会影响到原代码的工作,测试可靠性相对较低。由于使用32位的变量保存systick的计数次数,计时的最大长度可以达到2^32/72M = 59.65 s。3 A6 B. _) v% Z5 x# E3 v9 w
- g! ^" N5 v) k# b# x: n5 F2 v. t5 H

. D. S- `% L! s% p8 F) s( N示波器方法   
9 i" Q* p( z) ?7 r1 c操作简单,在原代码基础上几乎没有增加代码,测试可靠性很高。由于示波器的显示能力有限,超过1s以上的程序段,计时效果不是很理想。但是,通常的单片机程序实时性要求很高,一般不会出现程序段时间超过秒级的情况。" X1 A6 h4 h' q9 a4 e, D
- x6 A9 n3 Z  Y9 l
( k. V3 V! q& r

4 M/ s/ C6 N3 p! o" R转载自:单片机与嵌入式
: j& M, U  `* Q% f( ^: @: T如有侵权请联系删除7 M2 b* n7 v6 J0 e. }& I' U
6 @# K0 |, I" x4 r; a/ f% r$ G1 I2 m+ o
赞 收藏 评论0 发布时间:2024-5-24 18:15

举报

0个回答

所属标签

相似技术帖

官网相关资源

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