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

基于STM32F103C8T6工控板利用定时器计算某段代码的运行时间

[复制链接]
STMCU小助手 发布时间:2022-11-20 15:24
思路:
) B: f/ X0 z, Y1)利用通用定时器(选择定时器2)计算某段代码的运行时间;& G6 ^5 I  ]9 y' `' p, i
2)顾名思义,会基于定时器2创建两个函数(TIM2_Clock_Start和TIM2_Clock_End)分别控制定时器2开始计时和结束计时,被测代码放在这两个代码的中间;
5 _5 _; D5 p* q+ h! d3)考虑计时的精度和最大计时长度,创建变量 u8 OverflowNum_cnt用来计算定时器2溢出中断的次数,创建变量u16 cnt_value用来计算最后一次定时器2的cnt值;
9 `; v1 T0 a, W' z4 q* S  o) @  x4)利用USART1实时读取某段代码的运行时间,并上传至电脑,便于查看。% i) B' k+ q% o" `
+ g4 u- E( ]# J, Z& @& \
这个工程较为简单,主要代码如下:
( Q  R* n6 M5 U0 \( d. o1 w9 l7 T% ~  Q! ~- |
1.定时器2的初始化配置代码,注意:初始化后,不使能TIM2!!3 ^) `9 J1 q1 h& j3 A0 ]  Y$ s
  1. /*****************************************************************+ w0 _0 {, u, d- L  T9 I* m8 L
  2. 函数名称:TIM2_Init(u16 arr, u16 psc)+ L! T0 S3 ~: X- R/ {
  3. 函数功能:定时器2 初始化函数
    . Z' x' B% W3 ~
  4. 入口参数:u16 arr:自动重装载值, u16 psc:时钟预分频数
    ( H$ ]! ~/ l* V2 o, t
  5. 返回参数:无( b; K% \9 ^# A3 r3 ]
  6. 开发作者:闲人Ne6 G# m, W1 m/ X6 n
  7. ******************************************************************/
    " J7 L- G2 e1 m; m6 ?9 G8 I" z5 w
  8. void TIM2_Init(u16 arr, u16 psc); t0 J! |9 p4 ?# t! T
  9. {
    4 K$ H# M. {- R, S: s
  10.   TIM_TimeBaseInitTypeDef TIM_TimeBaseInitTypeStruct;
    5 G$ M: C+ I7 H: H% \
  11.   TIM_DeInit(TIM2);                                                                                       // 定时器 2 复位5 f) B1 M. [  s  c6 H7 D' H2 t$ u
  12.   RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);              // 使能TIM 2 时钟( L2 N! d. Y5 E2 |( U1 `9 b* o3 t
  13.   // 定时器 2 参数初始化配置
    . m' ~4 q8 z% T. V) i
  14.   TIM_TimeBaseInitTypeStruct.TIM_Period=arr;2 q! U7 }/ `0 C+ }& |# A
  15.   TIM_TimeBaseInitTypeStruct.TIM_Prescaler=psc;
    # j3 [# N$ m' l% i4 [8 @
  16.   TIM_TimeBaseInitTypeStruct.TIM_CounterMode=TIM_CounterMode_Up;   // 向上计数模式5 C( [' ?0 U$ n* R/ s, W
  17.   TIM_TimeBaseInitTypeStruct.TIM_ClockDivision=TIM_CKD_DIV1; ( u" u0 E/ F. J- v2 \8 J2 d
  18.   TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitTypeStruct);" a. N# e3 y) A4 z2 {& G) `4 q
  19.   // 定时器 3 中断优先级配置# a% D. S! t' a; |! |. ]' J  B+ J
  20.   NVIC_Configuration();
    % w. Q5 ~  t3 w" I4 `7 }
  21. }
复制代码

