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

基于使用Stm32延时与计时方法

[复制链接]
攻城狮Melo 发布时间:2023-3-17 19:22
一.延时的3种方法
& R* V5 @& U7 \6 L5 X5 Z) n首先,先了解一下什么延时。顾名思义,延时即是延长一段时间。* v2 C0 I# u' c2 U" t' L. t7 V
% l' B) C1 I. E. o
1.循环延时$ O8 P0 U( i/ K+ s+ z
这是最简单的延时方法,让单片机做一些无关紧要的工作来打发时间,这里通过循环的方式实现。但是,这种方法想到做到精准延时是需要经过不断测试的。
# x4 s6 _' A( M- g* K# X2 h; ]
  1. void delay_ms(u16 time)
    . h) J3 j& `2 B1 A1 j% x
  2. & r8 x  f' I" R) {! A
  3. {   
      ?. i6 h7 m  @/ B
  4.    u16 i=0;  0 l) {# {! g) j2 a9 d
  5.    while(time--)  U1 l, B, p- A. U$ s
  6.    {
      z7 g1 v  }  Y  y. N
  7.       i=12000;  //自己定义
    ( N: J6 {1 C( J- v/ Z: q
  8.       while(i--) ;   
    ) \5 I# a% f, F. I+ S. ^( s0 L8 \
  9.    }
      e& i: {+ o; ?, r0 k
  10. }
    & j, f0 u! X! w$ V% o
复制代码

) C. E7 {8 d% T5 s# \2.定时器中断延时与非中断延时3 S; ~' J- w& J" F. O8 `+ t: I- K
在实际应用中,我们常采用的是定时器延时。定时器延时分为中断延时与非中断延时。两种方法在延时效果上是一样的,只是实现的过程不一样。5 j+ n- v! B. Y0 @& P' q/ m% d3 |+ I
. F/ J+ Z2 a) @9 S
中断延时通过在中断中的计数值的不断递减来达到精确延时,而非中断则通过在循环里不停查询寄存器数值来达到精确延时。前者因为中断的存在,不利于在其他中断中调用延时函数。在很多延时教程中,都喜欢推荐非中断式的延时。不过对于非特殊情况,两者的效果是一样的。反而非中断延时需要操作寄存器,反而更难理解。1 }# t  l" S& ?  M4 E

4 q2 ~+ K" C2 W, ]) v4 D/ N

