SysTick定时器详解

SysTick定时器详解

关于SysTick定时器,如果想从STM32官方手册去寻找该定时器,会发现并没有该定时器的相关介绍,仅有库函数介绍。由此可以看出SysTick并不是意法半导体公司设定的。从Cortex-M3权威指南可以找到该定时器的详细介绍,由此可以知道SysTick定时器是在ARM芯片当中设定的。
这里有一个疑问,为什么M3有这么多定时器还要弄一个SysTick定时器呢?
这要从它的概念入手,系统滴答定时器是一个非常基本的倒计时定时器,用于在每隔一定时间产生一个中断,即使是系统在睡眠模式下也能工作。它使得OS在各CM3器件之间的移植中不必修改系统定时器的代码,移植工作一下子容易多了。SysTick定时器也是作为NVIC的一部分实现的。

如果有外设就一定会存在一堆用来配置该外设的寄存器,SysTick定时器也不例外。用来控制该定时器的寄存器有四个,下面详细介绍这四个寄存器。

SysTick控制及状态寄存器(地址:0xE000_E010)

位段 名称 类型 复位值 描述
16 COUNTFLAG R 0 如果在上次读取本寄存器后, SysTick 已经数到了 0,则该位为 1。如果读取该位,该位将自动清零
2 CLKSOURCE R/W 0 0=外部时钟源(STCLK) 1=内核时钟(FCLK)
1 TICKINT R/W 0 1=SysTick 倒数到 0 时产生 SysTick 异常请求 0=数到 0 时无动作
0 ENABLE R/W 0 SysTick 定时器的使能位

四个位都挺简单,对两个稍难的解释一下:

TICKINT 该位置为1时,SysTick定时器倒数到零会产生中断

COUNTFLAG 已经有了TICKINT为什么还要该位呢,原因是当TICKINT位置为0时,如果没有该位,就无法得知定时器是否已经倒数到0,因为倒数到0不会有任何动作。

SysTick重装载数值寄存器(地址:0xE000_E014)

位段 名称 类型 复位值 描述
23:0 RELOAD R/W 0 当倒数至零时,将被重装载的值

该寄存器24位,最大可装载值为FF FFFF

SysTick当前数值寄存器(地址:0xE000_E018)

位段 名称 类型 复位值 描述
23:0 CURRENT R/Wc 0 读取时返回当前倒计数的值,写它则使之清零, 同时还会清除在 SysTick 控制及状态寄存器中的 COUNTFLAG 标志

该寄存器被读取后,会清零,重装载寄存器就会将它里面的重装载值传递到该寄存器。

SysTick校准数值寄存器(地址:0xE000_E01C)

位段 名称 类型 复位值 描述
31 NOREF R 1=没有外部参考时钟(STCLK 不可用) 0=外部参考时钟可用
30 SKEW R 1=校准值不是准确的 10ms 0=校准值是准确的 10ms
23:0 TENMS R/W 0 10ms 的时间内倒计数的格数。芯片设计者应该通 过 Cortex‐M3 的输入信号提供该数值。若该值读 回零,则表示无法使用校准功能

介绍完了寄存器,那就去STM32官方手册看看相关库函数吧,有一点可以肯定的是,库函数就是用来设置上面四个寄存器中某些位的。

在core_cm3.h文件中有这么一个函数可以用来配置SysTick定时器:

/**
 * @brief  Initialize and start the SysTick counter and its interrupt.
 *
 * @param   ticks   number of ticks between two interrupts
 * @return  1 = failed, 0 = successful
 *
 * Initialise the system tick timer and its interrupt and start the
 * system tick timer / counter in free running mode to generate 
 * periodical interrupts.
 * 初始化并启动系统滴答定时器和它的中断/计数器自由运行模式用来产生周期性的中断
 */
static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{ 
  if (ticks > SysTick_LOAD_RELOAD_Msk)  return (1);            /* Reload value impossible */
                                                               
  SysTick->LOAD  = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;      /* set reload register * SysTick_LOAD_RELOAD_Msk为0xFFFFFF */
  SysTick->VAL   = 0;                                          /* 把当前计数值设置为0,这* 样会将重装载寄存器中的值自动加载进来 Load the SysTick Counter Value */
  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk | 
                   SysTick_CTRL_TICKINT_Msk   | 
                   SysTick_CTRL_ENABLE_Msk;                    /* 将SysTick控制及状态寄存器低三位全部置为1。0、SysTick 定时器被使能 2、SysTick 倒数到 0 时产生 SysTick 异常请求 3、选择内核时钟(FCLK)为时钟源,也就是72MHZ*/
  return (0);                                                  /* Function successful */
}

#endif

用中断的方式实现delay:

void SysTick_Configuration(void){
    while(SysTick_Config(72)==1);	//1us产生一次SysTick异常
    SysTick->CTRL &= ~(1<<0);	//SysTick暂不开启,等使用时再开启
}

Void delay_us(unsigned long n){
    SysTick->CTRL |= (1<<0);
    while(n);  //每1us会产生一次中断,n--
    SysTick->CTRL &= ~(1<<0);
}

void SysTick_Handler(void){
    n--;
}
原文地址:https://www.cnblogs.com/roscangjie/p/12489574.html