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

【经验分享】STM32---系统滴答定时器(systick)应用

[复制链接]
STMCU小助手 发布时间:2022-5-24 10:21
1.systick介绍& \6 i! Z( `6 o: a1 V6 u

3 a# P/ @, q7 B6 M8 A: G! [5 K( @     Systick就是一个定时器而已,只是它放在了NVIC中,主要的目的是为了给操作系统提供一个硬件上的中断(号称滴答中断)。滴答中断?这里来简单地解释一下。操作系统进行运转的时候,也会有“心跳”。它会根据“心跳”的节拍来工作,把整个时间段分成很多小小的时间片,每个任务每次只能运行一个“时间片”的时间长度就得退出给别的任务运行,这样可以确保任何一个任务都不会霸占整个系统不放。或者把每个定时器周期的某个时间范围赐予特定的任务等,还有操作系统提供的各种定时功能,都与这个滴答定时器有关。因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器,以维持操作系统“心跳”的节律。 只要不把它在SysTick控制及状态寄存器中的使能位清除,就永不停息。
- p$ o( I9 |& a$ G) G7 E2 h8 E  S1 f' w
     知道systick在系统中的地位后,我们来了解systick的实现。这里只是举例说明systick的使用。它有四个寄存器,笔者把它列出来:
1 K6 F+ A* _4 S& a/ e0 U0 X: M
2 f$ O& f. e. v: a  m8 q: J7 g    SysTick->CTRL,        --控制和状态寄存器
- s! ^% s. b, N& y# Q4 z: Y
' L/ b- p$ C4 x    SysTick->LOAD,        --重装载寄存器# B& B* F7 l5 B. P4 S: N0 ]( K
, w3 k9 ]" b. T" s" E
    SysTick->VAL,          --当前值寄存器
1 D  c9 r4 d1 q1 W6 b: x; I! x: p1 K; `0 x
   SysTick->CALIB,        --校准值寄存器   
# L! }  U. C/ c, E7 R# d* f& G# E' i3 ~- g( L
1345388072_8448.jpg % U+ ~; p/ ^- z* S: O

/ q+ O9 f8 J( P$ Z* R/ E+ Q$ N; v 1345388045_7722.jpg
0 s" V; `2 p- k; Q: S; F1 M/ [& s2 w3 O  ^( g7 W. P2 a3 v
1345388109_7290.jpg , K' i: Y) m0 u; ^! c# c. V0 [1 l
" k4 W( j) I' v! g! J
1345388134_2995.jpg & @; ]( p' I: t8 z4 g; n( R

3 o. R7 {! l# H8 J+ H+ M7 c2.systick编程/ T+ p5 V8 H, V# N0 [- h& o7 s

: ?7 M# x* ^% W# _, l    现在我们想通过Systick定时器做一个精确的延迟函数,比如让LED精确延迟1秒钟闪亮一次。
' e' o  i! \  b2 s  Q' B' t- V
: }( Q% h  t2 }0 g6 c% q$ G    思路:利用systick定时器为递减计数器,设定初值并使能它后,它会每个1系统时钟周期计数器减,计数到 0时,SysTick计数器自动重装初值并继续计数,同时触发中断。
; U8 |2 Y9 y' z) e4 h1 N% C6 ]1 I1 s, u% U
那么每次计数器减到0,时间经过了:系统时钟周期 *计数器初值。我们使用72M作为系统时钟,那么每次计数器减1所用的时间是1/72M,计数器的初值如果是72000,那么每次计数器减到0,时间经过(1/72M)*72000= 0.001,即1ms。(简单理解:用72M的时钟频率,即1s计数72M=72000000次,那1ms计数72000次,所以计数值为72000)
+ r6 o- C9 x" j) ?; F' k4 l5 ~5 ~7 n% e% e% f4 o

- W4 i$ W  R" C6 @5 e. Z# {7 t. d8 @  d6 Y( Y
首先,我们需要有一个72M的systick系统时钟,那么,使用下面这个时钟OK就 !9 s5 H3 `# U, v; D. A5 Z
9 O5 R, C9 t' t' N( O
    SystemInit();+ J7 B3 ~$ I, h- o

) I3 ~0 a/ S0 \2 |: A    这个函数可以让主频运行到72M。可以把它作为systick的时钟源。9 \/ N# `1 x* L) v
' r! Y! g5 M3 m. B; f7 f% n7 T3 g
    接着开始配置systick,实际上配置systick的严格过程如下:
" k0 V, V* C5 h' }8 R1 J. X" ?  T$ D) h2 x/ Z- I- I4 _+ G
    1、调用SysTick_CounterCmd()       --失能SysTick计数器