" _3 P% p* V3 x& G6 {- |# S三.定时器中断式计时与延时
7 ~, D2 m; z+ w8 [. G首先,需要用CubeMX配置一个定时器(以TIM4为例),配置如下:) ]5 ?3 a$ k! `& G" @1 s5 h
4 o2 G9 F. b1 {1 u& h1 Z. S
20200711152339345.png $ {3 E7 N1 P5 d5 p( {: g

5 o( C  B5 w: @. u, a5 r0 A) e步骤:  y/ |. E4 [3 l6 |3 G  {2 R' X& b8 k
6 o! }; \1 c" z+ p+ b- ^' V% W
    1. 打开TIM4,将分频系数设置为71(我使用的是STM32F103C8,高速外部晶振为72MHz,分频后所得频率即为1MHz,换句话说定时器每次计数的时间间隔为1us)。分频系数的需要视自己选择的芯片而定。, i) k3 U, K1 C
% j8 R. l# U7 s, q$ N) T
   2. 重转载值设定为最大值65535,同时打开中断。定时器每次计数的时间间隔是1us,而计数到65536将会溢出产生中断,所以每一次中断的时间间隔为65535us。
4 C/ k0 o5 l; I; p# B3 O5 J1 o  W& a& o& Y0 d9 B) Q
   3. 已知每次中断的时间间隔(65535us),同时记录下中断的次数(TimerCnt),再加上定时器当前计数值(CNT),便能得到系统的绝对时间了。即:
+ j- h! w$ y7 h7 R7 ]. T7 v& P& _  T" ?/ b' H; t2 s% v
SystemTimer=TimerCnt*65535+CNT
1 k7 c8 |1 S) }) d1 o- q! I
以上就是利用定时器计时的原理,他能够记录你的单片机从开机后每一刻的绝对时间。下面给出实现的代码:$ H% f* T% e* ~
  1. volatile uint32_t TimerCnt; //定时器中断的次数(设为全局变量)
    . X3 n2 _8 f" s0 |
  2. " S2 ?3 D8 }" E, |8 @
  3. void delay_Init() //定时器初始化: O5 F# ~/ W4 f" ^% B
  4. {
    $ a- t1 i( A3 p9 c, U5 B5 T# v
  5.         HAL_TIM_Base_Start_IT(&htim4); //使能定时器中断
    0 ?# J! d, j# a  k( O0 i" u$ D
  6.         HAL_TIM_Base_Start(&htim4);  //启动定时器: M1 N% Q( A& r# k
  7. }# `* Y6 o0 S/ X4 \4 O# J
  8. 3 _+ k% [9 [5 q8 q; I) ?' I
  9. uint32_t Get_SystemTimer(void)//获取系统时间的函数$ B+ s6 H3 G( H( E
  10. {
    3 j( m# n9 X# }& U6 [' j2 E
  11.         return htim4.Instance->CNT + SystemTimerCnt * 0xffff;
    1 z% n- d' _, ?9 b( {
  12.         //系统时间=定时器当前计数值+65535*定时器中断次数; \' M9 `2 K: L" h8 [2 g
  13. }
    ( Z* A1 ^3 y5 X8 |' [7 ?

  14. + z# D6 ^( T) j) F* v) u: {( A
  15. + ^. m% g0 F# o* b8 h
  16. //CubeMX生成的TIM4中断服务函数,在stm32f1xxit.c中. [. N; U$ N( a
  17. void TIM4_IRQHandler(void)  
    , e1 m/ ^% {4 N7 L& ]4 q
  18. {
    , V! v* ~7 v6 s2 h" P
  19.   /* USER CODE BEGIN TIM4_IRQn 0 */# ?& k* b9 N7 z3 }
  20.   /* USER CODE END TIM4_IRQn 0 */8 Z# z# D; j0 K* H6 F. y" e
  21.   HAL_TIM_IRQHandler(&htim4);! {2 w& K' D' @/ U5 z
  22.   /* USER CODE BEGIN TIM4_IRQn 1 */8 H. |* q& i7 T2 D# ?: \5 t
  23.         TimerCnt++;  //每中断一次TimerCnt计数值+1
    ' P4 a4 d1 s5 B; g# \1 X5 t( R
  24.   /* USER CODE END TIM4_IRQn 1 */5 Z# i+ O5 d$ }4 c5 i$ a
  25. }
    * F6 M) P$ ]2 X$ O) |* b5 F( Q5 d
复制代码

8 Q& y2 ?' h- \+ ?  R下面是我测试时的效果,Stm32从定时器初始化后开始不停得计时,计时精度还是挺高的。4 X9 U+ T5 y, p. C0 `! j8 Y0 V

6 O( I4 a8 Y. x& i! \( _
20200711175307347.gif
; o3 O$ c$ I2 G1 a% `

8 x4 P: \6 H: p# S7 n计时记录的是单片机开机后的绝对时间,那么以此为时间轴,延时也就很容易完成了。只要记录下你延时开始的时间,然后在你预定的延时时间里用循环来阻塞就可以了。在上述的基础上加上如下代码;
1 F: Y2 n) u/ N3 B" u+ h
  1. //微秒延时
    & c8 p4 |' ?( i- m+ x
  2. void delay_us(uint32_t delay_time)
    0 F& b$ S& t+ [/ o7 N
  3. {
    5 N' A' ]' @, e2 h( J
  4.         uint32_t temp = delay_time  + Get_SystemTimer();+ w. P4 F* p3 g
  5.         while(temp >= Get_SystemTimer());
    : D. y' j9 d5 s6 `- \% H2 p7 V
  6. }1 Z7 x$ b1 g" |5 `3 N, l2 V

  7. " N/ e( @7 l& W
  8. //毫秒延时
    * `, o6 C: v! l+ ~
  9. void delay_ms(uint32_t delay_time)! }) O/ A0 e/ U$ o+ p
  10. {
    7 i: d* {( v& B( P
  11.                 uint32_t temp = delay_time * 1000 + Get_SystemTimer();9 \# ?# ?9 p4 i6 a
  12.                 while(temp >= Get_SystemTimer());, N, I) m7 o+ T  @0 k& ]
  13. }
    ! D" C& H5 U+ `* o* @
复制代码
( \" Q* u# Q( c6 C1 x$ ]
二.定时器非中断式延时* P3 v! _8 P$ Y9 E
以系统滴答计时器为例(代码来自网络,亲测有效)
: p& N9 \, U! H% `7 x; C
  1. //微秒延时
    + S/ F. T" v: L7 ~2 H
  2. void delay_us(uint32_t nus)
    * ^5 I" R5 ^3 g, {1 c) A0 p6 s
  3. {
    ! P5 _  G3 p# F4 B
  4. uint32_t temp;) Y% K9 R6 X  a
  5. SysTick->LOAD = 9*nus;5 ]& _  s  m" z
  6. SysTick->VAL=0X00;//清空计数器; T! v" T: G; ?# r1 C
  7. SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源, d% \+ f0 r- C
  8. do/ U& G* C; {1 S
  9. {
      p- v! p9 y: ]: Q1 W2 e
  10.   temp=SysTick->CTRL;//读取当前倒计数值: P$ d- X/ M0 Y; a( P0 o5 }+ q, m3 b
  11. }while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达# _+ r! G: j- b( ]7 y' ~4 p+ `
  12.      SysTick->CTRL=0x00; //关闭计数器
    4 M" x! W" w1 J- G
  13.     SysTick->VAL =0X00; //清空计数器
    + T/ Q: A4 Y, t0 M; O; X. }) r
  14. }
    + L' @8 o: v+ u7 _+ |+ `

  15. $ W' q4 [  C& f1 i" A
  16. //毫秒延时. U9 n# V5 {2 [# N$ l* r1 R
  17. void delay_ms(uint16_t nms)5 W4 V0 A( j# J: R# k
  18. {
    0 p. I9 F5 j& ^% t: f2 `, m
  19. uint32_t temp;. L7 R' z2 {  j: z
  20. SysTick->LOAD = 9000*nms;
    " m% R% X; O6 Z7 s6 ]9 K- m9 d
  21. SysTick->VAL=0X00;//清空计数器! J0 l$ g! j3 L4 I% b( E. a
  22. SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源
    ) l, v, `' o+ K7 O$ {
  23. do
    / D; t1 U$ o  s' a; P1 @1 D$ K
  24. {- o. `- E) a4 C% e. G% Q
  25.   temp=SysTick->CTRL;//读取当前倒计数值
    4 `& m( t( J) K
  26. }while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达
    $ b  {, b9 F. m+ |0 U7 u5 a5 m
  27.     SysTick->CTRL=0x00; //关闭计数器
    ; v  R) U1 _( o! U- |
  28.     SysTick->VAL =0X00; //清空计数器3 A: `: R4 _  ^( }
  29. }
    ( ~3 W7 D; R- w
复制代码

  I: q- q, h* E) ?, m( y四.代码例程* ^/ |, \) y& H) i0 K
已经把我写好代码上传到CSDN上,已经调试好,亲测有效。
; P2 I1 x1 v1 j/ p0 w————————————————! c+ F1 F+ s( T
版权声明:冬瓜~
4 g7 C: e; i6 q( u, U  R如有侵权请联系删除
; n. h/ O" a2 v8 X4 B6 d+ @5 g  T$ T  A

  L- u5 {# d  n3 g- S
赞 收藏 评论0 发布时间:2023-3-17 19:22

举报

0个回答

所属标签

相似技术帖

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