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

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

[复制链接]
攻城狮Melo 发布时间:2023-3-17 19:22
一.延时的3种方法6 u4 D4 Z8 j) p9 Q, K3 i0 Z8 E
首先,先了解一下什么延时。顾名思义,延时即是延长一段时间。
! v" q0 r! A) R$ y2 ~7 e
5 C4 T+ B/ j7 L; K/ ?( a1.循环延时
" K9 u7 L2 `3 y. f- h" D这是最简单的延时方法,让单片机做一些无关紧要的工作来打发时间,这里通过循环的方式实现。但是,这种方法想到做到精准延时是需要经过不断测试的。
9 C" h2 o5 u8 P8 j% ^5 x2 d
  1. void delay_ms(u16 time)6 _7 U/ }' x- s: @& q- [# Z
  2. 4 @1 ]% }# }1 p5 z3 F- j
  3. {    # a. R3 q" W1 P. H- C
  4.    u16 i=0;  
    8 D9 l1 a4 y5 A, T- q) L
  5.    while(time--)$ G. D( I8 n% m2 u2 p  H1 {
  6.    {
      ~3 @  a2 h7 g) H! y8 R
  7.       i=12000;  //自己定义
    9 s+ {5 o$ U8 w
  8.       while(i--) ;   
    ; F3 h5 z& E7 k7 V" J2 u& t
  9.    }, m8 p+ _# {$ W+ p- K! D% M/ n
  10. }
    9 w3 S3 O7 {# N$ ?! g
复制代码

& `, G4 F( p2 M' I! w2.定时器中断延时与非中断延时( ^5 ^6 A, e; I
在实际应用中,我们常采用的是定时器延时。定时器延时分为中断延时与非中断延时。两种方法在延时效果上是一样的,只是实现的过程不一样。2 X1 _: _. A+ s

' H. m% e7 e5 U中断延时通过在中断中的计数值的不断递减来达到精确延时,而非中断则通过在循环里不停查询寄存器数值来达到精确延时。前者因为中断的存在,不利于在其他中断中调用延时函数。在很多延时教程中,都喜欢推荐非中断式的延时。不过对于非特殊情况,两者的效果是一样的。反而非中断延时需要操作寄存器,反而更难理解。
0 C9 Q2 A9 ^7 N6 j* T: K- O  ~* P+ i4 }( ]
* ^" p3 F4 P# m4 m
三.定时器中断式计时与延时. r  a  p! n0 v
首先,需要用CubeMX配置一个定时器(以TIM4为例),配置如下:
) p& v8 P! _* d9 s3 K; z$ e; Y+ r9 l& N1 |6 A
20200711152339345.png 5 t3 [6 u2 Z0 B0 {) c' `

$ e% I& \1 n! m$ {步骤:
4 x8 }+ b; p3 D& L

7 S8 X( {5 i- F0 L& g    1. 打开TIM4,将分频系数设置为71(我使用的是STM32F103C8,高速外部晶振为72MHz,分频后所得频率即为1MHz,换句话说定时器每次计数的时间间隔为1us)。分频系数的需要视自己选择的芯片而定。
0 m7 J$ i$ ^# i( S; ^" {5 V+ O  X% w, w8 `* c2 N
   2. 重转载值设定为最大值65535,同时打开中断。定时器每次计数的时间间隔是1us,而计数到65536将会溢出产生中断,所以每一次中断的时间间隔为65535us。; M) g* o/ R. A8 ?, U% c$ ]1 ^0 }
$ S/ {5 f0 Z2 s8 p8 r" v8 b" t
   3. 已知每次中断的时间间隔(65535us),同时记录下中断的次数(TimerCnt),再加上定时器当前计数值(CNT),便能得到系统的绝对时间了。即:3 w7 d6 U6 {2 A# P2 {0 J
1 p3 L9 L8 O# P
SystemTimer=TimerCnt*65535+CNT. I, R( ~% Y) I, h2 v& V- y
以上就是利用定时器计时的原理,他能够记录你的单片机从开机后每一刻的绝对时间。下面给出实现的代码:9 [; j$ o* U" N* y: K+ s
  1. volatile uint32_t TimerCnt; //定时器中断的次数(设为全局变量)
    : S) N- ?3 t" M6 z% Z. R$ N
  2. ! @0 V  f0 x' K* l" p/ N7 g4 s
  3. void delay_Init() //定时器初始化
    9 B& ]5 {8 g4 H" T  |/ m
  4. {
    - s- C- V4 P1 a
  5.         HAL_TIM_Base_Start_IT(&htim4); //使能定时器中断
    / x  T, f( k/ D( I
  6.         HAL_TIM_Base_Start(&htim4);  //启动定时器
    9 k* b( Q0 l8 R& Q- s# r0 {4 T
  7. }
    , C# b. \- s* P% D4 H

  8. ; a4 q+ x0 ]9 T) ?3 j
  9. uint32_t Get_SystemTimer(void)//获取系统时间的函数& R. D+ D# F9 c1 l
  10. {
    * j0 f' x" ~- Y1 |0 O% ~/ Q
  11.         return htim4.Instance->CNT + SystemTimerCnt * 0xffff;. k5 c% N+ p5 s$ K/ e
  12.         //系统时间=定时器当前计数值+65535*定时器中断次数
    ) C$ S7 z, t! \* j; e- c" L
  13. }
    , D( x) U2 {% w+ w- S3 Y
  14. 4 t4 U5 T. R* V: q. l
  15. % H7 p# ^2 c# r9 u% S7 ~
  16. //CubeMX生成的TIM4中断服务函数,在stm32f1xxit.c中  P  \! q& o0 N; l# m3 ?1 O
  17. void TIM4_IRQHandler(void)  1 h1 R; a2 d7 z$ y! h3 P6 U9 Z
  18. {2 I2 y" @! j/ k  G6 b9 H
  19.   /* USER CODE BEGIN TIM4_IRQn 0 */, h9 H- \  p% j+ P1 H
  20.   /* USER CODE END TIM4_IRQn 0 */$ k9 z+ K/ Z; }% R* L/ u
  21.   HAL_TIM_IRQHandler(&htim4);
    + K1 P. d, X* m3 J, {  |
  22.   /* USER CODE BEGIN TIM4_IRQn 1 */
    4 m1 w, d8 `) {& ?
  23.         TimerCnt++;  //每中断一次TimerCnt计数值+1# e  A1 g5 f$ ~1 s: Y
  24.   /* USER CODE END TIM4_IRQn 1 */& k" {) c& ^$ x9 N% c% d% p$ W
  25. }& I) v0 V& u9 j% z2 }1 Q( x
复制代码
) I0 w& i0 \/ G8 g
下面是我测试时的效果,Stm32从定时器初始化后开始不停得计时,计时精度还是挺高的。
/ N8 V+ k! l& j; b. Y8 M1 @) j# I. l$ Q, m+ o$ B0 c
20200711175307347.gif $ d* `1 H9 R, a- ]% s0 _4 O/ \
. b( x& N" R' R3 C  W1 \! s- O
计时记录的是单片机开机后的绝对时间,那么以此为时间轴,延时也就很容易完成了。只要记录下你延时开始的时间,然后在你预定的延时时间里用循环来阻塞就可以了。在上述的基础上加上如下代码;8 R0 s, p4 R/ l3 b' c* A- d
  1. //微秒延时
    ( {* f& w0 r4 N+ \3 J, @1 O
  2. void delay_us(uint32_t delay_time)" p; L9 T  K; K/ a
  3. {
    . t6 n4 ]  H4 d
  4.         uint32_t temp = delay_time  + Get_SystemTimer();
    + ~% z# }' ~* l1 S/ W5 e" B
  5.         while(temp >= Get_SystemTimer());9 R: x( C0 q; o- T1 ~, F/ O5 U
  6. }
    2 \1 P/ s% O; b6 a' f" A1 g

  7. 9 N, l$ F6 q" ?$ z, o' Q# {6 E
  8. //毫秒延时
    * _& f& \" g$ l# W( E  ]5 ]
  9. void delay_ms(uint32_t delay_time)1 {6 z( r1 p/ E* M9 r/ H
  10. {
    ) U% e8 \& o' l  x5 {0 A* O. P# C7 F" u
  11.                 uint32_t temp = delay_time * 1000 + Get_SystemTimer();
    / ]. n6 I1 y& t5 E1 u3 J7 _
  12.                 while(temp >= Get_SystemTimer());
    * V: U# H7 x' |6 f# Q. c; M' V; s1 k
  13. }
    ' _" B0 a$ E1 `  l5 w; o4 |# {
复制代码
1 G$ @: y: ^' Y  u) O
二.定时器非中断式延时
& h* u! s  }) _6 o以系统滴答计时器为例(代码来自网络,亲测有效)
: s3 f& l. m  x& Q1 j+ x
  1. //微秒延时" G) _. w& n3 v& h  ?: \! {! u' G
  2. void delay_us(uint32_t nus)! o9 W/ F4 e/ C$ U
  3. {0 I- o8 N2 F+ X0 q* X
  4. uint32_t temp;
    $ `7 r; A) P1 K: T# h2 @
  5. SysTick->LOAD = 9*nus;
    ) }* P- V4 [5 I
  6. SysTick->VAL=0X00;//清空计数器
    9 y9 a7 L5 U7 S# T9 J9 w# o/ F. g
  7. SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源) |0 `: W: C2 \: R( K2 Z5 Y
  8. do, L  ]" O+ I) ?& X
  9. {( k( b; y0 C% @) U% ^+ I, T
  10.   temp=SysTick->CTRL;//读取当前倒计数值  W- B6 \0 U( m
  11. }while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达
    1 B+ Z$ Y: e4 k0 s
  12.      SysTick->CTRL=0x00; //关闭计数器$ e2 a/ V+ P. N, t& n. U* w
  13.     SysTick->VAL =0X00; //清空计数器
    / ^) c* ?. \* s. R) H/ @2 b
  14. }
    0 O9 x2 m6 B4 e# T( Z8 X  K
  15. 9 c+ G4 w/ l" _1 U
  16. //毫秒延时' k8 w* w$ P9 Z  b
  17. void delay_ms(uint16_t nms)
    % j  _6 w, G+ A6 k$ C
  18. {, q5 T, b: @' L* A! P' K5 ~# c& \
  19. uint32_t temp;4 U3 w  r; ]; Q8 x5 d
  20. SysTick->LOAD = 9000*nms;$ j' a5 G: D1 I: V
  21. SysTick->VAL=0X00;//清空计数器" j6 }* p0 ?4 L" a9 w, q* O
  22. SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源/ L. b- ^) L5 u
  23. do! k: C7 u1 `) H
  24. {! Z2 y) Z3 V' l8 C- F8 a; p
  25.   temp=SysTick->CTRL;//读取当前倒计数值6 L# A* t* G# o3 {/ [1 `
  26. }while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达
    4 `$ z2 A: Z  V# z
  27.     SysTick->CTRL=0x00; //关闭计数器
    3 m, l. m; X5 @8 ?% j% r! o
  28.     SysTick->VAL =0X00; //清空计数器. u" }. G$ B* T: z4 [6 n: u; ?* ^
  29. }8 F* A  p7 W$ m0 J4 E
复制代码
; p" y; j2 ~9 e! b4 @6 t; j( U& f
四.代码例程
/ j1 K0 x, X: O& |% I" W* b已经把我写好代码上传到CSDN上,已经调试好,亲测有效。
1 v+ K) g8 H% B& T8 L/ p8 x————————————————
" i& M6 J- V, E8 O4 N! x版权声明:冬瓜~
, E( ]$ X  T9 U( ^如有侵权请联系删除1 T9 m1 ?1 e) Q/ D+ o) I! {/ H

# I, n8 C! L) ~& p3 B+ M
1 m* U# j+ f* n, g9 x
收藏 评论0 发布时间:2023-3-17 19:22

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版