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

【经验分享】STM32 基础重点—SysTick定时器

[复制链接]
STMCU小助手 发布时间:2022-4-27 23:04
11.1 关于SysTick定时器
+ Y/ L* ?% |/ X  X3 JSysTick定时器(又名系统滴答定时器)是存在于Cortex-M3的一个定时器,只要是ARM Cotex-M系列内核的MCU都包含这个定时器。使用内核的SysTick定时器来实现延时,可以不占用系统定时器,节约资源。由于SysTick是在CPU核内部实现的,跟MCU外设无关,因此它的代码可以在不同厂家之间移植。
) z0 {# S% h7 b, z9 R) D; ?3 \) b+ R; A8 m' g$ y
本章将使用系统滴答定时器实现延时函数,注意SysTick用于了HAL库的毫秒级延时函数“HAL_Delay()”,不建议日常使用SysTick去作为其它用途,这里只作为演示。
+ A1 A4 @& ^+ _  R. {$ A" L; n; c/ `$ j; J9 v0 T' p* r& Z
SysTick定时器是一个24位递减定时器,即计数器可以从最大值224开始,每个时钟周期减1,当减到0时,会产生Systick异常,同时再自动重载定时初值,开始新一轮计数。通过设置这个定时初值,就可以实现得到指定时间。如下图 11.1.1 所示,y为定时器初值,然后随着时间增加,值逐渐减小,直至为0,再重新加载初值,如此往复,x1、x2、x3这些时间段,就是我们需要的延时时间。, N4 d+ f2 @3 Z9 E- p
( O) Z& s% d) |" z1 z- l1 ?" I
[[_9E}~4BAPVH2QA1JFFR@C.png
  G7 K" p; a  V8 [* E0 G* c: o
% V$ e% |, R4 `1 X0 u2 c, X) R图 11.1.1 Systick定时器工作示意图2 Y+ E+ e* V- R0 z; \7 ^
假设STM32F103工作在72MHz,即72000000Hz,意味着1s时间内,会计数72000000次。那么1ms则计数72000000/1000=72000次。这个72000就可以作为系统滴答定时器的初始值,将这个值写入系统滴答定时器,定时器在每个时钟周期减1,减到0时,就刚好是1ms,同时产生中断通知,再次加载72000如此反复。HAL库提供“HAL_SYSTICK_Config()”函数去设置这个初始值。5 w6 L' K! L2 b, W8 f

9 l; J( k, Z# n9 g4 M- h系统滴答定时器控制寄存器比较少,整体比较简单,借助本次机会详细分析一下寄存器和HAL之间是调用关系。系统滴答定时器只有四个控制寄存器:STK_CTRL,STK_LOAD,STK_VAL和STK_CALIB。因为系统滴答定时器属于Cotex-M3内核的外设,相关寄存器介绍不在《参考手册》,而在《3_STM32F10xx Cortex-M3编程手册》,后简称《编程手册》。8 u! Q  k9 ]  _1 K
! Q& h: S; L% q) b
系统滴答定时器控制和状态寄存器(STK_CTRL)

3 |) f- j1 ?9 a/ U. O3 T/ b: I, \  R4 _- I  s
[3{6M[FR`KH03Z%FP{FP]@I.png
. \( x' ^2 l" Z
) b2 S& R% s" K9 o重点关注Bit[0],用于使能系统滴答定时器,Bit[1]使能系统滴答定时器中断,Bit[2]系统滴答时钟的时钟来源。
0 f0 G3 ?7 |3 c2 |! A" J3 _9 L8 `, h4 `% V, z5 m* e( Q! a
系统滴答定时器加载值寄存器(STK_LOAD)
- B. b$ T! ?$ i5 R, ?* D5 m1 m9 g" U+ Q, W7 ^
E9VBHEX31HP7TKJ2}KS5[%H.png
! F9 {' o5 C+ X. {1 r: f8 L- m! v+ @9 @. y2 m& ^+ T0 o, z( h4 A1 P
Bit[23:0],一共24位,用来设置系统滴答定时器的初始值,因此范围为1~ 16777216。* J- F) V+ U5 N2 l) n0 @3 w$ E

( m2 g+ m2 m: S  D系统滴答定时器当前值寄存器(STK_VAL)
3 B' V) z8 n8 J
8 A5 ^4 t3 o5 n I)3RM7IWY)]A6S1$VNQX3QV.png ; y0 {" U: B( V9 P0 n
, T4 L- q, \$ ]0 {) k7 B
Bit[23:0],一共24位,用来获取当前系统滴答定时器的计数值。
) b* ~! A  p: x! d6 q( Y. z; E
/ U* j5 E. l+ P系统滴答定时器校准值寄存器(STK_CALIB)

/ s3 o% u0 u$ O- H! H4 O$ q$ K" c! A* a
ES27833[KFM_W@NFVV34YAX.png
* {/ G9 Q$ S( @# u: _  v" e
+ c1 l4 @: t9 [5 v这个寄存器没用到,可以不用管。此外,当处理器在调试期间被暂停(halt)时,系统滴答定时器也将暂停运作。
  W' f0 o" B$ x# ]
0 d+ O  O* g) n在理解系统滴答定时器的工作方式,了解系统滴答定时器的寄存器基本信息后,就可以尝试编写程序了。
6 F+ F' q8 R- d; ]0 k, x: N* b- L
( F- A/ {1 m' F. y* ^6 O3 q' P) A* Z4 G4 [0 |* g+ h
11.2 硬件设计% U/ E$ o( s' D) N
系统滴答定时器属于Cortex-M3内核资源,不涉及外部硬件电路。实验中会用到LED灯,电路设计参考前面LED点灯实验。' h. h6 J8 _9 P! s

2 x% T9 x9 l. Z) g3 d- d( t- {5 t9 g" c8 v
11.3 软件设计% |1 k4 I/ W9 U
11.3.1.1 软件设计思路
& |7 U7 _: h- f1 ^实验目的:使用系统滴答定时器实现自定义延时。
' ]( z0 r; a+ }) n, x8 {) D) R0 q% h# X6 }4 W5 G# M' Z4 T
1) 分析HAL库的系统滴答定时器配置函数;
$ K% _9 r. W$ ^# t% {3 K
* a# i/ Z6 U* D* w9 ?9 }5 B0 E3 {3 E2) 初始化系统滴答定时器(设置计数初值、使能等);
1 q. R$ E$ v3 a  z
; X* ^6 a- p2 l" x1 @# |9 `2 o3) 封装延时函数,设置系统滴答定时器中断处理函数;0 C8 g0 D& M2 [  o3 i/ N
* \8 ~0 y, l* z" _+ q
4) 主函数调用验证;
2 S' U. q" o0 I0 b# ~. `0 x6 i
* D- O5 V" k' r9 A9 _本实验配套代码位于“5_程序源码\4_基础重点—SysTick定时器”。( X8 i, T( O0 I

. T: e, M( s4 }" e7 }+ K; B5 s' J11.3.1.2 软件设计讲解
! ?% a( j( S* |" t
1) 分析HAL库的系统滴答定时器配置函数
8 I7 \& T  v, V5 L! I
: ]! t, n: E' f& o! x5 p在HAL库中,使用“HAL_SYSTICK_Config()”函数配置SysTick的初始值。$ s6 ?6 y/ E! v5 o" [5 M! d
9 t3 k, u: V  d
代码段 11.3.1 SysTick配置函数(stm32f1xx_hal_cortex.c)! p) n4 y, K- A6 H. R
- c4 h- C3 i2 A+ T5 V/ Z+ W
  1. /**
    : b  p5 S  v3 X; i
  2. # W' p2 v3 j3 `
  3.   * @brief  Initializes the System Timer and its interrupt, and starts the System Tick Timer., V5 t& [7 T* L! ]3 A4 z& C6 u

  4. 1 @8 m6 ^& r: t5 ^) b6 k* g
  5.   *         Counter is in free running mode to generate periodic interrupts.6 m( E4 m; E0 e) m) }; z3 Y

  6. + a8 K9 T9 e" Z
  7.   * @param  TicksNumb: Specifies the ticks Number of ticks between two interrupts.
    & i  {  W2 a' P2 J+ b

  8. ( l9 @( w0 T5 M& h
  9.   * @retval status:  - 0  Function succeeded.
    5 n6 D7 Z. z  @& U$ e& ]
  10. ) _8 f2 ]. a. [5 R* }
  11.   *                  - 1  Function failed.
    2 H$ R) L& v' D4 `2 t3 e

  12. " }) d/ J1 v; Q0 X% [
  13.   */
      X3 G# Q1 V$ M5 y% }

  14. . T% i5 C' z5 o$ @1 H* v, b8 X
  15. uint32_t HAL_SYSTICK_Config(uint32_t TicksNumb). I; O  [9 W/ e+ K

  16. 6 z$ l3 m3 [4 X% b& r# Q
  17. {
    : o. ~# S* {- c% B  y% L

  18. 5 i7 O6 I: Z; a) J
  19.    return SysTick_Config(TicksNumb);# A. T4 D( z9 \2 T9 M) E

  20. ( w% g1 c! A0 Y# A
  21. }
复制代码

4 s( R3 A6 B, f* N: O( u' @' t" v该函数调用“SysTick_Config()”函数,函数内容如下代码段 11.3.2所示。' G( ^6 b( d& Y  C% x, b; x
4 `: q8 F; H, y3 V
代码段 11.3.2 SysTick配置函数(core_cm3.h)' n: t2 }2 x6 ~! v6 X* ?

+ `- |& C. ?3 k0 R; W7 n
  1. /* ##################################    SysTick function  ############################################ */
    6 w2 P. ?# [* P8 w! {# a% W
  2. /**
    & i- x$ ?% q1 M, b( ]1 q
  3.   \ingroup  CMSIS_Core_FunctionInterface+ h$ d2 P( h4 b! T: U! U4 u
  4.   \defgroup CMSIS_Core_SysTickFunctions SysTick Functions
    $ U9 e) i0 O; U+ z9 E. [
  5.   \brief    Functions that configure the System.
    # Q' T0 F% i5 E! M
  6.   @{
    ) r5 h/ b9 E& g# \0 K" C
  7. */
    2 p8 a- h( v7 x/ B( _3 R
  8. 7 b9 b- r1 L: d* r3 v
  9. 5 ]( r! ]8 q$ @, T' m

  10. / `* I% D1 O" y
  11. #if defined (__Vendor_SysTickConfig) && (__Vendor_SysTickConfig == 0U)% @, A- T1 R; ?8 V, |9 Q5 c* w5 H7 W
  12. / }1 e( x2 e$ b5 z+ q" ]2 m$ _5 J

  13. 9 H" ]0 c; o4 }. b/ D: l$ [3 X! Q0 Q
  14. /**, X4 G, D9 X4 K" f3 k7 ~; n
  15.   \brief   System Tick Configuration
    ; n. p+ K8 u$ i$ G' ]6 {5 `
  16.   Z9 F1 ?/ g( w; j, N
  17.   \details Initializes the System Timer and its interrupt, and starts the System Tick Timer.
    7 r+ e) o. j9 C+ ^
  18.            Counter is in free running mode to generate periodic interrupts.$ |+ Y3 [( t* s8 G" h! o9 l
  19.   \param [in]  ticks  Number of ticks between two interrupts.
    ; S% L4 U3 I, _1 o( G% H# O

  20. 1 ~3 T1 k# R0 [3 ^

  21. / A: C' J) G- e, V3 a/ t$ G. G

  22. 1 ~1 u, H0 b' U) G7 [
  23.   \return          0  Function succeeded.% s; q0 U( k1 v- s3 V: `8 ^+ ]

  24. * N9 @4 G0 C; r$ J- p! z
  25.   \return          1  Function failed." e# F8 w/ d: k2 i9 z9 t0 b

  26. - d( B& Y5 e) i$ ]1 I
  27.   \note    When the variable <b>__Vendor_SysTickConfig</b> is set to 1, then the
    & {: B. Q2 L. t' u5 X* \0 Q
  28.            function <b>SysTick_Config</b> is not included. In this case, the file <b><i>device</i>.h</b>5 [: p: @+ H" ]7 i1 c( B7 c
  29.            must contain a vendor-specific implementation of this function.2 w) Y! p* z; t5 T
  30. */# d3 D/ n/ i/ D. D! w
  31. __STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
    * ^$ x* G. k5 R) v  u

  32. 9 a' G3 E7 @/ b
  33. {
    7 o) X( h) P+ t! G) n4 }; k. Q

  34. - Q4 x3 S$ i' C  h
  35.   if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)7 J/ D4 Z  m+ r( t
  36.   {9 j5 t0 @5 m0 n) \; @) _
  37.     return (1UL);                                                   /* Reload value impossible */1 Y) B' v% s" R! ^  _, d
  38.   }
    ; U3 i  w. Y3 Z  {7 i# [
  39. 5 o" W& l% F. n2 w$ k0 W) G+ f
  40.   SysTick->LOAD  = (uint32_t)(ticks - 1UL);                         /* set reload register */
    , K+ e0 v0 |6 n
  41. ( u8 y0 `, e9 U% ]  ?
  42.   NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
    8 f: a3 V( c& m, z+ F1 b! l4 K+ k
  43.   SysTick->VAL   = 0UL;                                             /* Load the SysTick Counter Value */* N5 n8 H. [' T  S
  44.   SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |5 ?/ `4 s0 @4 N: E* p+ r2 Z6 ?2 c
  45.                    SysTick_CTRL_TICKINT_Msk   |
    0 I& P0 }  k# `1 z! C2 P6 r$ d" z
  46.                    SysTick_CTRL_ENABLE_Msk;                         /* Enable SysTick IRQ and SysTick Timer */3 y! Z2 Y) I. {( F5 d6 V
  47.   return (0UL);                                                     /* Function successful */4 D6 t9 K: O1 w3 k: @$ n/ j4 j
  48. }# i% l! i% Q1 L" W8 l" \8 N

  49. , z8 o) H3 L/ l5 B" @5 e- C/ _8 S+ G% e
  50. #endif1 [- j* Z/ x: h2 E
复制代码

7 E6 f: S4 w4 @6 K' K6 g1 i# l6 m# C% G. f, z2 T
24~27行:判断传入的SysTick初始值是否大于最大值224;) C  t7 y6 w) F. o: T7 Y

9 `/ |3 P* G# v8 a, m) ?) K, o29行:设置SysTick初始值;
' V, @7 T4 }7 z9 Y/ Y: A: p+ e- m
' R+ z, ?) f5 n( s30行:设置SysTick中断的优先级,默认为最低;
& c; I# ?" _7 K+ d; E6 h  z$ I, s3 m' s8 ~
31行:将SysTick当前计数值清零;
& s& B; L) s7 X# ^) X2 K% d# w" J0 P7 k. J* p, I% O$ z# f3 t
32~34行:设置SysTick的控制和状态寄存器,展开对应的宏,值为“(1<<2) | (1<<1) | (1)”,结合前面STK_CTRL寄存器介绍,可知这里使能了SysTick,使能了SysTick中断,时钟源为AHB。当系统时钟为72MHz时,AHB不分频,也为72MHz,则SysTick的时钟也为72MHz。
6 T' R* t. i! S% C  s7 g4 ]$ O& k; B6 @' y
通过对“HAL_SYSTICK_Config()”函数分析,可知只需要传入SysTick初始值,其它的都默认已经设置完成了。
* @7 W, G$ o" o* G% I6 y2 m- v! J8 b( I' `: \, J1 t% J* d% h, G: Z

) u2 U7 A  _$ P! e5 A: K2) 初始化系统滴答定时器
) b3 p6 T- E7 C3 [5 Z
2 V, D! P- W4 c* u$ B* l/ t
假设当MCU工作在72MHz,SysTick也工作在72MHz。时钟在1s内完成周期性变化的次数叫做频率(单位:Hz),因此72MHz则表示1秒SysTick计数72000000次,即1毫秒计数72000次。
! q, J/ P6 ~: h/ X
" @* [& P; d# w4 z: ^0 \' M" B因此,如果将72000传入“HAL_SYSTICK_Config()”函数,则SysTick从72000减到0,花费时间为1毫秒,创建函数“SysTickInit()”初始化系统滴答定时器,如代码段 11.3.3 所示。
; }8 j2 p6 y6 I: N' A4 r; Y3 t2 }; Q" F" E6 `
代码段 11.3.3 初始化SysTick(driver_systick.c)6 h2 p* |6 f! x' |7 w8 y! r( ?
$ m8 Y2 O& c2 ]
  1. /*8 J, H1 y/ o6 z0 t

  2. : K  _* F6 a) _. A) ]5 w( k+ P% I3 v
  3. *  函数名:void SysTickInit(uint32_t cycle)6 T* k; Y' l1 q! H" g" V
  4. . ]) Y8 R2 Q: G/ O( K# o4 q& h
  5. *  输入参数:cycle,设置系统滴答时钟周期# A7 V6 f! K' u
  6. " `% r- J5 ^: m. |* H9 ^
  7. *  输出参数:无
      E' q2 R1 W/ e8 m' M
  8. / j3 ~- v; P7 {6 w$ A4 Z
  9. *  返回值:无+ b& [; o0 C5 a$ X3 [
  10. : G  J' H6 L7 k  V8 l- x: s
  11. *  函数作用:初始化系统滴答时钟的频率和中断优先级; \# N) y5 E3 O+ B; }" G! ]

  12. # y7 ^' `; H$ c6 R5 W" F
  13. */
    ( E, o2 Z' q9 r3 Z

  14. # @0 ~; U, O. k9 J& P
  15. void SysTickInit(uint32_t cycle)
    ( L; V% E3 i' A$ e4 b' E$ g# Y" V' v
  16. # [6 H0 _  p3 E6 ^% u: p/ `
  17. {9 j' `, b1 A3 S! ~4 M, E% A& D
  18. + T9 u( y9 ~2 ]) d8 {" t0 M
  19.     uint32_t init_t = 0;
    3 O6 s' l( B* z; z, w0 m$ q

  20. 6 s. N  m0 I; E3 m7 O
  21. : ~3 _9 r- l/ V% Z2 m1 Z0 x8 g! E

  22. 3 T( }; x2 }; u3 O, ^
  23.     init_t = SystemCoreClock/cycle;
    1 h: b% A( R$ `! }; Q0 i
  24. 2 s9 P3 P- y$ @7 l" x: h' D
  25. # O4 i5 L8 C6 V
  26. 7 [" A" k& m+ D$ ~8 d
  27.     /* 时间(单位:s)=1/频率(单位:HZ)
    % v5 [: h; W) L8 y

  28. ; Z$ W2 e' }" ]' ~: p9 r! B. D
  29.      * SystemCoreClock频率: 72MHz = 72,000,000
    % s1 F7 ^, v% {+ {" g

  30. : t4 V' M8 X  H) |/ Z& t( @
  31.      * 即MCU 1秒会计数72,000,000次# p/ s; t! J$ ]- y% i

  32. 4 b7 c1 Q# U' q) ?5 E) ]
  33.      *       1ms则计数 72MHz/1000 = 72000次: q/ D* `7 c; V3 d# {2 I8 s- K
  34.   }( H1 J, a" ?3 V' c
  35.      * 72000就是滴答时钟的初始值,它向下计数72000次,计数将变为0,就会产生一次中断
    / b" l$ m& i" l& M" m/ L

  36. 4 p4 A2 F4 t3 v0 c' V, s, z+ d
  37.      * 滴答时钟初始值范围:1~16777216
    7 `, }( v# ]4 j3 b0 |- _

  38. 9 ^  m2 w) H% W9 L5 [4 r( A
  39.      *5 i/ u7 w. o# P% s/ h4 I

  40. 4 K4 P  t7 k* A0 @' n2 p( }
  41.      * SystemCoreClock/1000:    1ms中断一次
    / c3 T8 e4 O: A6 B
  42. * G; C3 V. |, V. w
  43.      * SystemCoreClock/100000:  10us中断一次
    4 t  T2 f( w# ?& C2 \# G: k% E  V
  44. * ^# |$ _9 \8 h5 Z2 |- U9 a
  45.      * SystemCoreClock/1000000: 1us中断一次
    % C: ^* B# i2 d

  46. 7 Y# _3 b! `* O/ L/ Y0 K! S
  47.      */5 k& m4 d  E0 P# i' G
  48. ! E9 I# g6 I; `1 r; J" e) g
  49.     if(HAL_SYSTICK_Config(init_t) != HAL_OK)/ |! t  a+ O" b) w9 W- Y

  50. ! D0 O. a! o* a6 q# }9 x9 }! V
  51.     {
    8 G) Q; }2 |$ \

  52. 1 j4 J4 L" B6 N$ \+ P
  53.         Error_Handler();; G& }; i% ^; `( k

  54. ) R( S1 ^$ S+ k2 A1 h
  55.     }" Y4 p: ~  _& f2 w) A

  56. 8 b% D! C5 U8 \7 S3 i2 _5 [, w: n
  57. * E, \9 B2 S/ C4 Q6 E

  58. + C9 C& `2 q0 ]6 z" q" d; r
  59.     // 设置滴答定时器中断优先级:最高
    - Q9 S( U1 u, m+ N7 e& L, {

  60. 3 R  R4 e; I7 l8 p, f' X; x8 k
  61.     HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);2 X/ k& @7 u* X# L( C& n
  62. 1 T7 u  C+ P) v0 q/ n6 c
  63.     // 使能滴答定时器中断; a3 M' x# d" t: K
  64. : [7 c8 ^  P" I! {2 \: l" d
  65.     HAL_NVIC_EnableIRQ(SysTick_IRQn);
    : v  k# O3 R6 E7 v! m9 Q2 Y1 Q

  66. 1 O! F4 u: G7 z, ^  W$ [
  67. }
复制代码
: ~- {: P3 H9 R7 J6 Q$ J; w
0 t7 @% r* M6 z6 K( K) Q  y1 u7 c
12行:使用HAL库提供的全局变量“SystemCoreClock”获取当前系统时钟,再根据传入的cycle,计算出SysTick的初始值; ; V# S/ y/ I( \6 F
& a$ Q5 f8 ^  V1 G# z# p# b- G
25~28行:使用“HAL_SYSTICK_Config()”函数设置SysTick的初始值,并检测是否设置成功;0 M6 k! ^" L3 E! w6 i  x" s- t
2 W8 Z% f4 e/ R; X( |0 [
31行:设置滴答定时器中断优先级,这里设置为最高。前面分析“HAL_SYSTICK_Config()”函数,知道该函数也会设置中断优先级,这里重新设置为最高优先级,在当前示例里,SysTick中断的优先级不重要;, I5 M0 a3 \8 o; H' S
) O9 E( n2 o/ Q2 a0 K
33行:使能SysTick中断;这里是使能NVIC,而“HAL_SYSTICK_Config()”函数使能的是SysTick;5 Z6 ]4 G* P; [8 q" R
- S7 r- s2 \! I$ f7 V
为了方便修改SysTick的初始值,这里定义几个常见的延时周期,如代码段 11.3.4 所示。当需要延时周期为1毫秒时,传入“CYCLE_1MS”给“SysTickInit()”,则SysTick计数到零花费1毫秒9 d4 Z. ?* f. d/ p

: h. b) o' g7 f" K! G代码段 11.3.4 定义延时周期(driver_systick.h)
$ V  S% p+ f7 X9 Z: I8 G5 e+ k* i# m+ b6 b: l" B; s  H9 ?5 R
  1. #define CYCLE_100MS   10/ g7 K6 d0 {4 k) j+ s7 S+ t
  2. 4 N3 f1 r8 O+ g" U$ ]2 W/ L5 A1 F
  3. #define CYCLE_10MS    100: r; ]! _$ q# H. ^
  4. 1 u: s5 t- ^, L$ d& [0 d! a
  5. #define CYCLE_1MS     1000
    ; j& D8 D9 p" v- E% r. `& y
  6. 5 f2 A- s0 ^5 X: r* K( h' C
  7. #define CYCLE_100US   10000
    - A6 [$ h2 Z% H8 l, K" ^: j

  8. & h6 q, Q) x2 U2 y' B% A
  9. #define CYCLE_10US    100000
      p+ b+ F. B& }3 s! I# k3 X9 z
  10. 9 D3 q5 w) C- |; k$ _
  11. #define CYCLE_1US     1000<span style="background-color: rgb(255, 255, 255);">000</span>
复制代码

* Z4 S; ?' k" y$ H5 f) G3 d% l) A3) 封装延时函数,设置系统滴答定时器中断处理函数
) e/ z9 F, x" L7 O. Q- a% T+ L( {. x1 w- W4 T& Y
创建延时函数“SysTickDelay()”,在该函数里设置自定义全局变量systick_t的初始值,SysTick每计数完一次则进入SysTick中断,将全局变量systick_t的值减1,如代码段 11.3.6 所示。一直到systick_t变为零,结束延时,如代码段 11.3.5 所示。
/ G# Y* R9 |& Q- S- h
. L0 w' `# `% X6 i( x4 h代码段 11.3.5 SysTick延时函数(driver_systick.c )& l" T! ]. O) g* b

- V: B' o  }+ |4 U# C. |
  1. /*
    " E" \2 M3 }$ k% N7 L' t% M; P
  2. 8 {2 ^6 d+ h3 T& t4 X
  3. *  函数名:void SysTickDelay(uint16_t m)) d' C3 J# E9 w

  4. 2 s) R0 l5 T. s3 z
  5. *  输入参数:m-延时时间. U; D! X6 s3 r  A/ b3 i2 @( s2 a

  6. : `' w2 T! l2 g$ y: V
  7. *  输出参数:无
    5 ~$ ]4 r7 L6 K5 A* @0 U3 y8 h
  8. 6 s$ |2 }9 j! ]! W* V
  9. *  返回值:无
    4 Z4 ^! d5 N8 U- C  j0 U1 W
  10. 6 C6 y, h* h& a$ l( W! t
  11. *  函数作用:滴答定时器实现的延时函数
    ( S9 a9 J, M5 _
  12. 7 Q- L1 Y* y7 n2 l
  13. */- h  \9 h$ S- F  Q0 W

  14. / s; D: c! {7 F- a6 _
  15. void SysTickDelay(uint32_t m)
    , |- M4 d: J" q4 B3 B- A7 q% z* ]
  16. 2 L& s- G5 ?0 p% u: q
  17. {# j* B  r8 X, K+ F- C1 [' Y

  18. " s8 ^- j  x4 I& s/ H% i" t. q
  19.     systick_t = m;& B9 I7 ~& R) T& j* O5 z2 w

  20. # N8 G2 U4 f0 e
  21.     while(systick_t != 0);
      Q3 L$ j' U2 x9 O
  22. * s, L: V" s, b3 V( E3 u* x
  23. }5 {; Q, M% u+ v2 r( ]
  24. 3 B0 X5 p+ M( O
  25. ( a" U5 B! K' }5 C
  26. 代码段 11.3.6 SysTick中断处理函数(stm32f1xx_it.c), j" v2 M- ]7 C$ ]4 Z0 X3 n0 f

  27. - H+ x, e3 C( _
  28. /*& [' L! N# D0 V3 b) Y$ [

  29. 1 X! I3 h1 z: L# C( i, M& _
  30.   * @brief  This function handles SysTick Handler.
    ' d, n; U, |# Y3 z/ u
  31. ! e3 w& k7 u2 `. f; j
  32.   * @param  None
    2 ]: {) A- N* v! a1 J1 Z; e8 A
  33. 5 `0 {& f; i: O' n' T
  34.   * @retval None
    8 o/ E7 n; G! P( l! b7 J
  35. + Y# S4 _4 @7 o  A6 v
  36.   */
    + Y/ A1 ^* l" |. d" S. l
  37. # q2 v1 n) ~% J; u7 ]1 _  u' |
  38. void SysTick_Handler(void)
    / y  z+ ?: o. v% R, C" o2 ^

  39. . z% b5 N3 ^7 N1 `. g; S0 o0 T
  40. {
    1 S- U+ Y" K6 v, T, B! W+ j  V6 B: }
  41. 4 b! ?: G2 ]4 t6 l
  42.     HAL_IncTick();
    0 Y2 _$ R2 ^0 N2 \

  43. / c) @, U. j1 A+ Y! q* u
  44.     if(systick_t)
    , L( _3 \) O; ^) r: l  O

  45. 6 W" o6 l+ }7 e8 @5 W  _
  46.     {7 f% I4 s3 ~1 v; N9 P% [
  47. . k4 m2 A4 {) y1 v/ d2 \  M7 {+ Z
  48.         systick_t--;& H5 o. G" R4 D
  49. 1 q# Z1 h, ~& H2 C# Y
  50.     }
    + p* ^5 w* c, j
  51. " m& a" B6 K# R  B1 ]: Z" u
  52. }
复制代码

0 o/ _6 _  ^9 M- H( k6 N4) 主函数调用验证

; e5 ~+ S0 G: ^7 U$ q, T+ M' N+ a& \- K. c
代码段 11.3.7 SysTick延时点灯(main.c)
4 J* t" {: x$ b! N7 l. `2 L% }/ {3 L; W$ |
  1. /*7 C# t6 @* R9 U8 ]1 H
  2. 8 i  K7 J4 n4 [; A: G
  3. * 初始化滴答时钟6 f$ M7 D7 d: Q* o" v

  4. , `; {0 U! x- h. D- K
  5. * 通过改变传入参数改变滴答时钟的频率,即SysTickDelay(1)的时长
    ! Y# J# Q: R" n8 M& G3 ?

  6. - G, S8 w: P* v( b
  7. */6 u5 a( p; g9 ^2 u! ~: G
  8. ' ^, s, \/ k3 A4 j
  9. SysTickInit(CYCLE_1MS);
    1 d4 R- u+ m5 |; @, _9 z6 @
  10.   b) W/ x6 D! @1 Z2 C6 y
  11. 1 ~5 D4 g; \3 R- G9 @: ]9 ~
  12. 2 U7 @/ d( r! o2 R/ s
  13. // 初始化LED  }' q6 h( z8 `5 f" |) f% S

  14. 1 R; o- i. o" d. f) F' o& B
  15. LedGpioInit();. j" x* r8 |) d# w, e6 N
  16. " {; P  C) V$ R: F9 @
  17. while(1)! ^( ~* k3 s7 B) W* b
  18. . C6 j& @2 }' c1 j$ s" V7 j
  19. {1 j, K* k7 d! \
  20. + G- e/ n  _! @* S3 ]$ `& v: X
  21.     /* 通过延时一段时间让LED亮灭实现LED闪烁,可以通过示波器打LED的引脚反转周期,精确看时间是否与设置的一致*/
    . M; G) |2 o: v1 L
  22. ! _3 r: R" l! H' i0 E1 R0 K/ b
  23.     BLED(ON);             // 点亮LED. z$ T7 }% x$ V# Z( [0 T7 v
  24. ! A& f( f% z3 f6 s
  25.     SysTickDelay(1000);   // 延时CYCLE_1MS*1000=1s
    9 }- h6 {4 i9 [, ~+ a- C0 N
  26. 4 p$ _' R- o% h1 J
  27.     BLED(OFF);            // 熄灭LED; v7 l- i4 u) I; z8 S' {; j
  28. " _4 y; `3 F5 ]( ?* ]8 G
  29.     SysTickDelay(1000);   // 延时CYCLE_1MS*1000=1s
    : a; h- g; I; |  S4 \% Q
  30. : Y6 X# W( O, C4 C1 z
  31. }
复制代码
5 ?7 M7 U: T% d2 U1 l- D

* o0 |& X; ?! e2 O# x" m6 w5行:初始化SysTick,这里传入CYCLE_1MS,则延时函数“SysTickDelay()”的单位为1毫秒;
& R, }. \! o9 U: g( N+ ^
5 R" S0 b4 I; b8 X5 D0 Y7~16行:初始化LED,调用延时函数“SysTickDelay()”,传入1000,则延时为1秒;
; B# R7 A* M" A. \4 e4 W1 z5 w( K
/ z: `+ v7 l! g# {8 i7 Q1 E+ \' A
0 V" E7 j1 x- i, G7 Z/ R2 d! T
7 g  l& g) X/ t% u11.4 实验效果
7 }9 Z4 |" D! R- [, X0 D  K
本实验对应配套资料的“5_程序源码\4_基础重点—SysTick定时器\”。打开工程后,编译,下载,可以看到蓝色LED灯间隔1秒,交替闪烁。读者可修改代码段 11.3.7 中的第5行时钟周期,或者13、15行的延时时间,改变LED灯的闪烁间隔时间。
; v# N  u/ j7 h% t. F7 ]5 O) M& M) l# r; [) Y3 e5 [
通过LED展示SysTick的延时结果不够严谨,有条件的读者可以使用示波器或逻辑分析仪,触碰LED灯焊盘的引脚,测试翻转时间,如图 11.4.1 所示,分别修改延时时间10us、1ms、1s后逻辑分析仪测量值。
0 R: c3 b' G  H6 ~4 h& l8 V7 |( s! n" k* h" x' V( u0 Y
X@5HN2ZMEBP{BBH3JG2[_IT.png : B5 S( F: ^- S/ X

% l+ J9 Z8 `, {+ F( p* L9 W! S图 11.4.1 逻辑分析仪测试SysTick延时 9 U# [1 T5 w" U: G; @8 @/ g
. A0 H! X. h) v+ K' F

5 i* O0 j& ^( U1 c$ v: H
收藏 评论0 发布时间:2022-4-27 23:04

举报

0个回答

所属标签

相似分享

官网相关资源

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