stm32专题九:SysTick(一)系统嘀嗒定时器原理

SysTick是存在于stm32内核的定时器,嵌套在NVIC中,24位,只能递减。在stm32中文参考手册中,对于SysTick的描述其实很少,主要如下。systick的时钟可以为AHB时钟,或者是AHB时钟8分频=9M。而校准值固定为9000,也就是说,当时钟频率为9M时,9000的固定值对应1ms时间基准,9000 000对应1s时间。

在core-CM3编程手册中,有配置systick的寄存器描述。

stm32专题九:SysTick(一)系统嘀嗒定时器原理_第1张图片

SysTick控制和状态寄存器STK_CTRL

stm32专题九:SysTick(一)系统嘀嗒定时器原理_第2张图片

stm32专题九:SysTick(一)系统嘀嗒定时器原理_第3张图片

 

位描述:

COUNTFLAG:如果上一次计数到0,则返回1,为计数标志。

CLKSOURCE:选择时钟源,为0时即为AHB时钟8分频,为1时直接就等于AHB总线时钟。

TICKINT:SysTick异常请求使能,该位为1则计数值减到0时发起系统异常请求,为0时不响应。

ENABLE:该位为1时,计数值从重装载值寄存器开始往下递减,当减到0,会设置COUNTFLAG标志位为1,并根据TICKINT的值来选择是否发起系统异常请求,然后重新装初始值,开始计数。

STK_LOAD重装载值寄存器,设置计数初值。值得注意的是,SysTick是减到0,一次完整的计数过程是0 - 99 - 98 -... -0共100个数,这是循环计数过程。因此,如果我们希望的计数值为N,实际上要写入到LOAD寄存器的值必须为N-1,这个非常重要。

stm32专题九:SysTick(一)系统嘀嗒定时器原理_第4张图片

另外,如果是希望计数只触发一次,则填入的值还是N,因为少了一个0-N的一次记数,这些都有寄存器描述,最常用的循环计数还是初始值为N-1

stm32专题九:SysTick(一)系统嘀嗒定时器原理_第5张图片

还有一个当前计数值寄存器,该寄存器一旦写入就会将当前寄存器的所有位清零,并还会把CPUNTFLAG标志位清0,所以我们不要鬼这个寄存器进行写入操作。

stm32专题九:SysTick(一)系统嘀嗒定时器原理_第6张图片

野火给出的框图如下,也是在说明上述意义。

stm32专题九:SysTick(一)系统嘀嗒定时器原理_第7张图片

SysTick定时时间的计算:

  1. 时间t   单词执行的时间,和reload CLK有关;
  2. CLK  9M或72M,由CTRL寄存器配置;
  3. reload值,24位,用户配置;

所以就有下面的配置:

t = reload * (1 / CLK)

CLK = 72M时,t = (72) * (1 / 72M) = 1us,此时reload = 72

CLK = 72M时,t = (72000) * (1 / 72M) = 1ms,此时reload = 72000

注意,这是单次计数,所以reload = N,就是从N到0,实际上计数N次。而循环计数时,reload要设置为N-1,因为从N-1到0计数N-1次,再从0到N-1计数一次,这才是一个完整的循环周期。

如果产生中断的延时是微妙级别,那么系统会频繁的进入中断,很多事情就做不了了,与系统的时间相冲突,因此意义不大,通常使用的中断都是ms级别。

标准固件库中对SysTick有非常详细的描述

这个时初始化结构体

typedef struct
{
  __IO uint32_t CTRL;                         /*!< Offset: 0x00  SysTick Control and Status Register */
  __IO uint32_t LOAD;                         /*!< Offset: 0x04  SysTick Reload Value Register       */
  __IO uint32_t VAL;                          /*!< Offset: 0x08  SysTick Current Value Register      */
  __I  uint32_t CALIB;                        /*!< Offset: 0x0C  SysTick Calibration Register        */
} SysTick_Type;

然后看系统默认对SysTick的配置,这里有几个值得注意的地方,1 输入嘀嗒数不能超过2^24;2 嘀嗒数就是要定时的数N,因为代码里自动实现了N-1;默认将时钟配置为AHB时钟72M;默认中断优先级位最低优先级15。

/**
 * @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 中断优先级,默认为最低的优先级(1 << 4) - 1 = 16 - 1 = 15
  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_CLKSOURCE_Msk = 1 << 2,默认会将时钟配置为AHB时钟源72M
  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk | 
                   SysTick_CTRL_TICKINT_Msk   | 
                   SysTick_CTRL_ENABLE_Msk;                    /* Enable SysTick IRQ and SysTick Timer */
  return (0);                                                  /* Function successful */
}

固件库设置中断优先级的标准函数,首先判断中断标号<0(内核)还是>=0(外设),如果是外设的中断非常简单,直接设置IP寄存器的高4位(priority << 4),如果是内核的中断,不是设置NVIC_IP寄存器,而是设置SCB_SHPR寄存器。

stm32专题九:SysTick(一)系统嘀嗒定时器原理_第8张图片

stm32专题九:SysTick(一)系统嘀嗒定时器原理_第9张图片

 

/**
 * @brief  Set the priority for an interrupt
 *
 * @param  IRQn      The number of the interrupt for set priority
 * @param  priority  The priority to set
 *
 * Set the priority for the specified interrupt. The interrupt 
 * number can be positive to specify an external (device specific) 
 * interrupt, or negative to specify an internal (core) interrupt.
 *
 * Note: The priority cannot be set for every core interrupt.
 */
static __INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
{
  if(IRQn < 0) {
    SCB->SHP[((uint32_t)(IRQn) & 0xF)-4] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff); } /* set Priority for Cortex-M3 System Interrupts */
  else {
    NVIC->IP[(uint32_t)(IRQn)] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff);    }        /* set Priority for device specific Interrupts  */
}

当SysTick和外设同时产生中断时,根据4位数的数值大小来解析中断优先级的高低。

stm32专题九:SysTick(一)系统嘀嗒定时器原理_第10张图片

 

你可能感兴趣的:(stm32专栏)