; [( L/ M  `% u1 l2.定时器2开始和结束相关代码,注意:引用了2个放在main.c文件里的变量!!$ Z8 L- f$ H: `- T2 a: h) b% @" e% K
  1. /*****************************************************************
    ) n8 y3 u% z/ b0 A+ |$ E
  2. 函数名称:TIM2_Clock_Start()
    . A3 O0 n0 w2 \& }9 u
  3. 函数功能:使能定时器 2 函数,开始计时( ]1 h% K, T, B( F
  4. 入口参数:无4 {( j; ]4 F5 u& {
  5. 返回参数:无- h9 t% O/ K7 n, T
  6. 开发作者:闲人Ne6 L7 c% |" v$ A
  7. ******************************************************************/
    , r- k/ \0 Z& i& |3 a6 K
  8. extern u8  OverflowNum_cnt;                                    // u8 计数器,用来计算溢出中断的次数,初始化值为0000 0000+ z9 ?* |5 m4 q5 x9 B5 p7 R
  9. void TIM2_Clock_Start()
    0 N" x/ I, |- U7 a% o1 o% q1 D
  10. {8 g4 V' C8 w  l& [) [
  11.         OverflowNum_cnt = 0;; Y, E2 ~* a3 G) I
  12.         TIM2->CNT=0x00;                             // 将定时器 2 的计数器至零
    8 p, \8 F6 c: g, f' \& @
  13.         TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);    // 针对TIM2_DIER寄存器,[0]位,UIE至1,允许更新中断, I% W7 v0 F* [* ~
  14.         TIM_Cmd(TIM2,ENABLE);  0 [& q: v: n$ a/ s. `
  15. }
    2 @; D+ K; v+ D2 s) ]9 u9 d
  16. /*****************************************************************/ Q. b5 r' `. \& i, N0 M, v5 F
  17. 函数名称:u16 TIM2_Clock_End()
    0 L5 j+ ^/ _% Y3 T$ \! _4 k2 ?
  18. 函数功能:停止定时器 2 函数,读取CNT数值
    : Q/ B9 Y+ Z6 k
  19. 入口参数:无. @" q0 r8 a2 ?3 @- o
  20. 返回参数:u16 cnt_value,返回当前TIM2_CNT的值' r9 h& y3 A: M
  21. 开发作者:闲人Ne
    $ }8 T) A& t' w1 H2 U! W2 E
  22. ******************************************************************/) J: ^& z# D  B, y3 j& k9 G( B+ D+ j) K
  23. extern u16 cnt_value;
    ! t/ t8 Q1 w2 a6 `+ P. M
  24. u16 TIM2_Clock_End()
    * F0 g+ u. j7 a8 {0 F! P* K
  25. {
    . n+ r; p& }, ~3 `# F: }
  26.         cnt_value = TIM2->CNT;
    8 g6 Y% O3 Z7 y$ T
  27.         TIM_Cmd(TIM2,DISABLE);
    ; E% w  ~# ^) H; L
  28.         return cnt_value;
    $ f7 c! z% R, O/ V: T. n
  29. }5 r! U0 u) ~& A8 @: d" e& x# g