/ V$ _* E0 Z4 L/ V5 p: o( T( Y& I4 G
    2、调用SysTick_ITConfig()          --失能SysTick中断
8 r7 \3 {& B) W: B
+ }8 K( O; Q: k+ c) f- w/ x    3、调用SysTick_CLKSourceConfig()  --设置SysTick时钟源。
. m- o3 O7 `5 n  A# {7 w' c5 a* O! a0 e  d. B) l* s+ ]8 v1 |
    4、调用SysTick_SetReload()         --设置SysTick重装载值。
  ^0 r% t8 \0 p# E2 k% V3 Q" J; g4 X9 E, a& x0 L5 \
    5、调用SysTick_ITConfig()          --使能SysTick中断7 s. r7 z+ l$ A: e
* k  w6 C2 m1 @1 L* A
    6、调用SysTick_CounterCmd()       --开启SysTick计数器                                                      
0 X( s; v7 r8 \5 A- ^0 G6 r$ p; s
6 P1 A: K" _- x) n" I# V    这里大家一定要注意,必须使得当前寄存器的值VAL等于0!
" c; u* Q3 @: i% j1 s1 J! |) X# p8 I
    SysTick->VAL  = (0x00);只有当VAL值为0时,计数器自动重载RELOAD。
2 i0 D# N0 {) q
) ~5 e" S: T. Z( B7 w接下来就可以直接调用Delay();函数进行延迟了。延迟函数的实现中,要注意的是,全局变量TimingDelay必须使用volatile,否则可能会被编译器优化。( |9 \1 Y$ x, `6 s

; }& b+ D( Y5 {8 L+ H9 {8 y" M下面我们来做一下程序分析:" T% y0 r7 j. c2 {
$ \, h5 K6 {. Y7 _9 N7 C% q9 W
(1)系统时钟进配置

0 J% J+ Y, U" R/ V( r, ?0 w& `/ G2 v3 p5 J# }. b* p% ^
首先我们对系统时钟进行了配置并且SetSysClock(void)函数使用72M作为系统时钟;
8 @1 g9 E" }: _2 r8 g* B, ~/ g  ]2 F9 ^9 Z* A* O
为了方面看清代码我选择截图:
  A: q2 ]) F$ i
5 X( q: m! I  P5 Z 1345388271_9008.jpg
; Q6 B0 _* g7 X4 t+ `4 b% Q
  X$ ?# n! w. x1 W0 `8 f 1345388291_8358.jpg
: O# [/ q- J# H$ ?9 Z3 F6 @
8 d8 v1 u! W5 r(2)先来看看主函数8 w- b! {: p7 ]' Q

* E6 ]8 X1 Z% k. E: N" J
  1. int main(void)
    5 b+ O9 z7 k4 F2 A, u1 D$ E5 D

  2. + M0 [9 G, @+ C( e5 r
  3. {            unsigned char i=0;
    9 M  k1 ~2 n) T5 ~: L. a. @7 d. g
  4. % z0 j! r8 g% o: n
  5.         unsigned char a[] = "abncdee";7 ]& p! S% i3 P$ t
  6. 5 W; d- a. X; {# q4 _

  7. 2 }5 k) M/ F- I7 a1 Q
  8. + G7 Z2 [( I) I6 @
  9.         SystemInit1();//系统初始化' U# V) w8 s3 K' d* S. z

  10. 1 f" K4 r) @+ a# J# G

  11. / K5 p3 {' |8 q+ D0 n1 L- Y4 f

  12. 3 A$ }1 m4 f& ?5 a8 S- U, P3 u
  13.        if (SysTick_Config(72000))  //1ms响应一次中断
    + s* a: \7 X, S/ n1 c% i) x6 R

  14. & |4 S+ V* N% Q" ~: j
  15.         { ( w% I: n: S) Q; d

  16. / J# c3 e8 _* s. b8 |
  17.             /* Capture error */) ~# x/ |( K) p2 ], M3 r
  18. 7 z+ j& ~# I$ G- d; `" h
  19.                  while (1);8 S4 `# s0 c4 I; r; V+ G, |: N- {
  20. : w  N8 P$ @: b7 Y3 F2 j' o# a1 d7 z
  21.         }
    2 |4 P2 b2 m- g% r* d' {" @
  22. * S2 S9 c: B9 U: l% S7 t6 X8 G
  23.         /*解析:因为要求是每500ms往中位机发数据一件事,所以放在while语句中,8 ]4 r& ?( R/ ?* q1 M9 G
  24. $ L% z1 r8 a( ]9 y2 Q
  25. *送据+延时可以完成相当于中断的效果;
    / S8 A/ K8 v5 l

  26. / k4 k4 H9 `! I9 w9 g4 l
  27.                *若是多任务中,其中一个任务需要中断,这把这个任务放在中断函数中调用;6 F# d& {% L/ c. X

  28. & ]5 N  B- @1 q& q
  29.                */
    # \0 A' l- v/ i3 F
  30. & Q0 x$ t$ l5 A4 j
  31.         while (1)% i3 @. @7 C5 |; Q3 o
  32. ; Y6 Q2 m# Y/ l+ @0 q+ L
  33.         {
    0 c+ N- g: N. B0 _, I
  34. % G6 Z& s) Z+ Y9 C
  35.              //测试代码:测试定时器功能,通过延时来测试8 J. j4 l' A6 a! M5 Q7 X
  36. : F# o( k  T  M$ ^2 J

  37. " X3 l2 r9 [0 a: X/ z9 z' H$ V

  38. % q( G, n  n4 ^/ k2 o
  39.              GPIO_SetBits(GPIOC, GPIO_Pin_6);      //V6
    - \) k+ C" E5 m
  40. 1 v$ c/ x+ C. R: a" `& B
  41.              Delay(50);& P6 @5 u+ Z2 j2 @

  42. 3 x& P1 v/ X$ P* j% M7 L
  43.              GPIO_ResetBits(GPIOC, GPIO_Pin_6);         //V6
    1 Y( ~" P! ]- }0 J4 @: M% ~

  44. ) Z2 {! Q4 [5 H+ ?+ [0 X( N  a" V
  45.              Delay(50);! X1 G$ F8 B4 h/ C/ p& A

  46. / I. \" b. f5 x  l6 y4 h) F

  47. : G  N  h. V2 f4 V, e
  48. 1 b" v% A& C* p1 ~
  49.             //功能1代码:每500ms发送数据
    ! L- ]+ {0 p' g
  50. " t; G9 O, J0 ?
  51.                /*
    % a+ ]; A& r- |2 h5 `- r
  52. ! a& E! H' Q3 C. L, j
  53.                       UART2_TX485_Puts("123450");
    ) V* `8 y$ n6 [# I! v5 x

  54. ! H# M! V: n$ ?/ n) H
  55.                       Delay(500);
    # M% h* w! o( c( @/ U, l: f
  56. 9 u6 _5 S! j$ _- `8 x- m/ M
  57.            */
    " n! }& m. G! r) z+ A$ l
  58. 0 y' b- J& l( g) y  W0 {
  59.             //功能2代码:上位发特定指令,中位机执行相应操作& a' S: ]% Z1 [3 \
  60. 0 M7 L9 I: g" i6 E) F" c, m2 y
  61.               //     RS485_Test();: K' O+ l  w- N5 j

  62. ' [- h  [- Q% A) V8 X: ^
  63.               }     . L& R9 r6 G/ ?! R5 g! X' R8 q

  64. " T2 y% A4 Y, @6 K
  65. }
复制代码

) U) u5 F& H- ]! v, s8 k$ r2 x7 P+ I9 h
(3)系统滴答定时器的配置--主角登场:1 e+ K7 y% A& O4 Z1 F0 p

+ `/ o. H0 W4 m4 {' g! i3 c$ m4 j2 F主函数中: SysTick_Config(72000) ;滴答定时器的参数是72000即计数72000
# L, J# i: ~  n9 f& P1 y  q
  W/ |* H* m* P$ u# ~$ l1 C( F) B(因为我们使用72M的时钟频率,即1s计数72M=72000000次,那1ms计数72000次,所以计数值为72000) ) E/ g/ R6 G5 Z. k, G
6 U% n5 ?5 M3 a0 X6 f
在文件Core_cm3.h中
/ C/ e# U) \5 U0 B( ], }2 U; B
7 S% R1 p1 z& E& B' ASysTick_Config函数的具体实现如下:, M& ?. ], p! W5 ~: T$ j% R% z
6 P9 N4 a8 N4 ?. m# Y0 \, t# ~
  1. static __INLINE uint32_t SysTick_Config(uint32_t ticks)% }) w. c3 K- D# ^- e2 P' u

  2. , w( }! u& Z' P0 R! i8 Z% K
  3. { ) n4 s! w& J1 f) O) u
  4. 4 l1 g* E7 e" y2 a
  5.     if (ticks>SYSTICK_MAXCOUNT)  6 s" F  Y$ ~3 e

  6. ) [, q9 R3 b) @0 ?2 @* u' F1 U& q
  7.      return (1);      /* Reload value impossible */+ m- n) C2 m. D% q/ T! n" |/ k
  8. 2 C7 g8 b  F0 E4 @4 t
  9.     SysTick->LOAD = (ticks & SYSTICK_MAXCOUNT) - 1;//systick重装载值寄存器   /* set reload register */
    3 A' h/ [' f! `# b' d) A) ~
  10. / v2 W0 d% ~1 o3 P
  11.     NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Cortex-M0 System Interrupts */
    3 L' f! v. H  z

  12. 4 i& ^) Q, g8 ]0 K0 S& k9 N4 P) ]
  13.     SysTick->VAL = (0x00);  //systick当前值寄存器                              . t& L! r" x- a2 r) G: x! G
  14. 6 e; r8 T2 K$ H' f4 v
  15.    /* Load the SysTick Counter Value */
    : N  e: J8 r" s4 a0 W' K; h
  16.    SysTick->CTRL = (1 << SYSTICK_CLKSOURCE) | (1<<SYSTICK_ENABLE) | (1<<SYSTICK_TICKINT);//使能IRQ(普通中断)和系器         return(0);      /* Function successful */5 ~) n) Q3 N+ N& g* P
  17. 6 J, v2 I) L: y- Z
  18. }         
