01. SysTick定时器概述
" J; w3 w9 ?. ~& a2 e# TSysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号:15)。在以前,大多操作系统需要一个硬件定时器来产生操作系统需要的滴答中断,作为整个系统的时基。例如,为多个任务许以不同数目的时间片,确保没有一个任务能霸占系统;或者把每个定时器周期的某个时间范围赐予特定的任务等,还有操作系统提供的各种定时功能,都与这个滴答定时器有关。因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器,以维持操作系统“心跳”的节律。: e0 j$ G, t- y* F# j
6 m% ~0 |4 [0 Y, Y1 X$ h5 @
Systick定时器就是系统滴答定时器,一个24 位的倒计数定时器,计到0 时,将从RELOAD 寄存器中自动重装载定时初值。只要不把它在SysTick 控制及状态寄存器中的使能位清除,就永不停息,即使在睡眠模式下也能工作。
3 C Z' j( q4 ~7 ?% H7 E! W7 E
2 U4 r U* H$ I# W" ] A7 O02. SysTick定时器寄存器描述
# p; g$ ]2 c/ F6 S( [& f0 T& ^SysTick控制及状态寄存器(地址:0xE000_E010)! M# f) I* q5 ^" a' W: }) g
8 {5 d! V9 q: ^1 e
: G+ O' W4 _: m9 V& Y0 R" Y6 t! k
$ }! |. d1 a# `) T8 V8 N4 _SysTick重装载数值寄存器(地址:0xE000_E014); v0 c8 L0 w! T4 O. ?
/ [) E# n5 M( W
% m* V' _" o$ S" G
: h$ M8 E2 J. W
SysTick当前数值寄存器(地址:0xE000_E018)
) ?, o- J. j4 U, [- _0 o. P% }
7 |8 |( F0 s2 i) p3 _) l9 p7 X0 X7 r
2 Y4 _7 Q3 ~- v9 s) ?& m8 I7 j( o6 I* B+ U! E$ G
SysTick校准数值寄存器(地址:0xE000_E01C)
* n8 \/ n4 j2 z. i$ R
0 _# q# U+ u p$ c( O/ D8 A4 P! J
5 I( |: r5 N |) F4 G3 _% F
- _# w4 z. [" w2 ], u* d
03. 相关函数实现" J, F" ~5 d% m9 `" u9 B+ p4 ^
core_cm4.h文件& o% R+ Y/ f# d
2 S# j4 ^3 ]6 s/ a: C
- /** \brief System Tick Configuration3 k& n, h1 b0 h7 L' _ C7 U
" `4 q7 f* v) I1 w4 f3 ]' S- The function initializes the System Timer and its interrupt, and starts the System Tick Timer.& i! Q0 j* H. ^& ^9 n
- Counter is in free running mode to generate periodic interrupts.
3 A/ G, N/ g( e& s, n6 Z
7 H1 m4 d6 T- U4 X* }; a6 [* F9 |& ~- \param [in] ticks Number of ticks between two interrupts.
K: O2 u0 ^4 T2 d* w - # ^( D% C0 @$ V' }: |
- \return 0 Function succeeded.
! u2 h) \% S( `% D - \return 1 Function failed.
+ b4 K% D. a0 p7 i' Y0 B1 w
2 l& I( y) U2 T; t- \note When the variable <b>__Vendor_SysTickConfig</b> is set to 1, then the
8 ]# ]# K6 Y% ~ - function <b>SysTick_Config</b> is not included. In this case, the file <b><i>device</i>.h</b>+ [) _2 Y3 c3 E, n+ I
- must contain a vendor-specific implementation of this function.5 {1 s8 y7 i" F1 h
, G3 C ?" s. m% b- */3 d+ Y$ w5 \+ @, A
- __STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
* S8 x( h$ c) j) ] - {+ N F8 u% l8 A
- if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) { return (1UL); } /* Reload value impossible */1 k: d: ]/ S+ v/ {
- " v: q2 @" B) U3 W$ N2 M. \1 ?
- SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */; l. Q* }! U0 w' M7 x
- NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */9 Q3 j/ Y2 Z4 \$ m- q" I8 X
- SysTick->VAL = 0UL; /* Load the SysTick Counter Value */0 q2 d8 g; W( f" O+ `* s
- SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |, x+ T; b8 v) d3 \
- SysTick_CTRL_TICKINT_Msk |/ Y' B# W9 ~( n1 X+ _
- SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
" x1 |" g' g& {; R - return (0UL); /* Function successful */- J* d; p0 f/ P( u; j$ @- M
- }
复制代码
# A1 x' G( u" C: Zmisc.c文件
8 v# t1 P( i, L- `% @: _3 t F- o/ R2 b& A+ g
- /**( B9 i( a: t! l |4 f- Q* y6 M0 s
- * @brief Configures the SysTick clock source.
! _+ y4 e1 @$ @) e* a0 Y - * @param SysTick_CLKSource: specifies the SysTick clock source.5 v$ K/ E5 k9 u
- * This parameter can be one of the following values:* m1 C3 K/ K& \: ~: b* K" v
- * @arg SysTick_CLKSource_HCLK_Div8: AHB clock divided by 8 selected as SysTick clock source.) O. t' B0 b8 \" m- ?; I3 r
- * @arg SysTick_CLKSource_HCLK: AHB clock selected as SysTick clock source., N* y+ j6 B/ G4 K
- * @retval None
4 W- s7 D$ A6 ^! w' _ - */! T7 T2 s R' B" H: D- a( b4 g
- void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)4 R9 C* [& Y: k/ u
- {$ R7 `# _3 ]/ O. Z, `4 A( j
- /* Check the parameters */
* I3 k0 ` e0 J - assert_param(IS_SYSTICK_CLK_SOURCE(SysTick_CLKSource));# w9 n& {& a( ]& S0 R' \0 E+ Z/ ?* z
- if (SysTick_CLKSource == SysTick_CLKSource_HCLK)
! O5 g) F6 K% P5 V$ p: q2 A - {" S; M4 A) R! d- N6 k0 B" r
- SysTick->CTRL |= SysTick_CLKSource_HCLK;
% L3 V( b9 S- D. N. C - }
W/ A, F, C! K' ]+ A6 ~/ m - else
3 q* Z& n) I0 v& G - {8 W$ F0 A4 k7 N9 d9 y- N
- SysTick->CTRL &= SysTick_CLKSource_HCLK_Div8;0 C( d! N; a9 c) j
- }/ j1 t1 s& [/ B/ N! l
- }
复制代码 : c: e" U" _3 A3 o
04. 延时函数实现. Y) Q9 Y& D' n8 [
delay.h文件
" O& u& S) t8 ~ }1 L( I2 k) M: c; }3 |8 }; w) l
- #ifndef __DELAY_H' a# ]8 b6 P; N; Z
- #define __DELAY_H # `# }# q# p* r0 E% b
- #include <sys.h>
$ [0 x2 ^. o" p% Y a - & R/ [8 @6 V- I: ^5 L; ]' h7 c
- void delay_init(u8 SYSCLK);. W4 j. F! O3 q, k2 q$ I
- void delay_ms(u16 nms);& G: r Q( g' Z' p( A
- void delay_us(u32 nus);' m- \ f9 r$ t; h3 ] M4 V. _
" s2 H5 D5 S, M( K- #endif
复制代码
2 D# B1 ~# o& u' G6 [9 odelay.c文件) q1 t" j# H' _9 L
+ t4 p! w) t9 I/ e( \5 @
- static u8 fac_us=0; //us延时倍乘数 3 o2 @% E& f7 B7 g
- static u16 fac_ms=0; //ms延时倍乘数,在os下,代表每个节拍的ms数
0 |; ]/ [( T t- X: n0 L/ b
# H+ |. x1 h5 [; b# f- //初始化延迟函数2 z# s9 {0 o3 K4 C! j6 ]
- //当使用OS的时候,此函数会初始化OS的时钟节拍4 i$ u) s3 A1 h: n
- //SYSTICK的时钟固定为AHB时钟的1/8
! B% w7 b P) n" t$ ]' y# L0 r - //SYSCLK:系统时钟频率
& w% e, \& ^! z" a# W5 g- F% p8 r - void delay_init(u8 SYSCLK)
6 Q9 q4 j# W! y8 r# N) }% j - {
5 C/ ]2 V* w: F
0 c1 B4 u# |6 P, x9 v" E: J* C- SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
: ?- m- `0 c: ]2 N - fac_us=SYSCLK/8; //不论是否使用OS,fac_us都需要使用7 t& p% H% ~% g/ {& P
% Q1 l- N6 {' E4 L- |- fac_ms=(u16)fac_us*1000; //非OS下,代表每个ms需要的systick时钟数 0 e$ h( f( y! v- I0 M" w
- } $ o8 c% Y: X4 k. v8 Y2 O
8 j" x3 w- {, c6 [, X- //延时nus
- {1 C! `0 E# |4 g6 z- n - //nus为要延时的us数. 4 {8 m- r1 o0 O1 m2 D, }
- //注意:nus的值,不要大于798915us(最大值即2^24/fac_us@fac_us=21)$ m; d8 ~$ D: E s# o( c1 @
- void delay_us(u32 nus)
/ ~: X! w- ^! |& r4 {: Q4 @9 Z% P - { / w. a. I- j* B" o
- u32 temp; % M. ~( m0 W7 t @' @. @
- SysTick->LOAD=nus*fac_us; //时间加载
7 r( [* _' k% y) P - SysTick->VAL=0x00; //清空计数器 h" Y* z: n" z* U3 Z
- SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数 : X$ i" m8 K2 i, \1 \. D
- do2 V: l/ `& o1 T
- {# R* ~0 h5 C" o" c$ A i# ?4 S* _
- temp=SysTick->CTRL;8 {! |: K7 `1 N8 L8 |9 \
- }while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达 ; O6 U# u p! `+ W$ V
- SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器
6 B: C+ P2 J8 W D1 U: H - SysTick->VAL =0X00; //清空计数器 4 k! t1 U' ?; g1 T, I- X
- }: b! y4 ^. X7 q% C7 g% H% Y
. C8 S$ @, ]: G' p2 P v* s5 `- //延时nms
. p/ r' M( C8 ?. Y1 @" Q! U" x - //注意nms的范围* S$ T7 p9 v- d6 _( W' _
- //SysTick->LOAD为24位寄存器,所以,最大延时为:
# o# l: b' ?+ e9 _& T6 z - //nms<=0xffffff*8*1000/SYSCLK( M" ^/ p, h4 E. b
- //SYSCLK单位为Hz,nms单位为ms
% \! N, D. A6 s# A; A6 j8 v - //对168M条件下,nms<=798ms $ ~' |2 A' m2 j& ?$ |/ O2 T5 L& t
- void delay_xms(u16 nms)
7 I* p$ o+ s. {! g - { 3 Z+ K% C1 ?' n) G
- u32 temp;
5 Q0 h9 ^, V2 U$ a - SysTick->LOAD=(u32)nms*fac_ms; //时间加载(SysTick->LOAD为24bit)
( J/ S$ a, e+ _) }7 o; t - SysTick->VAL =0x00; //清空计数器! f! v) S' A; J
- SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数
4 t5 `- U, X5 C' f7 c9 y) V# e6 {( o - do
7 a3 D$ a0 m0 o5 p7 z3 }2 o6 P; f6 F* d - {
& \9 P+ e: c5 I4 H. E# p- ~, C3 o - temp=SysTick->CTRL;' Z% j/ y( a! @1 r
- }while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达
, t" p j0 L" i# y; K - SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器3 k* g$ M9 A& d: F" e
- SysTick->VAL =0X00; //清空计数器
0 a( E. n" S) _5 M( a3 V - } 6 i! [8 E D% i# U
U( }5 {+ q0 k% w" i2 I. O# Z9 M: F- //延时nms 4 U% u0 j$ u5 s' K$ G) {8 M1 `2 k
- //nms:0~65535
5 v+ V& w0 p( t% R6 N( L$ I+ h - void delay_ms(u16 nms)( |* X* S6 ^7 P, W: B, N
- {
; a9 X% ^; K9 }9 Z" @0 z8 p5 w - u8 repeat=nms/540; //这里用540,是考虑到某些客户可能超频使用,+ N/ F) Y* N9 A
- //比如超频到248M的时候,delay_xms最大只能延时541ms左右了
$ C$ \" w( P& X+ v; R1 J4 K4 P - u16 remain=nms%540;7 _! Z* Q6 @4 a) I9 X( Q
- while(repeat)" h c9 X* }0 u0 u7 x: z
- {% i( M8 ^3 K2 ~2 Z% s& q/ j
- delay_xms(540); {) D/ j# ^( ^. n2 ~6 `
- repeat--;- x7 k" ]8 ^; k/ X8 ]$ _
- }
: W, I! i" h% O - if(remain)delay_xms(remain);2 A4 c4 T7 Z9 \
- }
复制代码 ~" Z$ E' l( F3 F9 R( `
05. 应用示例& V" P( p+ q: L8 j" O0 q
用中断的方式实现delay延时7 m }- e: X- T% D
+ @4 P/ m8 ]/ M3 O
- static __IO uint32_t TimingDelay;: A" h5 @+ K0 n. \7 G
- void Delay(__IO uint32_t nTime)
/ L+ X3 R H3 o. A& G [ - { & m' ^( s1 J0 e/ z
- TimingDelay = nTime;6 X$ T0 I1 q9 y8 l1 Z5 p+ v
- while(TimingDelay != 0);' Y( S- v" @7 N6 `2 M; j
- }
" U/ m% Z- p8 d0 x - void SysTick_Handler(void)
: z! e+ o1 m4 ?( Z( u; n. v. w4 X - {
/ \2 M* q& V$ Z" V: K7 r1 } - if (TimingDelay != 0x00) 0 `- H5 U# T9 \, w
- {
8 a5 _% A# j ?. _# p. q3 e - TimingDelay--;
8 Z; m. @4 e) a0 h; O- h0 y8 Z - }
8 S. X* K5 A' W# b - }
$ G) a3 ~+ f+ N! V* M2 n - int main(void)
1 x% b2 X0 V2 [/ h+ K& R" ] - { …- |$ z% J, D$ O1 t+ K5 r, m
- if (SysTick_Config(SystemCoreClock / 1000)) //systick时钟为HCLK,中断时间间隔1ms; j2 Q) U/ T1 d
- {# i- l8 I* J7 C: C$ Z
- while (1);6 O$ F" e1 _6 A; `( x+ j
- }7 F9 Q9 g$ ~4 N) Z R
- while(1)
! @$ p) G' S, h4 Z3 M. j5 B - { Delay(200);//2ms Z) ?1 J: s' o% w6 G
- … ! A* K( [$ ]8 @; P7 E
- }6 L# S1 a9 E& N" ?* r
- }
复制代码
6 N* ~, i, t$ R. E1 `6 K) Q4 n3 m; _/ v* @( N2 `
/ @( S5 [# k; W+ i6 }
|