SysTick定时器1 D( k8 |& a' u, m0 T
SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号:15)。在以前,大多操作系统需要一个硬件定时器来产生操作系统需要的滴答中断,作为整个系统的时基。例如,为多个任务许以不同数目的时间片,确保没有一个任务能霸占系统;或者把每个定时器周期的某个时间范围赐予特定的任务等,还有操作系统提供的各种定时功能,都与这个滴答定时器有关。因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器,以维持操作系统“心跳”的节律。Cortex‐M3处理器内部包含了一个简单的定时器。因为所有的CM3芯片都带有这个定时器,软件在不同CM3器件间的移植工作得以化简。该定时器的时钟源可以是内部时钟(FCLK,CM3上的自由运行时钟),或者是外部时钟( CM3处理器上的STCLK信号)。不过,STCLK的具体来源则由芯片设计者决定,因此不同产品之间的时钟频率可能会大不相同,你需要检视芯片的器件手册来决定选择什么作为时钟源。SysTick定时器能产生中断,CM3为它专门开出一个异常类型,并且在向量表中有它的一席之地。它使操作系统和其它系统软件在CM3器件间的移植变得简单多了,因为在所有CM3产品间对其处理都是相同的。
( ^7 L; |' u2 A: g4 z9 x$ I) m$ r _* }0 i% ^. e$ ?4 r5 I
; h( D# L7 S* @" g$ x
6 e8 I2 T i8 I& l5 \
% ~' V5 m& @ h$ F M3 P" V校准值寄存器提供了这样一个解决方案:它使系统即使在不同的CM3产品上运行,也能产生恒定的SysTick中断频率。
: L/ [6 N% `3 p3 m2 m b最简单的作法就是:直接把TENMS的值写入重装载寄存器,这样一来,只要没突破系统极限,就能做到每10ms来一次 SysTick异常。如果需要其它的SysTick异常周期,则可以根据TENMS的值加以比例计算。只不过,在少数情况下,CM3芯片可能无法准确地提供TENMS的值(如,CM3的校准输入信号被拉低),所以为保险起见,最好在使用TENMS前检查器件的参考手册。SysTick定时器除了能服务于操作系统之外,还能用于其它目的:如作为一个闹铃,用于测量时间等。要注意的是,当处理器在调试期间被喊停(halt)时,则SysTick定时器亦将暂停运作。- `" {1 j1 o3 i% Z
" J% u# V# \( E+ l9 j* m. s- static u8 fac_us=0;//us延时倍乘数 ; |; t2 ~# k4 u- x2 F- l" `
- static u16 fac_ms=0;//ms延时倍乘数,在ucos下,代表每个节拍的ms数
, N: O- `+ |& j" D5 W
7 B$ r X2 F2 ~6 P. e& B$ o- //初始化延迟函数
( j$ a& G7 x: Q% t. R. Q0 C3 ~. T - //SYSTICK的时钟可以配置为内核时钟HCLK或者外部时钟AHB/8
/ a. p0 O& i# H - //SysTick_CLKSource_HCLK_Div8 BIT2 = 0 为使用外部AHB / 8 , BIT2为1则为HCLK,系统时钟(单片机的主时钟)
) i: `# k* \8 Y5 C0 E# |1 ` - //SYSCLK:系统时钟(MHZ)0 t7 a( L, e" w( A
- void delay_init(u8 SYSCLK)
% G$ I; t2 S! y# q3 o - {! ]1 N2 P7 \: [6 V! |
- SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);//使用外部时钟源((uint32_t)0xFFFFFFFB) set bit 2 = 0
% ?& f" T. m4 V+ [! ^ - fac_us=SYSCLK/8;6 k1 i; r1 W: A/ d
- fac_ms=(u16)fac_us*1000;
/ a0 a5 V# f" S- l: A; x3 x - } / `2 H$ N, _4 }8 N( J6 }
- //延时nus
8 e1 T( o6 S9 ], e- N8 _ - //nus为要延时的us数.
! Z! ?* O( o' p$ @+ o# f. Q - //注意:nus的值,不要大于798915us7 a/ }' Q; t) r- S, e8 W
- void delay_us(u32 nus) K6 v/ |- Z6 ]* n9 i
- {
1 m0 H% F' @3 P& M+ y+ | - u32 temp;
T4 l. R; G8 f* Q4 i+ L; J; ~ - SysTick->LOAD=nus*fac_us; //时间加载E000E014' P: V3 M* A/ c( G: Y: R* ^; e) W
- SysTick->VAL=0x00; //清空计数器 E000E018
% Z3 S! a' {: t: m$ g - SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数 E000E010 BIT0 = 1 b2 K, h9 @- t# ]1 M x# m
- do: Y8 X, |& Z: J- u7 ^
- {
& v9 _! L) Z( u& u0 P - temp=SysTick->CTRL; //E000E010
p) Y+ f6 v6 ^5 O3 U% K3 ? - }$ b) o/ x" R( Z8 @" [) U
- while((temp&0x01)&&!(temp&(1<<16)));//等待时间到达BIT0 ENABLE && BIT 16 == 0) F/ J# V( p% D" V. @0 S5 t
- SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器
! H* O3 o- l2 d2 ~, B" G8 l4 l. P6 A - SysTick->VAL =0X00; //清空计数器
T& [& g R+ Q' {' }2 f - }6 ?6 ]* ^6 V7 y
- //延时nms& u4 O( P0 q+ ]
- //注意nms的范围# Q1 g( |2 s% E. m
- //SysTick->LOAD为24位寄存器,所以,最大延时为:
: D8 M& a F8 Z) K1 j m! i - //nms<=0xffffff*8*1000/SYSCLK
8 ~" E) a' Q2 _9 ] - //SYSCLK单位为Hz,nms单位为ms
1 ^0 R+ N" e9 h: D$ ]6 N0 d8 P; O - //对168M条件下,nms<=798ms 0 u& @$ V) O' `3 p; W1 {6 `
- void delay_xms(u16 nms)7 A: f1 P% S" y7 u% U$ @" x
- { ! q3 `# R3 t5 x
- u32 temp; ( Q3 Y# u* f" V) Y: ^ o3 E
- SysTick->LOAD=(u32)nms*fac_ms;//时间加载(SysTick->LOAD为24bit)
6 _+ q4 V# r% o; V# Q7 | - SysTick->VAL =0x00; //清空计数器1 H5 P: a2 o3 @: l$ S
- SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数 ' @* T* }% d4 W3 x8 ]/ ?+ N' b
- do5 X* p! r. G8 T
- {; u: [6 a. {/ l. T1 K
- temp=SysTick->CTRL;
: B% W3 a! I7 l$ H - }
/ @: O- l4 X g8 A0 J, e+ C! H# k - while((temp&0x01)&&!(temp&(1<<16)));//等待时间到达 2 c; _ b: b1 w6 V
- SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器
5 t" y6 \- q; l+ I - SysTick->VAL =0X00; //清空计数器 " ?' O9 T4 ~0 y5 d# k
- }
! L* v2 {* ?( E1 g - //延时nms
7 c. M4 b: k. r8 G2 M7 W - //nms:0~65535$ T( p6 o. D9 x+ ~# z
- void delay_ms(u16 nms)! n; T; R' y" E' _0 j) ]
- {
; S( P9 K% v. l3 R+ o! ^ - u8 repeat=nms/540; //这里用540,是考虑到某些客户可能超频使用,$ E- }2 x t; T) y2 F' F
- //比如超频到248M的时候,delay_xms最大只能延时541ms左右了6 ^% x1 \& O# \
- u16 remain=nms%540;8 A( ?9 ^- y( a
- while(repeat) M7 }" m. p( E# {4 v0 U- x
- {
/ h- X" h6 R @5 t1 ? - delay_xms(540);7 v1 L* G2 X8 _: d7 Z
- repeat--;
5 r9 w8 @& v( _ - }9 e. y$ V$ P( g* d$ l
- if(remain)delay_xms(remain); : a) \9 C# ^* X- U& O
- }9 V: k# k. s, t8 e
复制代码 : N. e$ l3 W: B& h; {/ H1 R1 L: q
最后这里再提一下systick开中断的方法:% i" O" n7 r* o: G1 E/ T+ `3 ^
systick也是可以设置中断优先级的,但是要开systick中断的话,必须将 systick的控制寄存器的bit1置1才行。
/ L3 {: G0 G/ h/ J, R* A! w; L$ a, t3 S
- void systick_irq_init(); _9 ~+ r9 p4 v7 Y% O$ l
- {
9 L; t9 A N' ?1 m" b1 t6 _6 z3 K - NVIC_InitTypeDef NVIC_InitStructure;0 p0 Y4 v# P/ B* ^
- NVIC_InitStructure.NVIC_IRQChannel = SysTick_IRQn;
4 z7 T l& c% k - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0X00;5 V* ? ], Z( M$ [8 z
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0X01;: G" V7 z# k8 `1 ~6 A- }3 U3 i- o
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//这里DISABLE也不影响
9 d" X2 ~# X3 N6 x$ W# y( z2 w - NVIC_Init(&NVIC_InitStructure);1 }' q. Y% `! S( n1 q7 U5 H. {, ?
- } - l0 L% v: n7 ~/ }8 o' L0 D5 c! u
- SysTick->CTRL |= 1 << 1;//一定要将控制寄存器的bit1置1才会生效。
; h# { F9 x' s& R3 J
复制代码
& T0 P) U) C' Q5 g5 d————————————————
/ }" U& o H! ?+ V) f3 X" n, ?版权声明:tony++7 X. a* X8 M/ Y( O2 X# P& L
6 X$ N: [, Q0 D3 F8 |0 L/ h; v
. J# \# Q& | j/ @" ?
|