Systick

来源:互联网 发布:灵畅互动软件 编辑:程序博客网 时间:2024/05/19 11:50


首先我们要明白什么是SysTick定时器?


Sys  系统 ,tick 滴答声 ,系统滴答滴答很形象地表示了它是一个系统节拍器。SysTick 是一个24 位的倒计数定时器,当计到0 时,将从RELOAD 寄存器中自动重装载定时初值。只要不把它在SysTick 控制及状态寄存器中的使能位清除,就永不停息。



?  为什么要设置SysTick定时器?

(1)产生操作系统的时钟节拍

SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号:15)。在以前,大多操作系统需要一个硬件定时器来产生操作系统需要的滴答中断,作为整个系统的时基。因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器,以维持操作系统“心跳”的节律。SysTick的最大使命,就是定期地产生异常请求,作为系统的时基。OS都需要这种“滴答”来推动任务和时间的管理。



(2)便于不同处理器之间程序移植。

Cortex‐M3处理器内部包含了一个简单的定时器。因为所有的CM3芯片都带有这个定时器,软件在不同 CM3器件间的移植工作得以化简。该定时器的时钟源可以是内部时钟(FCLK,CM3上的自由运行时钟),或者是外部时钟( CM3处理器上的STCLK信号)。不过,STCLK的具体来源则由芯片设计者决定,因此不同产品之间的时钟频率可能会大不相同,你需要检视芯片的器件手册来决定选择什么作为时钟源。SysTick定时器能产生中断,CM3为它专门开出一个异常类型,并且在向量表中有它的一席之地。它使操作系统和其它系统软件在CM3器件间的移植变得简单多了,因为在所有CM3产品间对其处理都是相同的。



(3)作为一个闹铃测量时间。

SysTick定时器还可以用作闹钟,作为启动一个特定任务的时间依据。它作为一个闹铃,用于测量时间。要注意的是,当处理器在调试期间被喊停(halt)时,则SysTick定时器亦将暂停运作。





?  再来看看SysTick的用法

(1)我们对一个系统编程,老说编程编程什么的,到底我们在编什么程?当然这个问题要探讨起来可能有点远了。我来说说对SysTick的编程,对单片机的编程不过就是对单片机里面的寄存器进行控制,使整个软硬件系统处于一种在你的掌控之下的状态。这就是了嘛,现在我是头,我对我的手下下达一些指令,让它们去做一些事情。所以我们想搞清楚怎样控制SysTick我们还得看我们能对它的哪些部分可以控制。那些部分就是寄存器。



SysTick有4个寄存器 :

寄存器        描述 
CTRL          SysTick 控制和状态寄存器 
LOAD         SysTick 重装载值寄存器 
VAL            SysTick 当前值寄存器 
CALIB         SysTick 校准值寄存器



对应地在固件函数库中定义了这个东西

typedef struct 



vu32 CTRL; 

vu32 LOAD; 

vu32 VAL; 

vuc32 CALIB; 

} SysTick_TypeDef;

在这背后,已经对定义的寄存器进行了一个地址映射。当我们操控我们定义的寄存器时实际上已是通过那种映射关系操控了芯片内部的值。其实在STM32中对寄存器的操作都是通过这种方式进行的。

具体的映射过程如下,我们可以看一下:

#define SCS_BASE ((u32)0xE000E000) 

#define SysTick_BASE (SCS_BASE + 0x0010) 

#ifndef DEBUG 

... 

#ifdef _SysTick 

#define SysTick ((SysTick_TypeDef *) SysTick_BASE) 

#endif /*_SysTick */ 

... 

#else /* DEBUG */ 

... 

#ifdef _SysTick 

EXT SysTick_TypeDef *SysTick; 

#endif /*_SysTick */ 

... 

#endif 

#ifdef _SysTick 

SysTick = (SysTick_TypeDef *) SysTick_BASE; 

#endif /*_SysTick */ 

为了访问SysTick寄存器,, _SysTick必须在文件“stm32f10x_conf.h”中定义如下: 

#define _SysTick



映射过程就不作讨论了。总这这样映射的结果是我们能直接使用SysTick。那就来看一下有关寄存器的设置。



(2)SysTick里的寄存器我也简单地把它理解为是一个32位数。

这里有一张图:



在最新的STM32固件库中的core_cm3.c中提供了这样一个函数来供我们配置SysTick,当我们须要用到SysTick时调用它就可以了:

static __INLINE uint32_t SysTick_Config(uint32_t ticks)//ticks 是要重装载的值



if (ticks > SysTick_LOAD_RELOAD_Msk)  return (1);            

/* Reload value impossible  检查重装值是否可用 */

/* 

这里引起了我的思考,在很多程序里的第一步都是检查输入值是否可用,也许我应该形成一种条件反射,一看到有输入值就应该判断是否应该对其检查是否可用,这样的好处还是很多的,经过检查我们就不必输入值合法不,不合适时程序会提示我们的 

*/



SysTick->LOAD  = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;      

/* set reload register */

/* 

往LOAD寄存器中写入重装值,前面提到了我们可以直接使用SysTick,这里就可以看出来,我们要使用SysTick结构中的LOAD寄存器,于是我们就直接用到SysTick->LOAD 

在core_cm3.c中也可以找到SysTick_LOAD_RELOAD_Msk的值为0xFFFFFFFFul,即unsigned long int 0xFFFFFFFF,请注意这样一句话:SysTick 是一个24 位的倒计数定时器,当计到0 时,将从RELOAD 寄存器中自动重装载定时初值。假设是你单独思考你会想到重装值是多少吗。为什么是ticks要减1,而不是ticks次。我们可以发现它是倒数到0的,也可以理解成从0计数到设定值的,所以它是ticks-1次。

*/

NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); 

/* set Priority for Cortex-M0 System Interrupts */



SysTick->VAL   = 0;                                          

/* Load the SysTick Counter Value */

/* 装载系统当前值 */



SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk | 

SysTick_CTRL_TICKINT_Msk   | 

SysTick_CTRL_ENABLE_Msk;                    

/* Enable SysTick IRQ and SysTick Timer */

/*

对CTRL进行配置,在core_cm3.c中有如下定义:

#define SysTick_CTRL_CLKSOURCE_Pos      2                                             

#define SysTick_CTRL_CLKSOURCE_Msk           (1ul<<SysTick_CTRL_CLKSOURCE_Pos)            

#define SysTick_CTRL_TICKINT_Pos         1                                             

#define SysTick_CTRL_TICKINT_Msk        (1ul << SysTick_CTRL_TICKINT_Pos)             

#define SysTick_CTRL_ENABLE_Pos         0                                         

#define SysTick_CTRL_ENABLE_Msk        (1ul <<SysTick_CTRL_ENABLE_Pos)

即有:SysTick_CTRL_CLKSOURCE_Msk = 0x00000004      clksource使用内部FCLK

SysTick_CTRL_TICKINT_Pos    = 0x00000002         响应SysTick中断

SysTick_CTRL_ENABLE_Pos     = 0x00000001         使能SysTick

*/

return (0);             /* successful */ /* 初始化成功返回值为0 */

}



总结:在配置过程对CTRL//LOAD/VAL三个寄存器进行了配置,初始化了SysTick使用的时钟,清除系统当前值,装入重装值,使能SysTick,使SysTick能响应中断,说了半天其实就这一句话。在主程序中调用SysTick_Configuration( uint32_t ticks ),输入重装值就配置完成了。



(3)SysTick 的中断处理函数在stm32f10x_it.c 

函数原型为void SysTick_Handler(void)

{

// user code

}

用户只要把须要处理的程序填入这里就完成啦。





例子:

正如上面叙述,SysTick的使用为:

(1)配置SysTick

(2)写中断函数



我们产生1ms的廷时:

在我们自己编写的main.c中有:

//前面的省略 ……

Volatile unsigned int TimingDelay ;      //定义一个全局变量,用于计数计时值



//中间部分省略……

void Delay_Ms( uint32_t nTime )          //我们须要的延时函数

{

TimingDelay = nTime ;                //把延时值赋值给TimingDelay;

while( TimingDelay != 0 );         //等待计时时间到,在SysTick的中断函数

//中每1ms对TimingDelay减1

}





int main(void)

{

//配置电源

//配置GPIO

//配置NVIC  等等

while( SysTick_Configuration( 72000 )  != 0  ) ; //配置SysTick,装入倒数值,我们假设系统时钟为72MHz,则要定时1ms,输入的倒数值为72000

while(1)

{

//user code

}

}



在stm32f10x_it.c中:

//前面省略 ……

extern volatile unsigned int TimingDelay;



void SysTick_Handler(void)

{

// user code

TimingDelay--;

}
1 0
原创粉丝点击