复制代码
+ S8 c' z6 w5 O: @
                           
+ H% J" p) x" x" i  j我们来看一下这句代码:SysTick->CTRL = (1 << SYSTICK_CLKSOURCE) | (1<<SYSTICK_ENABLE) | (1<<SYSTICK_TICKINT); 这是使能IRQ(普通中断)和系统定时器,为什么要使能中断和系统定时器呢?" ]( E3 Y3 [7 p

0 Z. @0 _0 u* W( I下面我们来看一下stm32f10x_it.h文件中:
9 r$ ^6 E& z0 H; \6 ?: D
4 m& d7 m6 h( [0 _$ g8 u5 K  R找到滴答定时器中断函数:SysTickHandler()4 ]& B% E9 p2 T/ d. k/ t

. |4 i! m; t8 z4 l0 o7 Y, Vvoid SysTickHandler(void)
4 v6 V4 C. z0 T9 y- f7 I2 Q6 B. D$ _% T/ h
{3 s8 e2 E/ p5 S8 P# J9 l

. R1 k6 u; i7 I7 A    TimingDelay_Decrement();; C  X. g3 T3 i( Z$ I
6 w2 H: s+ l& F; G% D5 a/ \7 F
}
( ^+ h1 b7 F! U/ V
4 }1 K8 M# e- X* z2 h从上文我们通过装载的计数值72000知道每1ms发生一次中断,在中断函数中调用一个函数TimingDelay_Decrement();-----即每1ms发生中断时就调用到此函数;: T  V# h4 `' B0 f  G' b
" `5 Y' w5 o: S8 Z
下面我们来看看TimingDelay_Decrement();在干些什么?
/ z7 V7 z% N8 H  B) I3 T! c
3 s5 b2 C" A7 c4 \/ o# L
  1. /*****************************************************************
    4 ^& D4 T1 E. a% _

  2. : I7 s; [0 y* S& j" K. ]
  3. *函数名称:TimingDelay_Decrement
    8 Z" o' S8 F: B
  4. 9 V! @5 {3 H& ?5 P% g% n
  5. *功能描述:中断里调用此函数,即没发生一次中断,此函数被调用,此函数里     ( o. r: z+ l0 s- n  c5 o

  6. ; q. @9 x% E4 l
  7. *          的变量TimingDelay 相当于减法计数器
    1 u" W( F4 H( Y, v

  8. 0 Z( L: ^- b5 d6 C. x7 `" z
  9. *
    9 ~2 b0 P4 H) I' S3 |/ x- G

  10. . X" A: U' x8 K1 [3 a5 ]- Z
  11. *输入参数:无7 X+ x' _1 N: ^# U8 B$ h

  12. 7 _0 P# y4 }4 W- G2 g1 C
  13. *返回值:无. y9 I: ?' X% E" J& E4 o

  14. : q' _  v4 G2 \; q
  15. *其他说明:无
    # Z- y4 e/ S0 D
  16. ' d! Q* A5 b5 c
  17. *当前版本:v1.0
    + _& C- ?* ?' `/ t% |3 c( p
  18. ( p) S0 x3 O$ O6 L; ?
  19. *作    者: 梁尹宣  U4 M9 w. ~" e- G1 r9 A

  20. ; ~" C( q, f4 w7 E! S
  21. *完成日期:2012年8月3日
    6 L  U' h- w2 [+ @" E
  22. % T3 _, z2 c; O
  23. *修改日期      版本号      修改人      修改内容
    & t$ O/ ^1 Q1 \0 M" K

  24. & M& H0 h3 O4 N
  25. *-----------------------------------------------------------------
    / I! R' P1 j; A; n5 h5 f- u

  26. ' T  _( i0 w+ ~# C- ]+ n& i
  27. *  c1 X3 U' R( Y; s, ^! W
  28. ! }0 H: @0 z$ O2 Q6 N. ^) s
  29. ******************************************************************/
    + C2 g# M5 d+ r1 J4 F; W8 V

  30. 5 m7 U; g% O% ~4 R9 @2 q: s+ i
  31. 1 n3 \2 U. N3 e

  32. : `: H3 K4 X$ _' m
  33. void TimingDelay_Decrement(void)  * U; T/ ~8 F  ^4 C8 ~

  34. 9 f# k  g0 E+ D
  35. {  5 |2 H- f2 t( b3 X' ]
  36. 0 g& W7 q: y6 a! C; A- a/ x% \  D* e

  37. * u; W" S4 r6 a* \$ M

  38. 8 e% @& i8 H# U% O3 w9 q) Z: E; Q5 j
  39.   if (TimingDelay != 0x00)  7 x8 A3 n+ p; Z/ A" f5 L
  40. 9 Y, d2 W! g  t* f/ ]4 m
  41.   {   
    , \# H( _: P( |

  42. 0 I/ S: b0 {3 _0 D- `+ ]
  43.     TimingDelay--;  
    : h6 y2 y' s/ k2 {, A

  44. : }  S0 u/ i% m( q
  45.   }
    3 F/ w  @0 b& D9 O/ G& e
  46. 9 g9 Q3 I) ]4 a# s
  47. }  6 v6 C( B3 H4 n% B6 \/ r

  48.   u' S0 t3 ^1 D2 t
  49. 我们看了TimingDelay的定义,又看了还有哪些函数调用到这个变量,如下:
    " \% w3 N# b4 J

  50. 8 Z; ?/ O1 Z7 J9 s* O6 @
  51. /*****************************************************************
    0 ]  a$ o/ n- H& b# R# Y

  52. " N6 c0 c1 s0 p, ^4 u2 b- F! K2 Q
  53. *                                        全局变量
    5 y6 D+ N; G9 z% ~: ~
  54. : M8 H2 Y: O1 H) @
  55. ******************************************************************/
    " M3 u& `) D' n) D0 g2 M

  56.   u. V3 [- E  C+ B& u0 s3 ~
  57.   R7 @1 K3 G# }! \

  58. # O/ f2 q8 T2 o1 ?+ {
  59. static __IO uint32_t TimingDelay=0;& d& u* K* y. p& A9 J$ j

  60. 7 c3 W/ G, s0 R/ u* }# b
  61. 4 y3 R4 n. l/ x9 N3 U$ {& ?

  62. 4 }# m; O) t+ x( ?# Y! T9 W
  63. /*****************************************************************
    0 {& l8 A! @3 H2 ?, _+ y: d
  64. - y  _" b: Z$ _* Q
  65. *函数名称:    Delay
    : \% }8 l! ~4 @  ^! _7 j( }' k

  66. : d" D+ P' ]/ E- z( O& m8 d7 }4 k
  67. *功能描述:    利用系统时钟计数器递减达到延时功能
    ; _8 |+ T( ]# ]7 L5 j$ R  o
  68. 5 ^: a, `$ j' T7 `$ ^8 ?! I  i
  69. * . D+ F7 O. |) m
  70. / P$ E2 ?$ {5 K( o" U: u
  71. *输入参数:nTime :需要延的时毫秒数
    2 w8 q, ?- G/ |  r7 `2 ^2 X" p
  72. 7 `, X( B9 q9 w* f$ \6 Y0 _
  73. *返回值:无1 S# K8 S1 g/ d8 G7 `! p- X$ ~( q1 }+ `

  74. . z8 L0 X- G+ p- r. f) _
  75. *其他说明:无
    + k- [' F% q9 @; P  c
  76. & }+ Y; s0 r; f" N- i9 x, u
  77. *当前版本:v1.0
    1 `( c+ T) ?# ?; H" G0 {. P( @

  78.   g4 O' t* q8 w- u$ ^$ w
  79. *作    者: 梁尹宣
    9 p+ @0 N! M( k' R* C

  80. + l; K/ ~& h/ o: L* Q" U7 u- W
  81. *完成日期:2012年8月3日& U- c" L% g( r1 \1 b2 c# U: t  E
  82. * N$ u% I- Q* R( X# q% M
  83. *修改日期      版本号      修改人      修改内容; s; b2 @" m% M3 O
  84. ) t1 Y1 {5 [8 z; ^8 ~
  85. *-----------------------------------------------------------------+ |5 D$ k6 f! S

  86. & U( F3 V$ ?8 d, V
  87. *7 `- N5 [% B6 J- S. x

  88. 0 t6 `" e2 ?$ S, w8 A1 [6 A
  89. ******************************************************************/% @0 u1 e2 ~$ G& B( W

  90. $ F, ^  N$ B. k1 k" i" d) G5 G

  91. * G& c9 @7 a8 a) Q  o8 ]8 E

  92. ( _/ V6 C- c" a2 l
  93. void Delay(__IO uint32_t nTime)//delay被调用时,nTime=500
    9 `  O8 N& f7 i# e. Q
  94. : q6 k% b7 @+ ?& |# f
  95. { 2 d7 A( o+ h; J( h, f% ]

  96.   ?7 m) ]9 h/ X: l. H) g6 _
  97.   TimingDelay = nTime;
    ( X3 X5 z* y" i% D: ~1 K9 K( w5 V
  98. & n+ y4 s; G5 S4 h- I
  99. " [0 X1 ?& b- ?
  100. 1 f# E0 p  G8 I. F, k3 ]
  101.   while(TimingDelay != 0);
    + k: }# Q% Y' \
  102. 1 ~, ?& Q& U- U/ T& A, b
  103. }" w  b& I5 H7 y, Q
复制代码

( K2 x  E7 u, J8 f通过上面几个函数我们知道了,在调用Delay(500)即nTime=500;在后在Delay()函数中TimingDelay =nTime;(即TimingDelay=500是它的初始值),再TimingDelay_Decrement(void)函数的作用就是把TimingDelay- -;每毫秒进行递减直到减到0为止;这样就起到一个延时的作用;7 I7 f+ `5 F. X/ p9 e" g" d

; x& V- l. n" Y+ {现在我们做出来的Delay(1),就是1毫秒延迟。Delay(1000)就是1秒。
: u. c# U; P1 i1 x2 b4 Q- q; V
$ x* h. ~2 N) ^5 |  我们来画个图,方便这几个函数间关系的理解:
2 |9 |8 h' r# V$ u7 B. t! X  z  q) ]3 `7 I1 m8 r
1345388401_3109.jpg
. {# V/ ]6 K( J4 J: [( o, U; B) w& {* S, \  N7 F
我们在返回到主函数main()中看这几条语句:红色标注de
* H2 y! a8 t% _3 t7 m  J" @
# t0 F$ T; M8 z* E
  1. while (1)0 ~6 S& l! l7 A' g

  2. 2 o& f5 w1 `  G* i& h1 u7 v" U0 z
  3.         {
    0 \- t+ q. A2 e) k# Q) L7 [" e

  4. ) `4 e$ F; P: y# W9 L3 _* [
  5.              //测试代码:测试定时器功能,通过延时来测试6 \. R5 A9 Z, ~7 y/ ?  w9 p( G

  6. * M' S2 C6 B7 J/ h  D
  7.              GPIO_SetBits(GPIOC, GPIO_Pin_6);      //V6 4 ~3 J, n/ k- g  D! A0 D

  8. # c2 x; H! u7 o2 t5 {
  9.              Delay(500);- d+ b1 R  {$ w/ @& D( [( }
  10. # L2 P4 Q- r( k. m) M4 Z2 X
  11.              GPIO_ResetBits(GPIOC, GPIO_Pin_6);         //V6 . w2 T* L+ |5 M

  12. & p/ i5 i; S& v) e
  13.              Delay(500);
    3 O* F/ M' ^4 H) x8 N- M
  14. 3 I* i, X1 X& r. m

  15. " d+ u* _' ^# }8 N; P2 }
  16. ' k& B' l) M7 I* }4 ]% S
  17.             //功能1代码:每500ms发送数据
    % C! U7 e6 T2 `; [$ M
  18. * C" F, u+ `6 }2 h' m% e) \3 _/ J; _
  19.                /*/ y0 O, n* ^$ @1 z/ v$ L3 a6 [
  20. + `, {8 _1 O3 F$ e' ]
  21.                       UART2_TX485_Puts("123450");
    6 Z1 Y6 F/ |/ ]) E* L
  22. $ _' `% A9 \# o6 `
  23.                       Delay(500);
    0 @, {) b& v$ [+ J1 ^3 R

  24. - u; v& I* h$ k
  25.            */# C+ l2 Y" C) f4 f" P+ ^0 b9 |

  26. + R* D1 O+ Y  W7 S
  27.             //功能2代码:上位发特定指令,中位机执行相应操作
    # `/ p- w* X& P& R+ ~
  28. / V  ^3 X. Q$ v/ P& E) ^
  29.               //     RS485_Test();4 i# ?8 G$ @7 P. B/ e+ O# J
  30. 1 {! U! r0 _6 D5 z8 A, a
  31.               }     
