主要内容:! J F1 C/ y3 {% s& m% z
1) Systick定时器及相关寄存器;* u; X6 r! M8 D/ v J: {
2) Systick相关函数及延迟函数代码解读。: W4 v6 j0 Q* l0 m7 u' K8 E
3 A1 a! a2 v: f. }
1. Systick定时器是什么?
$ ~. W" A* I; R6 T# i6 N: ~1.1 Systick定时器,是一个简单的定时器,对于CM3,CM4内核芯片,都有Systick定时器;
6 V% Z8 F$ G, W8 a1.2 Systick定时器常用来做延时,或者实时系统的心跳时钟。这样可以节省MCU资源,不用浪费一个定时器;1 Q6 N) B; N" j/ G
1.3 Systick定时器就是系统滴答定时器,一个24 位的倒计数定时器,计到0 时,将从RELOAD 寄存器中自动重装载定时初值。只要不把它在SysTick 控制及状态寄存器中的使能位清除,就永不停息,在睡眠模式下也能工作;
3 u6 O$ z+ ^4 K0 c; K! b1.4 SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号:15);
* \5 g2 X& C9 o0 U1.5 Systick中断的优先级也可以设置。
+ I4 e0 C5 g7 ?# T0 Y5 Y. ~6 Z2. Systick相关寄存器
6 Z' @* O: F' Q( H2.1 CTRL(SysTick控制和状态寄存器)
: G* r# n; y' I4 y( V+ `
% ?7 {3 A% q3 x/ |" c
3 P) C6 C0 D8 y
! e% N, g. n4 p' x2 V! V8 U
1.1.1 对于STM32,外部时钟源是HCLK(AHB总线时钟)的1/8,内核时钟是HCLK时钟;
1 z3 C% ]; V) M6 v- Y1.1.2 配置函数:SysTick_CLKSourceConfig();3 v0 h' @7 c2 d- w4 [1 ?
2.2 LOAD(SysTick自动重装载除值寄存器)" p, g- e' I, r2 j5 J
& x# K w8 S1 w3 L
- p& v' c ~+ N. {! u
* Q, G9 O$ E/ M7 D2.3 VAL(SysTick 当前值寄存器)& w: S6 D/ J" t8 Z+ x
0 C. C; {& ]- _, _
) T& G$ O3 O( t( n
' d3 `8 |' l, \/ u, F/ r: J) s" d6 p/ {2.4 CALIB(SysTick 校准值寄存器)& Q8 ]) z, x; T
6 d5 C* M V1 L' R P: @
; ?7 X: X! O) X% r" T
& N# n0 y4 b! H( q: j+ _9 n1 w
2.4.1 校准值寄存器使系统即使在不同的CM3产品上运行,也能产生恒定的SysTick中断频率。最简单的作法就是:直接把TENMS的值写入重装载寄存器,这样一来,只要没突破系统极限,就能做到每10ms来一次 SysTick异常。如果需要其它的SysTick异常周期,则可以根据TENMS的值加以比例计算。只不过,在少数情况下,CM3芯片可能无法准确地提供TENMS的值(如,CM3的校准输入信号被拉低),所以为保险起见,最好在使用TENMS前检查器件的参考手册。
! k' M! u# \% _2 H% l [. l
4 S' E. z( h6 c& ?8 V" u8 y3. Systick库函数
# m3 Z# V2 [1 o$ {7 i' `$ M# z3.1 固件库中的Systick相关函数:
0 g* X6 i" b6 k: g2 T: J+ d" `3.1.19 E$ G1 `' R: K
- SysTick_CLKSourceConfig() //Systick时钟源选择(在misc.c文件中)//
复制代码
- i# O' J# F( g a( M7 d6 ]( w3.1.2 e% m( @. [8 U( W% H2 b) @* ^; ]
7 O3 f" D5 H2 d) R( T. h- SysTick_Config(uint32_t ticks) //初始化systick,时钟为HCLK,并开启中断(在core_cm3.h/core_cm4.h文件中)
复制代码 4 ]/ T5 J0 `2 Y' B% o, I
3.2 Systick中断服务函数:$ j3 U( p. @+ H v: k
3.2.1) K3 ?4 I; f F7 r G
- m& x9 e8 Y2 P( K Z7 b0 F
- void SysTick_Handler(void);
复制代码
/ Y3 l9 X8 C' O+ e; d* P6 D3.3 SysTick_CLKSourceConfig函数:' n# U8 b* x) b. `6 o
( d# {% D. i! o; p) }/ z$ i
- void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource) //该函数在misc.c文件中//
9 k6 b7 L% S; ?0 |. M, l* e - {7 Y, O* O( L& k% K# `" S+ _
- /*Check the parameters */+ K+ O$ u2 ^* Q9 [& q; j1 q
- assert_param(IS_SYSTICK_CLK_SOURCE(SysTick_CLKSource));6 R4 Y1 i e$ ?$ |
- if
m& T1 E5 B/ z }6 Y" h - (SysTick_CLKSource == SysTick_CLKSource_HCLK)2 B1 o. V: k1 i) F! M h
- { u2 j) G! _5 X8 H% b
- SysTick->CTRL |= SysTick_CLKSource_HCLK; /*SysTick_CLKSource_HCLK 为0x00000004*/
% E$ G8 _9 h/ U3 t/ y# k [ - }
n$ m/ b4 t! u5 G - Else- _& A" y u) ?" ^' J+ e2 n* E
- {- H; r1 O; k. a U5 h
- SysTick->CTRL &=) N, V; K6 c6 Y5 d6 h: E3 Q
- SysTick_CLKSource_HCLK_Div8; /* SysTick_CLKSource_HCLK_Div8为0xFFFFFFFB)*/2 R4 ~1 U4 v" d4 b
- }
! G& T/ D9 N* t* n7 M9 X6 | - }
复制代码 9 D( I N+ @8 j. S
3.4 SysTick_Config函数:9 U8 d1 o) v2 r. N: \- q& j( K
1 C) t- B, C1 M+ q$ X) W6 \! A6 i- /* @brief Initialize and start the SysTick counter and its interrupt.*/
2 r) o; H1 n: s - /* @param ticks number of ticks between two interrupts*/5 Y3 c9 P) T- U
- /* @return 1 = failed, 0 = successful*/ Z0 N1 Q/ f3 P7 F5 q$ P
- /* Initialise the system tick timer and its interrupt and start the system tick timer / counter in free running mode to generate periodical interrupts.*/! x: C: A+ ]. M2 x$ `
- static __INLINE uint32_t SysTick_Config(uint32_t ticks) //该文件位于core_cm3.h中,内核级别//
2 k3 W9 b# p- A1 ^. M2 P0 M$ ~( U - {
% x4 ? [. d! ?9 G - if (ticks >SysTick_LOAD_RELOAD_Msk) return(1); /* Reload value impossible */ : T% h- c6 a! M2 M5 _* D
- /*SysTick_LOAD_RELOAD_Pos 0;*/ 6 a2 H$ g Y1 }% f
- /*SysTick_LOAD_RELOAD_Msk (0xFFFFFFul<<SysTick_LOAD_RELOAD_Pos);*/
# v" L( E7 E; a! b: V# H7 @ - /*将SysTick_LOAD_RELOAD_Msk的值设为0xFFFFFF*/
J1 X8 Q* T2 t* M, j - /* set reload register */
2 T/ p# f- o2 \: \ - SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; 8 j5 P6 N" y2 n4 f; j7 _
- /*set Priority for Cortex-M0 System Interrupts */$ U$ I& h1 Q8 D& Y4 g0 x. n( L* x( R
- NVIC_SetPriority (SysTick_IRQn,(1<<__NVIC_PRIO_BITS) - 1); /*设置优先级,暂时不细讲*/
. y* |' E" f5 j3 \7 }: r - SysTick->VAL = 0; /* Load the SysTick Counter Value */) P: x. {& x/ G2 j" J
- SysTick->CTRL= SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk |SysTick_CTRL_ENABLE_Msk; " A2 J5 H |" l
- /* Enable SysTick IRQ and SysTick Timer */
0 T- D: ?) b0 H [8 ?$ I+ o3 _ - /*SysTick_CTRL_CLKSOURCE_Pos 2; */
1 R; n( K% c/ p. g9 g2 `* y9 p/ ^ - /*SysTick_CTRL_CLKSOURCE_Msk (1ul <<SysTick_CTRL_CLKSOURCE_Pos); */
$ m0 G5 k, b, L - /*SysTick_CTRL_TICKINT_Pos 1; */
, W3 n5 n4 u/ O- ]0 `- G c7 P - /*SysTick_CTRL_TICKINT_Msk (1ul<< SysTick_CTRL_TICKINT_Pos); */
* G; y/ d7 W5 i" I2 i- i - /*SysTick_CTRL_ENABLE_Pos 0; */* f$ U2 l5 ^; a6 g8 o. D
- /*SysTick_CTRL_ENABLE_Msk (1ul<< SysTick_CTRL_ENABLE_Pos); */
9 M. N7 Q' A! {& Z - return (0); /* Function successful */% t1 i. I5 a( J& f& K- f+ U
- }
复制代码 & |0 n, D5 w/ T& R, h8 z5 _; a
3.5 用中断的方式实现delay延时
" r! f) _2 A# G O- e8 Q; O; d
7 {1 O4 C& }: k* }7 M- static __IO uint32_t TimingDelay;8 o4 ^; `6 Z( D
- void Delay(__IO uint32_t nTime) /*申明Delay()函数*/
+ D+ @" k& R, O: A8 Q5 U; i% X: I4 g - {
6 O6 m1 D6 ?8 f6 Y* X2 T( o - TimingDelay = nTime; ! k$ c& C3 v) ~
- while(TimingDelay != 0);
+ K0 m# E/ @6 F8 n - }6 b) v; T9 J, }& Z" S
- void SysTick_Handler(void) /*申明SysTick_Handler()函数,作用每隔1ms运行该函数*/
4 T, f6 w9 ?! T$ y0 t - {
0 e/ }4 u& e0 W - if
/ A5 F" n. s4 ~# h3 q- t, ] - (TimingDelay != 0x00) /*如果TimingDelay不等于0*/
5 T$ |( R/ k" P p5 { - { e* X1 M8 h6 N) S) u9 q+ R
- TimingDelay--; /*则TimingDelay减1*/
, t" }* X$ h# _ - }
! a' V! I+ B8 M! Z! y) I - }, A3 d# W! u, N+ z$ R+ D* ~
- int main(void)
6 r) l( e! `4 U( b - { …
) u T6 d! U; P3 v+ c - if (SysTick_Config(SystemCoreClock/ 1000)) //systick时钟为HCLK,中断时间间隔1ms//9 C: T+ ^3 g- s0 A. d! h
- /*SysTick_Config()函数位于core_cm3.h中,请参考3.4小节,内核级别,若systick时钟选择为HCLK,不分频,则SystemCoreClock时钟频率为72MHz,因此SysTick_Config(72000),意思是以72MHz频率计数72000个ticks需要1ms*/6 X) a" ~' `7 L* g' h% @
- { & p. e- Z& c, {
- while (1);& B+ f Z* i. y2 _+ S
- }
2 F- H5 ?) L5 N. ], v - while(1)5 }& q3 n2 S! f) @9 k a
- {+ b. y$ N3 `2 I) q
- Delay(200); //延时200ms//& K. s! |3 E& y3 H# z8 m/ {
- …
3 M) u3 W7 u' @# W: V" a - }
) H$ e/ }1 ~* b* z* A: {( Y - }
复制代码
3 ]& M( `; e( G2 i0 ?+ D3.6 delay_init()函数解读:
/ W# k6 R |4 K3 h: n9 I7 p% h9 P/ N# r) W6 |; I% b
- void delay_init()$ c) A7 d) G9 V8 E( e4 G
- { C; Q S) e# I3 g& Q, ^1 v) T( F2 S
- //**#if SYSTEM_SUPPORT_OS**// //如果需要支持OS.//, u# S; J- _4 J7 r7 b; B
- //**u32 reload;**// ) R4 \& v8 L; H" p$ n$ u8 ]
- //**#endif**// 9 c7 z7 l% t+ r' d( x
- SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //选择外部时钟 HCLK/8//6 y8 y0 c$ w( F* f
- //**SysTick_CLKSource_HCLK_Div8为0xFFFFFFFB,选择外部时钟源的1/8,请参考3.3小节**//7 H F( I D" e7 p j& h9 n- S0 q% |7 E
- fac_us=SystemCoreClock/8000000; //为系统时钟的1/8//
1 Z8 ]8 E4 W: \" w; ^7 v9 @* R - //**SystemCoreClock时钟频率=HCLK=72MHz,SysTick时钟频率为9MHz,则1us时间内SysTick计数9次**//
% c9 |/ G6 U! a' ?- H* W - //**#if SYSTEM_SUPPORT_OS //如果需要支持OS.//
5 d. }7 X% u2 X3 F; _5 I - //** reload=SystemCoreClock/8000000; //每秒钟的计数次数 单位为M// 4 d& k1 D, [ M! B- R) U
- //** reload*=1000000/delay_ostickspersec; //根据delay_ostickspersec设定溢出时间//8 K. K+ ]0 f: f9 G: O; W- W h! e
- //reload为24位寄存器,最大值:16777216,在72M下,约合1.86s左右//
1 ]5 r9 `; i: _/ N) I0 C! } - //** fac_ms=1000/delay_ostickspersec; //代表OS可以延时的最少单位//
; e H. E* A. | - //** SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk; //开启SYSTICK中断//4 _2 o, m; _( y
- //** SysTick->LOAD=reload; //每1/delay_ostickspersec秒中断一次//
' x- v0 E. D- p' _$ G: t6 ^ - //** SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启SYSTICK// 1 b0 X7 } {6 J1 m1 i
- #else
f* i, f" u7 y% { - fac_ms=(u16)fac_us*1000; //非OS下,代表每个ms需要的systick时钟数//
; O7 O# Q+ y# {7 N( p ?. n& g - #endif
& P5 x0 X& ?" R7 I- a8 d - }
复制代码 9 U) Y8 v4 Z9 B; ^% D# G
3.7 void delay_us()函数解读:; r# x C; }% ^! a& D
" r* M& H. X ^! \/ ~+ b
- //延时nus,nus为要延时的us数. //
5 X/ Z! m$ [ M2 m Q6 R6 L/ |3 W% e - void delay_us(u32 nus)
2 l$ _$ T) P# }5 m+ I - { 0 E9 e N# ~! l$ E% M# x& x
- u32 temp; % ?* x% n: ~4 |1 e: g; f
- SysTick->LOAD=nus*fac_us; //时间加载//
4 j, n2 \8 h5 P" h5 w7 O: O* i; C7 @# U" D - SysTick->VAL=0x00; //清空计数器//
' n# O0 ]- @& Z) B2 {. C- G - SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //使能SysTick定时器//
; x& a. S/ I. z8 Q - /*SysTick_CTRL_ENABLE_Pos 0; */
3 G* g4 \+ H$ S, J - /*SysTick_CTRL_ENABLE_Msk (1ul<< SysTick_CTRL_ENABLE_Pos); */
4 C z) U6 _% M1 ^ - do
. {( A. m/ ^9 e. G% q( a+ f; `& C8 u - {
( j6 u0 `1 D& y" @! o - temp=SysTick->CTRL;5 ]2 c' {2 {* _' x5 N
- }while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达//
! t# w; _5 r0 s' m! x - //**temp为xxxx xxxx xxxx xxxx | xxxx xxxx xxxx xxx1,因此跟0x01与运算后,其值肯定不是0,而跟(1<<16)与运算后,不确定,若不为0,则说明COUNTFLAG值为1,经逻辑非运算符!后,值为0,则while(0),跳出循环。否则,while(1)**//
8 _" E( f! c6 |+ G J w - SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器//
& l4 G9 \% d. x# C# }( ~* Z, q - SysTick->VAL =0X00; //清空计数器//
! C6 s( b: v! Z6 Q4 l - }
. H$ @# O, \( [8 K' f' l" N4 |
复制代码 3 M) B# _; ?7 }
3.8 void delay_ms()函数解读:
2 ?6 `4 w& d1 R* ^& U1 T3 |: N2 d% w! T3 G4 j
- //延时nms//( A! u. {: k% m
- //SysTick->LOAD为24位寄存器,所以,最大延时为: nms<=0xffffff*8*1000/SYSCLK//. |8 _- Y" y. e
- //SYSCLK单位为Hz,nms单位为ms,对72M条件下,nms<=1864 //9 N# e3 g$ S3 D7 t4 e: E& F+ d# I
- void delay_ms(u16 nms)
# c9 p0 j0 F, M H - {
* @5 A# } f7 \$ J" O) k; { - u32 temp; ' ^) ~* M4 d$ L: I" y# K/ `; I
- SysTick->LOAD=(u32)nms*fac_ms; //时间加载(SysTick->LOAD为24bit)//7 d$ e- |9 E- Y/ E! ^4 U$ N4 V6 |
- SysTick->VAL =0x00; //清空计数器//- G) |( [1 ? C9 S& L; X1 g
- SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //使能SysTick定时器// 2 E/ p$ U1 M& M
- /*SysTick_CTRL_ENABLE_Pos 0; */
. d" \8 S$ J. I7 w/ X# g5 \ - /*SysTick_CTRL_ENABLE_Msk (1ul<< SysTick_CTRL_ENABLE_Pos); */
+ a2 e, K/ i) o6 r: [. } - do9 X7 d3 Q: t/ Y4 ]4 `$ K: Q- v' D
- {
( k% ?1 R( {: g8 p" W, y - temp=SysTick->CTRL;
- G, ^1 r4 n3 P6 t. t7 U - }while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达//
" w! o/ a8 i/ ^$ y* A - //**temp为xxxx xxxx xxxx xxxx | xxxx xxxx xxxx xxx1,因此跟0x01与运算后,其值肯定不是0,而跟(1<<16)与运算后,不确定,若不为0,则说明COUNTFLAG值为1,经逻辑非运算符!后,值为0,则while(0),跳出循环。否则,while(1)**//
$ N4 b( c3 j4 f; I6 O: Q1 E - SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器//
# Q8 X" V$ K% a3 O - SysTick->VAL =0X00; //清空计数器//
/ R8 Z2 x( G; [0 E2 P+ O5 w - } 7 L; ?% r/ e2 I. V
- #endif
复制代码 ; z$ ?+ V( b6 v
————————————————
9 u5 @5 P ^ i版权声明:天亮继续睡
3 ?- L! T r# l- @$ X& t7 ]% a8 H4 U2 n- b" E. J3 _
) ]/ C% N9 G/ b
|