主要内容:
7 V( ~- A) m# A* U: ~1) Systick定时器及相关寄存器;
5 p! F2 k. V* f0 c, _ `2) Systick相关函数及延迟函数代码解读。: g/ O& z8 `. y! y6 n
6 H& h* i: y, R i
1. Systick定时器是什么?# }0 a; d4 i% M( C( i* i; }
1.1 Systick定时器,是一个简单的定时器,对于CM3,CM4内核芯片,都有Systick定时器;$ t$ {1 W) b2 z9 S p [% w
1.2 Systick定时器常用来做延时,或者实时系统的心跳时钟。这样可以节省MCU资源,不用浪费一个定时器;
3 A: ?/ ~: ?4 b% d, o/ U/ X1.3 Systick定时器就是系统滴答定时器,一个24 位的倒计数定时器,计到0 时,将从RELOAD 寄存器中自动重装载定时初值。只要不把它在SysTick 控制及状态寄存器中的使能位清除,就永不停息,在睡眠模式下也能工作;
* F7 N6 W5 {( I5 |; l5 ~1.4 SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号:15);' J1 F$ W* q) z& c8 H
1.5 Systick中断的优先级也可以设置。6 A8 m( m3 N" ]% C7 V
2. Systick相关寄存器
2 x+ W* b' [, f2.1 CTRL(SysTick控制和状态寄存器)
7 z- X+ _3 Z7 R4 _ u
1 q4 e q! a N5 q* X# L" k
# p# V9 ]$ s. D' x# }
7 _/ v) ]3 I; Q. k( `' B1.1.1 对于STM32,外部时钟源是HCLK(AHB总线时钟)的1/8,内核时钟是HCLK时钟;6 J+ {2 ^0 e: K' w1 B6 Z& `, D
1.1.2 配置函数:SysTick_CLKSourceConfig();
9 ^* m( I; b, q7 L2.2 LOAD(SysTick自动重装载除值寄存器): ?1 [; E) _6 m. ?2 p) z
U. ~5 U+ E K, t3 {2 `
+ r; i) d9 |* C5 H4 v
- q3 y- F" n: e9 }/ Q2.3 VAL(SysTick 当前值寄存器)
+ ^9 i) }7 N; @: ^* P3 c+ e: g8 v4 j$ n$ Y9 Y$ x1 H5 K' x
4 q7 U2 G1 A4 k
, ^% e& d* z3 H) c
2.4 CALIB(SysTick 校准值寄存器), X4 V3 D6 ?4 l, {7 [7 }1 T5 P
* U0 q& H1 [: z. G
8 b* J2 [9 g' U9 G! i
) g a9 C% C# p* b$ u: ?/ B( P, v
2.4.1 校准值寄存器使系统即使在不同的CM3产品上运行,也能产生恒定的SysTick中断频率。最简单的作法就是:直接把TENMS的值写入重装载寄存器,这样一来,只要没突破系统极限,就能做到每10ms来一次 SysTick异常。如果需要其它的SysTick异常周期,则可以根据TENMS的值加以比例计算。只不过,在少数情况下,CM3芯片可能无法准确地提供TENMS的值(如,CM3的校准输入信号被拉低),所以为保险起见,最好在使用TENMS前检查器件的参考手册。
# O* P; T; M, K; a" H5 V9 m7 P; ^6 ^0 {/ U- o7 u0 N
3. Systick库函数7 D5 U! i W- J2 ?; r, Z1 m
3.1 固件库中的Systick相关函数:& G* J3 P* f, ?# a D; I
3.1.1; ?# X( u( ?7 |* P5 I/ |( r
- SysTick_CLKSourceConfig() //Systick时钟源选择(在misc.c文件中)//
复制代码 / z6 B9 E# `7 r8 L: G
3.1.2
9 Q1 c# P! V# j& |1 O2 `8 o4 W6 r! c& i" ]& Y
- SysTick_Config(uint32_t ticks) //初始化systick,时钟为HCLK,并开启中断(在core_cm3.h/core_cm4.h文件中)
复制代码 / { i3 _5 X( B) X! K7 d' M
3.2 Systick中断服务函数:; K% o; f% v& N+ s7 z, |
3.2.13 w) Z6 Q# C7 h8 e9 F
2 t Y7 k; T3 D r2 R9 \
- void SysTick_Handler(void);
复制代码 1 C9 k! h4 U) S# t/ O
3.3 SysTick_CLKSourceConfig函数:
3 g+ J' S7 g, q8 G( T
$ N$ M" M* T% z2 t+ `- void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource) //该函数在misc.c文件中//4 G" J* r+ p7 ], N) x
- {
7 s& b, w+ K: f r5 S& i - /*Check the parameters */
: ]1 a" @6 X+ S- p# d. m; x - assert_param(IS_SYSTICK_CLK_SOURCE(SysTick_CLKSource));: V- I( M5 f: u. i4 \7 B( F
- if
1 j3 X( o3 E# c2 |7 A - (SysTick_CLKSource == SysTick_CLKSource_HCLK)
8 x/ P1 x$ e* [ - {
8 o. V. |3 U5 Y - SysTick->CTRL |= SysTick_CLKSource_HCLK; /*SysTick_CLKSource_HCLK 为0x00000004*/
/ s* a) n" @5 y5 ` - }
/ o5 m; o% X8 d8 {. ^ - Else; F! L7 T8 [( T7 R1 M
- {/ d0 y; ?( ^- X3 @( v- g* K8 z
- SysTick->CTRL &=
" G( K$ f- u ^% v4 o, H2 q - SysTick_CLKSource_HCLK_Div8; /* SysTick_CLKSource_HCLK_Div8为0xFFFFFFFB)*// a, v0 K8 {" n Y4 V" L! `- H
- }
8 X$ B! T1 e3 F( S - }
复制代码
0 ~8 h. w( A6 |; p" n! ~; j) R3.4 SysTick_Config函数:
4 V& O; h, h: i' a& c5 A
7 R {% K2 {" D, L, ^- /* @brief Initialize and start the SysTick counter and its interrupt.*/
( z8 h+ T; _' W6 f: y' z - /* @param ticks number of ticks between two interrupts*/, X( N3 H7 i" Y0 z: x' O
- /* @return 1 = failed, 0 = successful*/, j! o3 c5 V3 {
- /* Initialise the system tick timer and its interrupt and start the system tick timer / counter in free running mode to generate periodical interrupts.*/3 X+ D, G0 C! T
- static __INLINE uint32_t SysTick_Config(uint32_t ticks) //该文件位于core_cm3.h中,内核级别//
- ~0 D! J9 y6 L- g2 Z* A7 Q1 z - { ) o: Z2 D9 H4 n6 `0 ?- {+ M
- if (ticks >SysTick_LOAD_RELOAD_Msk) return(1); /* Reload value impossible */
/ G; U+ f% s6 N& { - /*SysTick_LOAD_RELOAD_Pos 0;*/
: `7 B$ ?! F5 L& e - /*SysTick_LOAD_RELOAD_Msk (0xFFFFFFul<<SysTick_LOAD_RELOAD_Pos);*/9 X, M, W: P" Y3 Q, n" e
- /*将SysTick_LOAD_RELOAD_Msk的值设为0xFFFFFF*// v. k# F+ A! N5 ^
- /* set reload register */ & i( C) g3 U! N- L+ K, d& ?
- SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; ; |' O- F9 S2 A6 E' S/ g; Z
- /*set Priority for Cortex-M0 System Interrupts */
1 u0 _2 I0 U% x t5 ` - NVIC_SetPriority (SysTick_IRQn,(1<<__NVIC_PRIO_BITS) - 1); /*设置优先级,暂时不细讲*/8 ?; R2 z# E$ ^) l
- SysTick->VAL = 0; /* Load the SysTick Counter Value */6 a% e' t, @" D' ~1 u
- SysTick->CTRL= SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk |SysTick_CTRL_ENABLE_Msk; 9 C; v' I( j }. n) u' i
- /* Enable SysTick IRQ and SysTick Timer */
& l9 W1 C. p8 _5 Q - /*SysTick_CTRL_CLKSOURCE_Pos 2; */
8 @3 s& i) e% O5 ] u$ w, Z% U - /*SysTick_CTRL_CLKSOURCE_Msk (1ul <<SysTick_CTRL_CLKSOURCE_Pos); */
# J! n+ z- X" ?. [5 F' u# x9 n& a' ?; c - /*SysTick_CTRL_TICKINT_Pos 1; */
9 O, `6 y& X' n$ F: [, A( h s - /*SysTick_CTRL_TICKINT_Msk (1ul<< SysTick_CTRL_TICKINT_Pos); */
# \% c6 I4 x5 p2 r0 ^ - /*SysTick_CTRL_ENABLE_Pos 0; */
y4 \5 @% K9 [7 F. C - /*SysTick_CTRL_ENABLE_Msk (1ul<< SysTick_CTRL_ENABLE_Pos); */
- P' G3 h n2 b& i - return (0); /* Function successful */# i: }. q$ G/ x* Z
- }
复制代码 / a' v+ [5 o T% i, `! N8 M! m
3.5 用中断的方式实现delay延时6 Q" r- a% p; ~3 P8 y( Q
( `8 X2 |. F6 X- static __IO uint32_t TimingDelay;
0 L7 s" s; Y" F( W8 }( I - void Delay(__IO uint32_t nTime) /*申明Delay()函数*/
1 @. j$ L7 i; N - {
2 g* ^: l/ ~: p: u+ `8 r5 e4 ` - TimingDelay = nTime; 0 x! C) h! x; b4 z' }, b
- while(TimingDelay != 0);
t6 |7 i! B9 a! K - }9 A$ _1 u. T" F, {# ]! u- u
- void SysTick_Handler(void) /*申明SysTick_Handler()函数,作用每隔1ms运行该函数*/
9 j7 B* N3 _6 h" T* f0 S/ D - {/ @+ L' z8 Q8 D4 R7 Z
- if
3 S3 \9 b, |1 d - (TimingDelay != 0x00) /*如果TimingDelay不等于0*/
2 d( `6 ]6 u% G2 i6 S' L - {
+ U/ G2 G6 P/ K, u' r - TimingDelay--; /*则TimingDelay减1*/
5 n3 a9 g* y Z, R9 O3 O9 ~ - }
O8 i3 X9 g% ~ - }3 E3 }7 O7 H" o! ]& T4 ^. h
- int main(void)* N6 a6 T3 [3 L# r0 ?
- { …
6 H. B' a: K6 ^, h - if (SysTick_Config(SystemCoreClock/ 1000)) //systick时钟为HCLK,中断时间间隔1ms//
! V% a9 M/ S9 f$ n7 d, i - /*SysTick_Config()函数位于core_cm3.h中,请参考3.4小节,内核级别,若systick时钟选择为HCLK,不分频,则SystemCoreClock时钟频率为72MHz,因此SysTick_Config(72000),意思是以72MHz频率计数72000个ticks需要1ms*/( h3 f9 T, m" H
- {
4 T7 z3 V( ?0 k% k2 Q& L9 g* `+ f3 C - while (1);
2 q& d1 y7 t% N: T9 q0 ^ - } 3 h |1 R1 d _* F4 t& z
- while(1)6 b& c& g" W" R/ {
- {
5 H7 y! ^& A9 ^5 x1 ? - Delay(200); //延时200ms//! i7 M4 g% ?. l1 r
- …
4 }# k/ c; ~4 `# k+ Y, ^ - }1 Z( q9 t3 j1 M
- }
复制代码
5 L. @+ [% T; o, O5 X3.6 delay_init()函数解读:, E; X: S' F4 G) Q
" @6 l/ l, i" d2 l- void delay_init(), s! \- h! x+ C e' ~
- {" l& S& @0 X# A% f% U( B
- //**#if SYSTEM_SUPPORT_OS**// //如果需要支持OS.//: A5 a" k$ M- k$ @+ P0 w; t) C1 E( g
- //**u32 reload;**// ) w0 c% q* ]# y: J
- //**#endif**//
6 J$ G8 W0 D% g- X, Y4 x - SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //选择外部时钟 HCLK/8//! b; D% z0 D# R8 E
- //**SysTick_CLKSource_HCLK_Div8为0xFFFFFFFB,选择外部时钟源的1/8,请参考3.3小节**//8 Q! S2 n8 S. ~1 N* q- |6 C) @7 m
- fac_us=SystemCoreClock/8000000; //为系统时钟的1/8// $ O! D3 j$ v0 `9 f3 A8 M
- //**SystemCoreClock时钟频率=HCLK=72MHz,SysTick时钟频率为9MHz,则1us时间内SysTick计数9次**//
X& q* u/ P r q$ W6 ~! t& _ - //**#if SYSTEM_SUPPORT_OS //如果需要支持OS.//
2 o# Y% v& G n4 I5 m0 O7 g2 } - //** reload=SystemCoreClock/8000000; //每秒钟的计数次数 单位为M//
& C* L. T2 M: s- K - //** reload*=1000000/delay_ostickspersec; //根据delay_ostickspersec设定溢出时间//% L! P, o3 }' I' T
- //reload为24位寄存器,最大值:16777216,在72M下,约合1.86s左右//
# x6 L8 l6 _7 I - //** fac_ms=1000/delay_ostickspersec; //代表OS可以延时的最少单位// 3 p- D9 n; {3 I3 j6 _
- //** SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk; //开启SYSTICK中断//
; m {; k- ?9 b) \5 }5 e/ d - //** SysTick->LOAD=reload; //每1/delay_ostickspersec秒中断一次// 2 n: v& W }1 U& y; U0 W
- //** SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启SYSTICK//
$ ]( e1 r: f/ i _2 M& p& d - #else
) n) k& i) J! f$ i9 I3 M1 d - fac_ms=(u16)fac_us*1000; //非OS下,代表每个ms需要的systick时钟数//
: d) u( b- H! U$ O6 T6 A: a - #endif* _3 I: m" T" e
- }
复制代码 - _/ j; }- \4 r% C; P
3.7 void delay_us()函数解读:
! B1 e) r1 V# [; R& `2 L5 R7 B& Q$ i; `5 q$ c
- //延时nus,nus为要延时的us数. //
- p) }1 t: i% u A( E& N: o - void delay_us(u32 nus)
3 R' A% R' W& o% L$ l - {
, A6 x" o$ _2 n$ t0 Z; |- d6 ~% U - u32 temp;
# [, C3 h# h/ y& B9 O - SysTick->LOAD=nus*fac_us; //时间加载// 4 z+ `+ ]: w# j7 ]* h8 |' w. s
- SysTick->VAL=0x00; //清空计数器//6 d8 X0 {" R X# T, `. Z
- SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //使能SysTick定时器// & Q( |; u2 y! L. j5 g% {" D
- /*SysTick_CTRL_ENABLE_Pos 0; */% I1 w, K `& {* X
- /*SysTick_CTRL_ENABLE_Msk (1ul<< SysTick_CTRL_ENABLE_Pos); */
7 D7 `/ Y& I/ r7 k3 l: J - do
' ^1 }4 g: C- I& k* \ - {! z) D8 F0 d- x* N! _3 M5 ]
- temp=SysTick->CTRL;& f( ]# O6 K: C" z6 L/ I) W( Z- J
- }while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达// 5 z# Z. o$ Q! b: ` ?
- //**temp为xxxx xxxx xxxx xxxx | xxxx xxxx xxxx xxx1,因此跟0x01与运算后,其值肯定不是0,而跟(1<<16)与运算后,不确定,若不为0,则说明COUNTFLAG值为1,经逻辑非运算符!后,值为0,则while(0),跳出循环。否则,while(1)**//8 ?# S+ U, O% y3 j8 Y) [
- SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器/// ]1 Y- u2 c r' O- F- W
- SysTick->VAL =0X00; //清空计数器// ) b, R$ G. ?- W/ J9 h' ^4 ]
- }
! u' V2 P9 J2 B" g
复制代码
" ^/ P: Q+ k3 R; b4 z3.8 void delay_ms()函数解读:: u& t* l% |1 |! Q4 z: @/ M
9 ~4 \1 ^+ j. o: I- //延时nms//# A w }$ h7 p, c
- //SysTick->LOAD为24位寄存器,所以,最大延时为: nms<=0xffffff*8*1000/SYSCLK//
5 }6 L* ^5 Z) X3 S$ U7 f - //SYSCLK单位为Hz,nms单位为ms,对72M条件下,nms<=1864 //
9 W2 U; Y, l \* K6 ]6 ?5 j - void delay_ms(u16 nms): V M! K6 m( |! B
- {
7 f& }- u9 ~& T& o - u32 temp; # u& Q8 b1 P& k+ j9 Q' `
- SysTick->LOAD=(u32)nms*fac_ms; //时间加载(SysTick->LOAD为24bit)//
4 b! p. O1 I& D8 M6 r( N, u% N - SysTick->VAL =0x00; //清空计数器//3 }- {; A% i9 ^8 w4 C, O- W
- SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //使能SysTick定时器//
% i0 M) R0 f; q! w) |5 B - /*SysTick_CTRL_ENABLE_Pos 0; */
3 Q1 H, U7 \$ E0 z5 }/ G6 O - /*SysTick_CTRL_ENABLE_Msk (1ul<< SysTick_CTRL_ENABLE_Pos); */* z- J, p0 z6 z% P6 N1 K$ l
- do
. S9 S. H$ a3 B- a7 @; a - {
3 [3 J) [/ Y5 _& T: J1 U2 k# [; b - temp=SysTick->CTRL;2 p! w3 j5 z$ K/ v) `& _- ~. W6 Q
- }while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达// 5 s# v- s4 d( P' P
- //**temp为xxxx xxxx xxxx xxxx | xxxx xxxx xxxx xxx1,因此跟0x01与运算后,其值肯定不是0,而跟(1<<16)与运算后,不确定,若不为0,则说明COUNTFLAG值为1,经逻辑非运算符!后,值为0,则while(0),跳出循环。否则,while(1)**//
) n8 I% R* p) D" ~5 @+ q5 x - SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器//
# ~' v2 V# w1 f/ K+ t - SysTick->VAL =0X00; //清空计数器//
! }& l& n8 `) O% v# e' P. r4 } - }
# P. @7 V# W# v7 B! ^0 m" x - #endif
复制代码 ) Y& C3 E: h9 L0 {
————————————————4 `0 g3 e) N2 a. f
版权声明:天亮继续睡
1 R$ K/ G8 D. N+ c' }# n s% w/ `- T5 ?
( v! B& k" f( a- ^7 y) s, ] |