复制代码
3 S1 T8 _& R# V* f+ i( I# D
3.定时器2的中断服务函数,主要目的是每发生一次溢出中断,OverflowNum_cnt值+1,如果OverflowNum_cnt值溢出,就报错。
! o4 o8 j- I- X2 \$ R, |
  1. /************************************************  d7 H9 P  v) z' w& B0 Z
  2. 函数名称:TIM2_IRQHandler()) k  M2 x2 C+ g% ^  W+ [, g6 `
  3. 函数功能:定时器2中断服务函数7 |. S' F6 g, r* c
  4. 入口参数:无, J+ V0 h. h7 V4 A2 ?4 O( n, \
  5. 返回参数:无+ a, X7 N# u# w' n5 g5 b
  6. 开发作者:闲人Ne
    : M! l3 G! K, b- k- [) i
  7. *************************************************/% Y1 e, t& D, ]0 B/ h* e. U  p
  8. extern u8  OverflowNum_cnt;                                                                  // u8 计数器,用来计算溢出中断的次数,初始化值为0000 0000                                            
    . Z3 v9 s3 h* x. z7 G5 g9 X
  9. void TIM2_IRQHandler(void)
    + @3 [  T7 M7 m$ m  M4 e8 H& Z9 `4 {+ A  c
  10. { 3 T2 z3 }( |) K
  11.         if(TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)              // 判断是否发生更新中断
    1 i  C, y6 @. w6 [: b# A# n
  12.         {5 m2 A- J: [) c+ l1 z# N
  13.                 if(OverflowNum_cnt==0XFF)                                              // 判断OverflowNum_cnt是否溢出                        
    6 n9 @& i; p$ Z; `) E
  14.                 {         
    8 a% X* j0 b. F3 I" [  s
  15.                         printf("错误:超出最大计算时间!");
    # K6 A$ U# Y4 H8 h# C9 e) i. K
  16.                         OverflowNum_cnt = 0;                          // OverflowNum_cnt置零$ R+ j7 J& G% Z1 {
  17.                 }* U9 j% ~: B$ q
  18.                 else
    - z/ D8 ], ]* ?) `- \' F
  19.                 {5 m0 m7 N) L; j2 h# ~
  20.                         OverflowNum_cnt++;7 U1 C) e# Y" v* V6 L
  21.                 }% m# T& y6 x, h) _, C6 C# z! m
  22.             TIM_ClearITPendingBit(TIM2,TIM_IT_Update);       // 清除定时器2中断标志位
    3 W7 I- i- W2 o3 \* Y, h2 g, p
  23.         }2 E$ O# o% B' ~. x( W
  24. }
复制代码

3 p# g  v& d. ^4 W6 h9 {4.主函数,这里注意,当TIM2_arr = 7199,TIM2_psc = 0,那么TIM2 中断时间间隔为0.0001s,又因为u8 OverflowNum_cnt最大值为255,所以所创建的定时器2计算某段代码的运行时间上限是0.0001 X 255 = 0.0255s,即25.5ms。如果被测代码的实际运行时间大于25.5ms,那么就不适用了。
) U2 ^7 Q! }1 Z9 M- L' {" F1 ?
  1. /************************************************
    , u9 {) p* ]0 |# N7 s
  2. 函数名称:int main()! f+ Y3 z# T* Z
  3. 函数功能:主函数入口
    ' l! Z3 K* C. P  t3 S% J) q. z! M$ _" C' f
  4. 入口参数:无
    " p* p$ ?: W  U$ o: Z5 J* x8 Y
  5. 返回参数:int+ A- _! O7 M8 i
  6. 开发作者:闲人Ne" U  }+ w7 Z  O. v7 D: [; Z9 S$ Q
  7. *************************************************/# Z; j3 |! C, t) l+ ]0 v. I; n
  8. u8  OverflowNum_cnt = 0;     // 溢出的次数
    " ]2 G) e3 w% Q5 j! f2 u
  9. u16 cnt_value       = 0;     // 最后一次cnt的数值
    " \: J, f! C: ?( s3 @  L
  10. u16 TIM2_arr = 7199;  
    9 M, K" n  Z6 z8 g* x
  11. u16 TIM2_psc = 0;
    & \8 [+ u0 ]4 X% H( b8 y
  12. float TIM2_looptime = 0.0001;                       // TIM2 中断时间间隔,TIM2_looptime=((TIM2_psc+1)/72000000)*(TIM2_arr+1)' a) b: g" o$ ~- z* L
  13. float TIM2_clock = 0.0000000138888888888;  // TIM2 cnt更新周期,TIM2_clock=1/72000000
    / \4 ?& g/ H% m( }% W
  14. u16 delay_time_ms=10;                      // 模拟某段代码的运行时间
    . E. n( X4 ~6 [6 d5 p, S
  15. int main(void)
    1 {3 k' r& T4 D4 k. q( R9 t
  16. {
    9 C+ |9 s+ Z8 ~, K; S! S+ F
  17.   float CodeRunTime=0;              // 计算某段代码的运行时间
    . L: m( {$ L- m
  18.   u8 t=0;                           // while循环计数用( y! h/ Z; q* m0 T- g% l
  19.   delay_init();% D' o/ W$ ]7 o2 p5 ^4 |! X) P
  20.   LED_Init();1 @- H- v6 i1 K! h- \, D) v
  21.   My_USART1_Init();    f/ V8 v" i3 M* R! H- B! p' C
  22.   TIM2_Init(TIM2_arr, TIM2_psc);        
    : T, E" d2 W) i: F8 g% h% G
  23.   NVIC_Configuration();: q9 p0 @: k& y* \2 O2 l
  24.   while(1)- I  {$ o' A' `
  25.   {
    / `3 J4 H; Z6 p
  26.         TIM2_Clock_Start();
    # F6 G& Q  i3 J# ?0 P3 [* ]6 w
  27.     delay_ms(delay_time_ms);             // 某段代码的运行时间* N7 L# v" x+ b8 y) U) _
  28.         cnt_value=TIM2_Clock_End();( o* a8 B7 B7 G* X  {: }! A
  29.         CodeRunTime = (float)cnt_value*TIM2_clock+(float)OverflowNum_cnt*TIM2_looptime;               
    ! D# X9 N) A* g6 Z) `/ J: E
  30.         t++;6 b: M3 M7 ?" |" n. [* B
  31.         if(t==100)% B! A( b) H) l/ x
  32.         {
    3 T; O8 ^" @6 N. B1 @* o# ?8 W
  33.                 printf("设定某段代码的运行时间为:%d毫秒\r\n",delay_time_ms);! Y( d  k+ y2 Y  {) L4 b# }
  34.                 printf("实际某段代码的运行时间为:%f秒\r\n\r\n",CodeRunTime);+ }$ m' J& S' t% U. w  y$ Y$ d
  35.                 D1=!D1;     //提示系统正在运行//        
    4 n% E/ X" T4 `8 P
  36.                 t=0;
    9 }5 v5 `, n( q7 v0 o. w% D
  37.         }                 5 W7 @" H4 o% n* `
  38.         delay_time_ms=delay_time_ms+1;7 E9 ^( n# q' {! ~) T: a+ i
  39.         if(delay_time_ms>20)
    , T, b7 q- P- F% y, k& M" }
  40.                 delay_time_ms=10;                . @4 M) L& t5 L7 c! d/ B: I
  41.   }
    ' w0 S' X; y) o0 L
  42. }
复制代码
  s; m5 f: j. I5 M( g
实验结果8 }/ V6 |/ h$ [! V  O$ U2 a
在串口调试助手上显示结果如下:7 }+ L7 z% z0 A- @6 ^
20210102144801409.png " j7 n3 @/ t$ B+ Q3 ~
/ k" q+ ]9 W* ^8 z& L
经验分享( b; V) _) J& z5 n
为什么要测试代码的运算时间?因为有时候,程序没必要运算的非常快,适当的降低运算时间,可以降低功耗。此外,有些功能需要实时的、快速的给与反馈,比如自动驾驶、无人机、主动控制这类工作,如果算法很牛逼,但是运算一次周期长,那也没什么实际用处。
. L! a, }# S# V/ h————————————————
' z: M0 @" ~% [7 B2 r版权声明:天亮继续睡0 X4 L9 N# n  T
; B8 X7 h; h% G$ q; N: j

3 c- D1 T5 y  |! O& b( N' A9 c
收藏 评论0 发布时间:2022-11-20 15:24

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版