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

【经验分享】填坑-关于SysTick定时器

[复制链接]
STMCU小助手 发布时间:2021-9-28 10:00
文主要来填坑,更正之前文章的错误。也进一步加深了我对SysTick定时器的理解,希望对你有帮助。+ g2 [0 }/ Q/ p
8 X3 u3 E, @4 {) \

3 X9 x/ [% W7 e5 Z
01
坑的由来

: X* _/ v2 C. J

; z0 }# D+ k( K% |在之前的推文中《STM32延时的四种方法》介绍了使用查询定时器精确延时,使用的就是systick定时器,具体代码如下
' H: z* ^0 n* @0 k: w- Y, X# K$ F
  1. void delay_us(uint32_t nus)" s+ t1 y' V7 F: p8 y- k  P
  2. {6 b0 |7 r! R1 |! G% y; S
  3.   uint32_t temp;
    ; B; C, C- Z( @7 f: G
  4.   SysTick->LOAD = RCC_Clocks.HCLK_Frequency/1000000/8*nus;8 S2 H& \% D) [$ Z! w
  5.   SysTick->VAL=0X00;//清空计数器, l, J' y: Z) y8 ^5 w
  6.   SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源" Y+ h# @2 h- m% `; @6 q) s
  7.   do
    7 t  i5 A  v( P% I, o
  8.   {
    ' E$ }  W/ M: g& ?& P
  9.     temp=SysTick->CTRL;//读取当前倒计数值
    0 s( C8 h* M0 O( }6 }
  10.   }while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达3 f0 U( [3 X8 y& H- A' P
  11.   SysTick->CTRL=0x00; //关闭计数器
    $ B4 D: ?3 g3 [6 L4 {7 Y
  12.   SysTick->VAL =0X00; //清空计数器1 ^$ B0 D. F& N8 _& t! j3 q3 o
  13. }; o3 p- n% }7 g7 |
  14. void delay_ms(uint16_t nms)0 t' K1 c* F( Z* [
  15. {
    7 R2 t; C0 k- P" r
  16.   uint32_t temp;/ G7 {* \; B7 u/ Q. j! P  y
  17.   SysTick->LOAD = RCC_Clocks.HCLK_Frequency/1000/8*nms;5 `3 V  q( L8 w: O% v2 f$ e
  18.   SysTick->VAL=0X00;//清空计数器8 U) M2 r$ X  k0 }# Q
  19.   SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源
    : a' U, U0 n- v( D, v: c
  20.   do* W& s& A: M/ h7 f
  21.   {
    8 B: w  u& M/ E4 C7 ]8 S# V  e
  22.     temp=SysTick->CTRL;//读取当前倒计数值
    + {, U9 B/ z+ C8 q
  23.   }while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达
    3 L% K1 E$ h% B% J3 x7 J
  24.   SysTick->CTRL=0x00; //关闭计数器8 [; T. p$ e; ~" z- s$ D
  25.   SysTick->VAL =0X00; //清空计数器1 E" J" [- P1 i& W2 ~% N. h" G
  26. }
复制代码
对于《STM32延时的四种方法》文中所说的内容如下
. a5 q+ a1 u6 b- U
13.png

  ^7 \/ _2 a! G9 h" }6 E也就是下面代码中/8的原因。1 t) I  ?9 D) Q, W, }) m
# U! o3 A$ h9 {( R2 W
  1. SysTick->LOAD = RCC_Clocks.HCLK_Frequency/1000/8*nms;
复制代码
我对此深信不疑,并在STM32F207参考手册(RM0033)上找到“证据”。! A/ m4 F' [+ E
14.png
2 Y6 o5 o' j$ b
上图①处直接是8分频,而不像②出的1/2/4/8分频。所以我确信是SYSTICK的时钟固定为HCLK时钟的1/8。
: F/ q; u6 D. E6 }2 u2 x* E: \6 {- U# n8 B4 H" }
我在学习RTThread的时候,看到配置SysTick定制器代码如下" r/ D0 q/ V1 @. {" a( V  Y
3 [7 j" L5 J- {2 A# |

2 k& y1 J; f% `9 A. K; y( J  K5 T  _

3 e& h( h" Q, K6 `! U2 J5 D% B. c# o我心里一堆问号,STM32官方手册,明明写了SYSTICK的时钟固定为HCLK时钟的1/8。我使用示波器测量,RTThread的配置是没有问题,可以正常延时的。+ @+ J1 Q* J6 ^" l( }

- A( Z9 Q; g' J) o
02

( ?- A' G: B0 L" q
填坑
, x" t5 A( }; p) K

  |% r- U6 m% g6 {3 c

4 P  ]3 p9 ]5 K5 [3 J2 w7 o这个坑其实很简单,在《STM32延时的四种方法》也提到了,只是自己没有注意这个细节。- `, r0 n  e2 S) m4 @0 ~1 f
15.png
* [; E* I* C$ t8 D* S1 U, m* C4 U
位2置1,表示时钟频率为AHB,也就是默认的120000000Hz。
2 O, S+ \9 H# J7 c( u/ l* Z- p. X/ Q3 P3 i# N5 j# {

6 h% o/ ~, n% u- |) s位2清0,表示时钟频率为AHB/8,也就是120000000/8Hz。
* g! a3 F8 u+ e: O) B5 E( ?  b# P
: n; V$ G, B- k( z7 eRTThread配置为内部时钟
! W9 w9 A! I8 Z  _' W7 B3 q
16.png

1 T2 t) z% V+ h) O8 F9 A8 l之前的文章配置为外部时钟源( Z1 r+ f* A8 N" }
17.png
! D! s9 Q  ~/ g) b6 C) h  V
这个细节我没有留意,导致我看RTThread代码时有点懵逼。在这里我更正《STM32延时的四种方法》中的错误描述; Y7 w9 S! S* f8 q
18.png
$ z: a8 X# E. w  m
准确的描述是:% `: i4 b# w5 ]0 i  g# S

8 s, D; w1 Y% b( w& q; D/ {) H

# U) t) F/ H! Y1 W4 MSYSTICK的时钟可以为HCLK时钟的1分频或8分频,在这里我们选用外部时钟源120M,所以SYSTICK的时钟为(120/8)M。2 [. Z; n7 \! }, v$ s
! ]7 a( p, H# Y. s3 a3 b5 L

. m0 Y% K. @8 T7 o3 A: x特此更正。
' j: N2 k7 r$ t, _; h- w" e/ {+ ^
关于这点,STM32的标准外设库提供的SysTick_Config函数,也是使用内部时钟的9 r1 U8 i4 [9 ?, X; D) r
  1. /** \brief  System Tick Configuration7 o9 F: [( ]" `6 c, p/ u# j
  2. % {4 {' O0 G' S$ O
  3.     This function initialises the system tick timer and its interrupt and start the system tick timer.7 ?* H  ^0 o8 E  P8 f* ?! a
  4.     Counter is in free running mode to generate periodical interrupts.# E$ K2 {* h- Z1 \) b3 u

  5. ! G9 M1 M$ `" D  J0 e) s
  6.     \param [in]  ticks  Number of ticks between two interrupts
    ! {& j8 ~; V% Y, X: h6 T
  7.     \return          0  Function succeeded  @& `5 T/ u  S6 `( D
  8.     \return          1  Function failed
    % _+ S" R% y# g' j0 f  x& x6 K- B
  9. */
    ; \. z$ k+ m; f. G: g
  10. static __INLINE uint32_t SysTick_Config(uint32_t ticks). K" N  k3 ?1 o; Z( _4 I4 x" D# a
  11. {
    8 u; H. m: ]1 `2 y, V
  12.   if (ticks > SysTick_LOAD_RELOAD_Msk)  return (1);            /* Reload value impossible *// z+ }6 G* K4 ^  j+ A

  13. 1 [" O( ~* E9 o- w; S
  14.   SysTick->LOAD  = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;      /* set reload register */# D9 r1 u! _3 j# b! I. `* w/ I
  15.   NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  /* set Priority for Cortex-M0 System Interrupts */* [7 S5 e9 H+ O
  16.   SysTick->VAL   = 0;                                          /* Load the SysTick Counter Value */
    7 I! z9 u1 A3 C6 D. @
  17.   SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |* s( Z5 O3 g( O8 A; {0 U7 Y
  18.                    SysTick_CTRL_TICKINT_Msk   |
    , r, L% u# U. b' B6 F) u- U; z
  19.                    SysTick_CTRL_ENABLE_Msk;                    /* Enable SysTick IRQ and SysTick Timer */9 C6 R) e% N' e' h' f
  20.   return (0);                                                  /* Function successful */6 L6 s& B2 U. K8 g% ?! b
  21. }
复制代码
调用方法,产生1ms中断调用方法& O' C, J; |8 t% ?* b

! c1 W" [0 X: t# [
  1. SysTick_Config(SystemCoreClock / 1000);
复制代码

' T& `# }- {( L2 X' @0 K$ z+ f- U关于时钟源的选择,除了操作寄存器外,还有库函数可以选择。: n$ Q! A( h2 s% P. `9 o& a

  1. % g# Z4 N# ?8 v  Z; z* A+ a
  2. /**
    8 m. G  q9 @+ C8 X5 n
  3.   * @brief  Configures the SysTick clock source.) S1 [) F& o% ~6 o! ~0 j3 `
  4.   * @param  SysTick_CLKSource: specifies the SysTick clock source.
    $ C1 Y0 f2 w% E# f6 H( m
  5.   *   This parameter can be one of the following values:
    # D, k1 ^' B7 A( `
  6.   *     @arg SysTick_CLKSource_HCLK_Div8: AHB clock divided by 8 selected as SysTick clock source.
    ! n+ t; H7 u5 `$ A1 P  V4 z$ v4 n
  7.   *     @arg SysTick_CLKSource_HCLK: AHB clock selected as SysTick clock source.% p' f( _& x# ^- h8 ?: b8 V. V
  8.   * @retval None
    9 J: @. l5 K2 I
  9.   */  E5 F1 D0 T+ E2 L; R4 J0 O; [
  10. void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)' W' \. X# Q& l  }
  11. {
      c+ @0 n; T4 ]! c* k5 u" @
  12.   /* Check the parameters */5 n% `! f  c/ p) H; I( i1 Y
  13.   assert_param(IS_SYSTICK_CLK_SOURCE(SysTick_CLKSource));
    : b6 p9 d( D' R$ C  x% N/ m
  14.   if (SysTick_CLKSource == SysTick_CLKSource_HCLK)
    ( {* i/ d" n3 g, a# N1 I
  15.   {
    ' e0 v6 C. S' k  R+ Z; b" b
  16.     SysTick->CTRL |= SysTick_CLKSource_HCLK;
    $ c" ?; W1 k% ^: g3 k: q
  17.   }
    / c" H* s+ B5 v$ l5 e" R
  18.   else
    ) o  k- f' u4 ?
  19.   {. @5 v# h/ Z; e4 l" T# W, H$ z- I
  20.     SysTick->CTRL &= SysTick_CLKSource_HCLK_Div8;: T( u$ f7 j% \' Y  t
  21.   }
    - V9 S# }3 i4 k3 C, P* L" E
  22. }
复制代码
除上外,我找到了其他证据来说明,SYSTICK的时钟可以为HCLK时钟的1分频或8分频。
6 S. o3 H/ l2 o: O7 q8 I5 }0 _
19.png
, X/ P. O, ]$ z& b0 m7 L: T
在STM32CubeMx配置软件中,可以选择1分频或8分频。- Q. C1 M& D; U+ `  n
) z- k# A) ^, A; d. a
03
( L  G" A7 e4 \
修改代码验证
6 p7 W( c2 C& Z: R, H

1 C1 E% P3 R3 S( |$ [* j4 v

6 C; `, @' g; X5 s2 K: f5 v. C把《STM32延时的四种方法》文中涉及的代码修改成1分频的。% U( z. t- k- S' i: U) A! s

  l' h5 Z5 r7 {2 d; `6 n  n
  1. void delay_ms(uint16_t nms)
      c! J0 H# z( D! t7 }
  2. {
    & [. Y6 \5 G1 K+ W" g9 c
  3.   uint32_t temp;; }, V0 G: ]# O0 G  \: [& D
  4.   SysTick->LOAD = RCC_Clocks.HCLK_Frequency/1000*nms-1;3 P3 f( E6 ]" Z/ E$ l5 `& ~
  5.   SysTick->VAL=0X00;//清空计数器
    5 M" D1 W/ w' d
  6.   SysTick->CTRL=0X01;
      k2 R( r  c9 {' M2 p: d7 ]  _
  7.   SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);
    - \3 O) L" p7 L# v4 V, m
  8.   do
    & }/ ?  A# x, I3 P$ d9 \6 d
  9.   {
    % e: g; o8 E' z- B9 v- a- x' d: K. R
  10.     temp=SysTick->CTRL;//读取当前倒计数值
    0 q' m5 Q7 Q2 n+ ^! P* t
  11.   }while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达% N! z+ q. {( }+ p  B& b. X
  12.   SysTick->CTRL=0x00; //关闭计数器
    ! z- [# n6 n6 p, @4 O" i: W
  13.   SysTick->VAL =0X00; //清空计数器6 f" f* K& n1 f3 l4 D3 s' l
  14. }
复制代码
然后调用4 i+ T5 m( n2 v- A, h3 q9 \9 X
  1. % v# s( e0 s- V. _: H+ h
  2. GPIO_SetBits(GPIOE,GPIO_Pin_4);  //熄灭LED灯                     " K4 d+ f% _" ?% Y3 x, Y; V' b9 s0 {( r" y
  3. delay_ms(500);//延时500ms
    ) E' c/ L  `7 Y& |4 o
  4. GPIO_ResetBits(GPIOE,GPIO_Pin_4);//点亮LED灯                     0 I" @  a' |4 g: w/ }: q+ J# o
  5. delay_ms(500);//延时500ms
复制代码
就踩到另一个坑,延时不准。
0 {' w# z. O, K
6 R; ?9 v. r) a

/ e6 D$ `4 o5 [0 X/ I1 u+ L$ X原因是:此时SYSTICK时钟频率是120MHz的24位的倒计数定时器,也就是说一个周期,最多定时139.810125ms。不能延时500ms。0 m% \3 f3 q4 Z  L8 H
这里再更正之前的一个错误,如下图
0 c6 W' e& M! p: _2 `6 p& @
20.png

0 y7 C3 r% j2 E这个计数器的值,我们减去了1,这样才更准确。需要减1的具体原因在定时器讲解的文章中讲解过了,不明白的同学请看《STM32基础定时器讲解》。
- E# m+ U0 @- `7 l/ p: w$ e% Y0 C' C% S( R( G
04

1 [- m  C- x% g! p' g$ S# N1 @5 ]& g
总结

. o3 W1 {1 Q+ S. J* U( Q, d/ W- J, o1 L
2 g! N8 w2 k) z" ~
总结:STM32官方手册并不一定是准确的,要亲自做实验,自己动手验证。这是个老生常谈的问题,大家都知道,关键还在于实践。
  k! {/ u/ R! V& c
# M7 c' M8 Q+ _! Y& @9 n; Q4 h; I8 o* W, V
7 g9 p/ w/ j# q! Z* U: Y0 T
- C0 h% Z, z. |# e" P5 K- I7 C( N9 `

2 ~2 H7 c& l; p1 y: W7 }- }$ E# r1 |2 Z1 D# T7 J
赞 收藏 1 评论0 发布时间:2021-9-28 10:00

举报

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