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

【经验分享】STM32的Systick滴答定时器及延时函数编写(内附代码)

[复制链接]
STMCU小助手 发布时间:2022-5-18 21:00
一、Systick滴答定时器是什么?
. c9 I! b% F/ ~/ [& t) Z
+ l# A, V: G6 w' C7 T5 |    Systick定时器就是系统滴答定时器,一个24 位的倒计数定时器,计到0 时,将从RELOAD 寄存器中自动重装载定时初值。只要不把它在SysTick 控制及状态寄存器中的使能位清除,就永不停息,即使在睡眠模式下也能工作。) `4 D; W  y% ]1 S; g. C7 {8 M

* ?; S- y4 h3 {8 n! u' o3 E7 y  s  定时器既是在规定时间之后执行某个操作。1 G7 ]0 a* p4 x

% [" t( E( A2 W; o- d    Systick定时器常用来做延时,或者实时系统的心跳时钟。这样可以节省MCU资源,不用浪费一个定时器。比如UCOS中,分时复用,需要一个最小的时间戳,一般在STM32+UCOS系统中,都采用Systick做UCOS心跳时钟。  f8 i: ?$ h" p: O9 I

! b/ @$ @2 f) e' R$ c" W4 N二、Systick一般用来做延时,精确延时% e" w1 z5 Y4 O6 h( \6 J
) T2 J9 y) m8 \0 z
一共4个Systick寄存器
" y5 j4 ?$ e" c6 a: U1 D- o! e9 m) @2 O2 t
    CTRL             SysTick 控制和状态寄存器 . w9 ^, t0 h+ @5 ^: h
( A6 R. u7 a3 b5 m4 V! b) u. }
    LOAD             SysTick 自动重装载初值寄存器 6 B9 V$ _$ h# f" t  t+ P+ O7 _
& q7 k: ^7 x$ y0 d! \) f# I
    VAL              SysTick 当前值寄存器
/ M! S2 i, L1 w# ]" d; I9 |& L, q  [, a9 b; ?5 c
    CALIB            SysTick 校准值寄存器0 G. ]' ^! h5 D4 ~+ h' S