复制代码
/ A  k5 m7 x6 x. n7 c$ @  X8 }
经过上面系统定时器的分析我们知道Delay(500);是延时500ms ;那么LED就是每隔500ms闪烁一次;5 a! Q5 ^& y4 j* c0 [- t
0 L5 B7 w( l9 ^  W1 P3 S
上面有关系统滴答定时器的应用讲解基本完毕!
: J. d5 u( \& k* Y
, t, e. [/ o7 u( y 有关SysTick编译后的源代码包,(其实客官细心的话一经发现上面代码含有485通讯代码,! M8 o/ @& ]& f2 Q( |/ p1 J' H

( H8 B& _) e9 }2 Z2 g. b6 ^( a  D! N
下面我们来看看一下参考资料的问题,一边对上面我写的博客有更深入的理解:
6 y0 s. t2 R2 L  E% n2 |& H3 g
) o5 ]9 t, @! }, t' f《Cortex-M3权威指南》
1 U/ P4 f/ |. ?' U& N; J
* I. A; r# Y2 e. K5 |; `7 C《Cortex-M3 Technical Reference Manual》+ T/ K6 z0 G7 e) K3 G+ n8 s" l# ~

' a+ L. q+ U3 L/ [2 v2 n+ l+ tQ:什么是SYSTick定时器?

- u: T' |9 g0 i
4 P6 E9 x3 S- P0 Z9 fSysTick 是一个24位的倒计数定时器,当计到0时,将从RELOAD寄存器中自动重装载定时初值。只要不把它在SysTick控制及状态寄存器中的使能位清除,就永不停息。
. \; c' h( D* o" Y$ ^( @% {2 X; @5 C, X2 n; w( D
Q:为什么要设置SysTick定时器?

, G5 y. o! e- }6 D9 D8 ^( x$ M$ J
, p/ E9 B, U. Y. \9 X& T( e(1)产生操作系统的时钟节拍
6 @' ?, l7 g, T2 P; A, q3 d+ E2 @6 M8 L9 Y1 g- O" Z; V4 G! j8 y
SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号:15)。在以前,大多操作系统需要一个硬件定时器来产生操作系统需要的滴答中断,作为整个系统的时基。因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器,以维持操作系统“心跳”的节律。
- Q3 Q9 R. H& e. X! d+ i; J% c- c
% z; a7 f' c4 ~5 Q; s, E(2)便于不同处理器之间程序移植。
8 d! F* i* |( [0 l) _  o: U
+ e. l+ t- A7 h2 a4 a' qCortex‐M3处理器内部包含了一个简单的定时器。因为所有的CM3芯片都带有这个定时器,软件在不同 CM3器件间的移植工作得以化简。该定时器的时钟源可以是内部时钟(FCLK,CM3上的自由运行时钟),或者是外部时钟( CM3处理器上的STCLK信号)。/ S" C$ ]% q; u0 l; J
  i( L7 |! d* _4 c
不过,STCLK的具体来源则由芯片设计者决定,因此不同产品之间的时钟频率可能会大不相同,你需要检视芯片的器件手册来决定选择什么作为时钟源。SysTick定时器能产生中断,CM3为它专门开出一个异常类型,并且在向量表中有它的一席之地。它使操作系统和其它系统软件在CM3器件间的移植变得简单多了,因为在所有CM3产品间对其处理都是相同的。
% m( `2 w: g' f0 r7 W; S8 o$ n& R, s' [. j% s
(3)作为一个闹铃测量时间。
8 a' {+ h/ W7 f7 Y7 R- r" C* ^1 ]3 Z7 u4 u4 j
SysTick定时器除了能服务于操作系统之外,还能用于其它目的:如作为一个闹铃,用于测量时间等。要注意的是,当处理器在调试期间被喊停(halt)时,则SysTick定时器亦将暂停运作。# L7 i& \+ ]1 `7 x2 Y! _
* |% y, n& w5 b4 b' N
Q:Systick如何运行?  l) ~: G0 A- e7 F' {, ~  o
; w5 N2 \& X8 q5 f( Z
首先设置计数器时钟源,CTRL->CLKSOURCE(控制寄存器)。设置重载值(RELOAD寄存器),清空计数寄存器VAL(就是下图的CURRENT)。置CTRL->ENABLE位开始计时。7 A0 r4 d: n8 N% Q  f

4 S5 ], A# c) F' j) }如果是中断则允许Systick中断,在中断例程中处理。如采用查询模式则不断读取控制寄存器的COUNTFLAG标志位,判断是否计时至零。或者采取下列一种方法
; F, T4 U( @. m  w" B  Z
0 J  T" F" y* P/ _: N* D* u  z当SysTick定时器从1计到0时,它将把COUNTFLAG位置位;而下述方法可以清零之:+ e; Z1 j. x% z( \' r  K6 ~* t7 r7 E
: O, @- g' }1 f4 D# h) T# I
1. 读取SysTick控制及状态寄存器(STCSR)
5 w+ l. @6 U7 a
% l0 {9 ~. h7 L+ m2 \8 @! z( r2. 往SysTick当前值寄存器(STCVR)中写任何数据
. r' t9 C, ]% @9 p; }/ w, a& V/ Y! c* D
只有当VAL值为0时,计数器自动重载RELOAD。
) i" H4 l, E: Y/ y0 K) S
! ?5 p+ ~/ ]5 a* ?Q:如何使用SysTicks作为系统时钟?
' U) O2 k9 T# \
: N- c% K$ W' h+ G( PSysTick 的最大使命,就是定期地产生异常请求,作为系统的时基。OS都需要这种“滴答”来推动任务和时间的管理。如欲使能SysTick异常,则把STCSR.TICKINT置位。另外,如果向量表被重定位到SRAM中,还需要为SysTick异常建立向量,提供其服务例程的入口地址。: `) N: @6 E% |
8 ]7 M7 T8 T* L$ E6 L6 s: x/ q
  V" c5 A. U7 @# x
收藏 评论0 发布时间:2022-5-24 10:21

举报

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