0 S- M# n$ M0 ?* B
三、systick定时器原理7 W* t1 F$ K9 `* |0 x) ~% d- j

) r- `- f) W7 ?) K6 i这个定时器是设置一个初值,然后这个初值减数到0,就是定时完成,完成之后可以产生中断,也可以不使用中断。( i- r- j  C+ M* z) ?  E
( T9 f+ X& x9 h
EZM`KG2081BWE(GB}VRW1YU.png % T0 @) ~4 H3 u: W# N& v/ p

! o$ i; T8 f; u第0位是使能位,可以使能或者使能定时器" ?9 m5 i+ D9 K' d. q! ^

+ U; K" `! g- t, I" n* N2 ?第1位是使能中断位,减数结束之后是否产生中断。/ l$ `* X& i: D4 I* R) W8 U

5 |( b( y" r; b第2位是时钟选择位,可以选择外部的或者内部时钟作为时钟源。
. x& K& h/ w$ d+ j0 q5 l
3 n7 s$ S/ M8 k& V7 N第16位是标志位,减数到0之后该位被置位1,读取过后自动清清零。/ ~. @- N+ f& s0 m- u$ k. i# g/ K
: f0 f$ v% D- u  E0 e4 s0 X
四、uSysTick 重装载数值寄存器-LOAD
1 Q, u+ c7 ^! H) h
6 J) C. A/ W! J6 b( ]" i/ p ICO9H2XKEDQJK}B@}KG{8VS.png
- d3 S& v6 `+ }7 W
. Z" f$ @# s3 D/ R. H1 q! S当当前值寄存器减数到0,自动会将把这个RELOAD的值赋给当前值寄存器。) |8 s+ K% P2 G0 k; t

6 S1 ~8 `4 T* V2 K- vif(VAL == 0); e; {" |! E* Q; @7 m7 `

+ T2 ~0 P1 `* g  j1 K; r    VAL = RELOAD0 f5 S3 o2 o4 L9 ^
# \1 N  H8 w/ o, o; |6 M$ l
五、SysTick 当前值寄存器- VAL5 b; @/ p! L$ o: s
. g" P/ I0 V5 w, m+ P$ x* r3 v* T
UFS`Z_@M4~9DKVW@2D9T2]5.png
3 Q- m, X3 n1 [7 g- E% P( c
) k0 y" I, H/ B/ a$ @# F$ eVAL就是从初值(RELOAD)一直减一,倒数到0的时候,重新将初值(RELOAD)赋给VAL。* _6 F0 T3 m' r% v( d. ~. w8 k/ S

" a! {4 Y' r& k: z* i" @2 x3 {  {% {六、滴答定时器的实现0 `, B! @2 B% b* V( T. A& M4 m& Y

, O2 _, X' N1 z" H: n/ B! E) u. z" z对于STM32,外部时钟源是HCLK(AHB总线时钟)的1/8内核时钟是HCLK时钟
; g6 m0 b' o* X" |# E9 j* g4 [1 a0 e. \  G3 z( [3 L8 V$ e
1、选择时钟源3 L; i6 _! e. Z8 Q8 D2 r
  _  h1 F/ j- U% R
    SysTick_CLKSourceConfig();//选择时钟源 misc.c文件中
* a  O& \; X5 K( ]8 G: e2 L0 O$ W! U9 ?, ?8 S4 ~: d
(]]A00RCAKI6Z0MN2P.png
5 t$ [8 G, Y, S+ _6 X, I% E$ v1 ~# l& m$ E) ?; [
    SysTick_Config(uint32_t ticks) //初始化systick,时钟为HCLK,并开启中断 core_cm4.h文件中
2 G1 ?( Q3 h4 \! l- A
" T" A+ [! z  Q) \3 Y 6]NZ4(S)@AQ(5GM($LD5YVK.png
- z  a* X. v8 P) v' z
  f. j) o6 p7 I2、编写延时函数
' [0 N6 t# L2 _# ?: F1 j& f$ \9 @- V  K) L3 I- g6 n& F
3、设置中断优先级分组) L& f! ~# e$ T+ T8 e6 F# z

9 D5 j* c! e9 W8 r  K5 |; c, Z    NVIC_PriorityGroupConfig( NVIC_PriorityGroup_2);3 a$ R, t- E+ ^0 O3 T# |; W
: C7 C" T: M  J
    一般使用中断都需要在最开始对我们的优先级进行分组,分好之后再进行优先级的设置。
  \: r! Z5 E$ k  d' R+ G
1 k0 D: Z+ @, K  i5 K( R  `    尽量不要在同一个程序里面频繁的改变分组,频繁切换分组可能会使程序出现不可预料错误。. y3 I) T+ ]- Y  R' x. F3 S
9 |! |' a& m2 ?2 d; m. Y
七、用中断的方式实现delay延时

2 Z/ \8 o- Y6 U# BSystick中断服务函数:void SysTick_Handler(void);
7 k; {" e3 Y$ A: l9 ^* t3 H+ S7 K0 Q3 E( v3 E8 X# y; F' p
2Z5JCHW%)M47(KDNRP3`8(L.png
* r$ a5 `9 ^8 A. H# s9 Q/ L% d& l0 X7 t6 I" R: N; ~- v, x
注意:5 \' l( k: {& E6 \4 e5 w- T5 K* p
$ S: Q0 p+ R' @, a% i- \: k
  uCortex-M系统中,Systick代码可以通用。6 d) n' p$ j" O! z

  g; E: }3 U1 ^  如果使用中发现延时不一致,问题一般都是因为不同内核时钟不一样而已。修改ticks值即可。
0 g% z1 V6 c8 e* r; ~1 F1 l  \' O2 k. a3 f7 j( F$ v
参考代码如下:1 k, G5 ?0 P4 L9 m

/ z+ W) f' U6 O8 ^- x/ u9 W
  1. void init_delay(void)
    * Z' T9 I. ]9 b6 Q- I: v1 j0 M5 R
  2. {
    7 L. @' R0 h" @- G7 [, M
  3.     /*我们外部晶振为8MHz,然后倍频到168M,那么Systick时钟即为21M,也就是Systick的计数器4 a# o/ c6 |$ W: e
  4.     VAL每减1就代表过了1/21us*/
    3 y: @9 g% ]* J

  5. & f# E' T. X+ G+ v( |$ p
  6.     //1.选择时钟源(选择外部时钟)
    3 j# g/ F  ~1 n+ p4 X+ \, L3 N
  7.     //外部时钟要/8,内部始终不用
    / c  b2 G. S/ n- N( }; o
  8.     SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
    6 v, v1 ]% J7 O/ c
  9. }3 U' d6 Y4 o' P
  10.   O3 O+ J% A8 m8 s* ?4 A( J
  11. //2.编写延时函数
    ' v& `- a9 P8 D. L( i2 }. Z. G
  12. //最大延时不超过798.915ms,即(2^24)/21/1000
    % g: E: w. F3 D% {, g, o, V$ x- p
  13. void delay_us(u32 nus): x1 i4 m8 q$ E$ g( C
  14. {
      u. H6 m9 G* _! K
  15.     u32 temp = 0;% E: M  W- g4 V, I2 @
  16. " l" i2 F7 w( c( c$ Z  Y
  17.     //1、实现1us*nus的延时
    3 m8 h# X, a" {$ {6 v" ?, h
  18.     //21外是外部时钟频率,如果选择内部时钟就是168M/8' ^* \' v/ M; d- Z1 `& a
  19.     SysTick->LOAD = 21*nus;//设置自动装载值为21(1us)) _  `2 _( @3 f3 d' d4 \
  20.     SysTick->VAL = 0x00;//设置当前初值为0! m0 I% a% K6 E
  21.     SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; // 开启(使能)计数:使能SysTick定时器$ p6 m. y. W. S& q# }4 ~2 z1 Z. I# l
  22. : X) @1 d% ^, R! v2 K
  23.     do3 b6 W- f8 E2 ~& h
  24.     {: b2 A! {# l, h3 O
  25.         //读取控制寄存器
    " W0 I! l0 h$ W( U$ m" S- q
  26.         temp = SysTick->CTRL;
    ; H. E3 l4 D, X7 e
  27.     }while(!(temp & (1<<16)));//等待计数时间到达(位16)$ a% l7 r1 r3 x5 w' W( n  c- g
  28. ( _. M; C1 A- A! n% B. ?- t4 I
  29.     SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; // 关闭(失能)计数
    $ w, t2 X* V6 S& `1 P
  30.     SysTick->VAL = 0x00;//再设置当前初值为0,重置VAL ' C4 @+ D9 h8 Q( _; I9 [3 I
  31. }
    ' Y/ s9 q5 z% ^8 z

  32. - t9 D. v5 }4 R9 y$ N( `3 p8 ?
  33. void delay_ms(u32 nms): F- D$ |( I6 i! \$ \8 S* L; j
  34. {+ T  c( D3 w6 C& D8 I+ F
  35.     u32 temp = 0;9 j% m# r$ t: l
  36. ( ~1 B) v( L& x* ]7 r
  37.     //1、实现1us*nus的延时4 N1 C+ d2 P3 f4 G
  38.     SysTick->LOAD = 21000*nms;//设置自动装载值为21(1us)8 F1 `' s/ M% s: o% F/ |1 M* W' P
  39.     SysTick->VAL = 0x00;//设置当前初值为0$ d4 @" l& t/ C7 N4 }* B
  40.     SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; // 开启(使能)计数
    - n# X3 Q8 r& v
  41. ) M* c, c: K6 A
  42.     do- J9 Q1 D% m5 X. g
  43.     {) L; a5 [6 q# U7 V0 s% A0 Z
  44.         //读取控制寄存器
    0 t/ s6 F7 o: V+ F7 S
  45.         temp = SysTick->CTRL;
    - e; @7 [' t& P# k
  46.     }while(!(temp & (1<<16)));$ K3 a) _$ B& ~0 z& l
  47. 6 M5 w- X2 j9 F+ P" O
  48.     SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; // 关闭(失能)计数
    , X  L$ b/ |8 n& N4 V- d
  49.     SysTick->VAL = 0x00;//再设置当前初值为0
    ' I& F/ Q# f. e  D
  50. }( b+ [& e( {/ Z% H/ H0 s
  51. % b4 o$ I) Q" Z# _: M$ Z* l8 Q+ _6 y
  52. void delay_s(u32 s)
    / J( }6 F: G3 y; Y
  53. {
    8 \2 w$ }- ~2 m5 Z1 J  h; `
  54.     while(s--)
    ) C( m3 M3 `# N$ r: i) a
  55.     {
    0 p8 Q' x; Q/ O) \9 d6 M2 l; v
  56.         delay_ms(500);: Z6 L, E, {* V" Q2 j9 E4 p  D  N
  57.         delay_ms(500);
    - P0 F0 F- b9 i- N7 r
  58.     }
    $ W) [, U. G* c8 e; P
  59. }
    2 o3 r( x7 B, [
  60. ! ~7 \! a9 H" S) t% P3 c" z& r
复制代码
) ~2 f" {: Q8 J  T+ Y) {
/ W: y& g( x) R. }) ^
: m% z! g  A, ]! J2 A
收藏 评论0 发布时间:2022-5-18 21:00

举报

0个回答

所属标签

相似分享

官网相关资源

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