【STM32】NVIC与中断控制 之 sysTick定时器

1. 基础概念

          SysTick—系统定时器是属于CM4内核中的一个外设,内嵌在NVIC中。系统定时器是一个24bit的向下递减的计数器,计数器每计数一次的时间为1/SYSCLK,一般我们设置系统时钟SYSCLK等于180M。当重装载数值寄存器的值递减到0的时候,系统定时器就产生一次中断,以此循环往复。

          因为SysTick是属于CM4内核的外设,所以所有基于CM4内核的单片机都具有这个系统定时器,使得软件在CM4单片机中可以很容易的移植。系统定时器一般用于操作系统,用于产生时基,维持操作系统的心跳。

 

SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号: 15)。在以前,大多操作系统需要一个硬件定时器来产生操作系统需要的滴答中断,作为整个系统的时基。

例如,为多个任务许以不同数目的时间片,确保没有一个任务能霸占系统;或者把每个定时器周期的某个时间范围赐予特定的任务等,还有操作系统提供的各种定时功能,都与这个滴答定时器有关。因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器,以维持操作系统“心跳”的节律。

SysTick定时器能产生中断, CM3为它专门开出一个异常类型,并且在向量表中有它的一席之地。它使操作系统和其它系统软件在CM3器件间的移植变得简单多了,因为在所有CM3产品间对其处理都是相同的。
有4个寄存器控制SysTick定时器,如表8.9至表8.12所示。

1.1 SysTick寄存器介绍

SysTick—系统定时有4个寄存器,简要介绍如下。在使用SysTick产生定时的时候,只需要配置前三个寄存器,最后一个校准寄存器不需要使用

寄存器名称

寄存器描述

CTRL

SysTick控制及状态寄存器

LOAD

SysTick重装载数值寄存器

VAL

SysTick当前数值寄存器

CALIB

SysTick校准数值寄存器

 

SysTick控制及状态寄存器

位段

名称

类型

复位值

描述

16

COUNTFLAG

R/W

0

如果在上次读取本寄存器后, SysTick 已经计到
了 0,则该位为 1。

2

CLKSOURCE

R/W

0

时钟源选择位,0=AHB/8,1=处理器时钟AHB

1

TICKINT

R/W

0

1=SysTick倒数计数到 0时产生 SysTick异常请
求,0=数到 0 时无动作。也可以通过读取COUNTFLAG标志位来确定计数器是否递减到0

0

ENABLE

R/W

0

SysTick 定时器的使能位

SysTick 重装载数值寄存器

位段

名称

类型

复位值

描述

23:0

RELOAD

R/W

0

当倒数计数至零时,将被重装载的值

表 184 SysTick当前数值寄存器

位段

名称

类型

复位值

描述

23:0

CURRENT

R/W

0

读取时返回当前倒计数的值,写它则使之清零,同时还会清除在SysTick控制及状态寄存器中的COUNTFLAG 标志

SysTick校准数值寄存器

位段

名称

类型

复位值

描述

31

NOREF

R

0

NOREF flag. Reads as zero. Indicates that a separate reference clock is provided.
The frequency of this clock is HCLK/8

30

SKEW

R

1

SKEW flag: Indicates whether the TENMS value is exact. Reads as one. Calibration
value for the 1 ms inexact timing is not known because TENMS is not known. This can affect
the suitability of SysTick as a software real time clock

23:0

TENMS

R

0

Calibration value. Indicates the calibration value when the SysTick counterruns on HCLK max/8 as external clock. The value is product dependent, please refer to theProduct Reference Manual, SysTick Calibration Value section. When HCLK is programmed atthe maximum frequency, the SysTick period is 1ms.
If calibration information is not known, calculate the calibration value required from thefrequency of the processor clock or external clock

系统定时器的校准数值寄存器在定时实验中不需要用到。有关各个位的描述这里引用手册里面的英文版本,比较晦涩难懂,暂时不知道这个寄存器用来干什么。有研究过的朋友可以交流,起个抛砖引玉的作用。

 

表8.9 SysTick控制及状态寄存器(地址:0xE000_E010)
【STM32】NVIC与中断控制 之 sysTick定时器_第1张图片

【STM32】NVIC与中断控制 之 sysTick定时器_第2张图片

【STM32】NVIC与中断控制 之 sysTick定时器_第3张图片

2.0 芯片介绍

分别为200 MHz/100 MHz/50 MHz。 RCU通过AHB时钟(HCLK)8分频后作为Cortex系统定时器(SysTick)的外部时钟。通过对SysTick控制和状态寄存器的设置,可选择上述时钟或AHB(HCLK)时钟作为SysTick时钟。

SysTick校准值设为25000, SysTick时钟频率配置为HCLK/8,此时若HCLK时钟被配置为200MHz,则SysTick中断会1ms响应一次。

【STM32】NVIC与中断控制 之 sysTick定时器_第4张图片

 

2.0 SysTick定时实验

利用SysTick产生1s的时基,LED以1s的频率闪烁

/**
  \brief   System Tick Configuration
  \details Initializes the System Timer and its interrupt, and starts the System Tick Timer.
           Counter is in free running mode to generate periodic interrupts.
  \param [in]  ticks  Number of ticks between two interrupts.
  \return          0  Function succeeded.
  \return          1  Function failed.
  \note    When the variable __Vendor_SysTickConfig is set to 1, then the
           function SysTick_Config is not included. In this case, the file device.h
           must contain a vendor-specific implementation of this function.
 */

__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
  if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
  {
    return (1UL);      /* Reload value impossible */
  }

  SysTick->LOAD  = (uint32_t)(ticks - 1UL);    /* set reload register */
  NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL);
 /* set Priority for Systick Interrupt */
  SysTick->VAL   = 0UL;             /* 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 */
  return (0UL);                                                    
 /* Function successful */
}
void SystemClock_Config(void)
{
    /* Set FLASH latency */
    LL_FLASH_SetLatency(LL_FLASH_LATENCY_7);

    /* Enable PWR clock */
    LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);

    /* Activation OverDrive Mode */
    LL_PWR_EnableOverDriveMode();


    /* Activation OverDrive Switching */
    LL_PWR_EnableOverDriveSwitching();


    /* Main PLL configuration and activation */
    LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSI, LL_RCC_PLLM_DIV_16, 432, LL_RCC_PLLP_DIV_2);
    LL_RCC_PLL_Enable();


    /* Sysclk activation on the main PLL */
    LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
    LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL);

    /* Set APB1 & APB2 prescaler*/
    LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_4);
    LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_2);

    /* Set systick to 1ms */
    SysTick_Config(216000000 / 1000);

    /* Update CMSIS variable (which can be updated also through SystemCoreClockUpdate function) */
    SystemCoreClock = 216000000;
}
/* SystemFrequency / 1000 1ms中断一次
 * SystemFrequency / 100000 10us中断一次
* SystemFrequency / 1000000 1us中断一次
 */
if (SysTick_Config(SystemCoreClock / 100000)) {
}

SysTick初始化函数由用户编写,里面调用了SysTick_Config()这个固件库函数,通过设置该固件库函数的形参,就决定了系统定时器经过多少时间就产生一次中断。

2.1 SysTick中断时间的计算

         SysTick定时器的计数器是向下递减计数的,计数一次的时间TDEC=1/CLKAHB,当重装载寄存器中的值VALUELOAD减到0的时候,产生中断,可知中断一次的时间TINT=VALUELOAD * TDEC中断= VALUELOAD/CLKAHB,其中CLKAHB =180MHZ。如果设置为180,那中断一次的时间TINT=180/180M=1us。不过1us的中断没啥意义,整个程序的重心都花在进出中断上了,根本没有时间处理其他的任务。

SysTick_Config(SystemCoreClock / 100000))

SysTick_Config()的形我们配置为SystemCoreClock / 100000=180M/100000=1800,从刚刚分析我们知道这个形参的值最终是写到重装载寄存器LOAD中的,从而可知我们现在把SysTick定时器中断一次的时间TINT=1800/180M=10us。

2.2 SysTick定时时间的计算

       当设置好中断时间TINT后,我们可以设置一个变量t,用来记录进入中断的次数,那么变量t乘以中断的时间TINT就可以计算出需要定时的时间。

2.3 SysTick定时函数

      现在我们定义一个微秒级别的延时函数,形参为nTime,当用这个形参乘以中断时间TINT就得出我们需要的延时时间,其中TINT我们已经设置好为10us。关于这个函数的具体调用看注释即可。

2.4 systick 微秒级延时

//代码 183 systick 微秒级延时

void SysTick_Delay_Us(__IO uint32_t us)
{
    uint32_t i;
    SysTick_Config(SystemCoreClock / 1000000);
    for (i = 0; i < us; i++)
    {
        // 当计数器的值减小到0的时候,CRTL寄存器的位16会置1
        while (!((SysTick->CTRL) & (1 << 16)));
    }
    // 关闭SysTick定时器
    SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
}

2.5systick 毫秒级延时

//代码 184 systick 毫秒级延时

void SysTick_Delay_Ms(__IO uint32_t ms)
{
    uint32_t i;
    SysTick_Config(SystemCoreClock / 1000);
    for (i = 0; i < ms; i++)
    {
        // 当计数器的值减小到0的时候,CRTL寄存器的位16会置1
        // 当置1时,读取该位会清0
        while (!((SysTick->CTRL) & (1 << 16)));
    }
    // 关闭SysTick定时器
    SysTick->CTRL &= ~ SysTick_CTRL_ENABLE_Msk;
}

2.6  结构体

/**
  \brief  Structure type to access the System Timer (SysTick).
 */
typedef struct
{
  __IOM uint32_t CTRL;  /*!< Offset: 0x000 (R/W)  SysTick Control and Status Register */
  __IOM uint32_t LOAD;  /*!< Offset: 0x004 (R/W)  SysTick Reload Value Register */
  __IOM uint32_t VAL;   /*!< Offset: 0x008 (R/W)  SysTick Current Value Register */
  __IM  uint32_t CALIB; /*!< Offset: 0x00C (R/ )  SysTick Calibration Register */
} SysTick_Type;

/* SysTick Control / Status Register Definitions */
#define SysTick_CTRL_COUNTFLAG_Pos         16U                                            /*!< SysTick CTRL: COUNTFLAG Position */
#define SysTick_CTRL_COUNTFLAG_Msk         (1UL << SysTick_CTRL_COUNTFLAG_Pos)            /*!< SysTick CTRL: COUNTFLAG Mask */

#define SysTick_CTRL_CLKSOURCE_Pos          2U                                            /*!< SysTick CTRL: CLKSOURCE Position */
#define SysTick_CTRL_CLKSOURCE_Msk         (1UL << SysTick_CTRL_CLKSOURCE_Pos)            /*!< SysTick CTRL: CLKSOURCE Mask */

#define SysTick_CTRL_TICKINT_Pos            1U                                            /*!< SysTick CTRL: TICKINT Position */
#define SysTick_CTRL_TICKINT_Msk           (1UL << SysTick_CTRL_TICKINT_Pos)              /*!< SysTick CTRL: TICKINT Mask */

#define SysTick_CTRL_ENABLE_Pos             0U                                            /*!< SysTick CTRL: ENABLE Position */
#define SysTick_CTRL_ENABLE_Msk            (1UL /*<< SysTick_CTRL_ENABLE_Pos*/)           /*!< SysTick CTRL: ENABLE Mask */

/* SysTick Reload Register Definitions */
#define SysTick_LOAD_RELOAD_Pos             0U                                            /*!< SysTick LOAD: RELOAD Position */
#define SysTick_LOAD_RELOAD_Msk            (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/)    /*!< SysTick LOAD: RELOAD Mask */

/* SysTick Current Register Definitions */
#define SysTick_VAL_CURRENT_Pos             0U                                            /*!< SysTick VAL: CURRENT Position */
#define SysTick_VAL_CURRENT_Msk            (0xFFFFFFUL /*<< SysTick_VAL_CURRENT_Pos*/)    /*!< SysTick VAL: CURRENT Mask */

/* SysTick Calibration Register Definitions */
#define SysTick_CALIB_NOREF_Pos            31U                                            /*!< SysTick CALIB: NOREF Position */
#define SysTick_CALIB_NOREF_Msk            (1UL << SysTick_CALIB_NOREF_Pos)               /*!< SysTick CALIB: NOREF Mask */

#define SysTick_CALIB_SKEW_Pos             30U                                            /*!< SysTick CALIB: SKEW Position */
#define SysTick_CALIB_SKEW_Msk             (1UL << SysTick_CALIB_SKEW_Pos)                /*!< SysTick CALIB: SKEW Mask */

#define SysTick_CALIB_TENMS_Pos             0U                                            /*!< SysTick CALIB: TENMS Position */
#define SysTick_CALIB_TENMS_Msk            (0xFFFFFFUL /*<< SysTick_CALIB_TENMS_Pos*/)    /*!< SysTick CALIB: TENMS Mask */

//\Drivers\CMSIS\Include\core_cm7.h 

/* Memory mapping of Cortex-M4 Hardware */
#define SCS_BASE            (0xE000E000UL)                            /*!< System Control Space Base Address */
#define ITM_BASE            (0xE0000000UL)                            /*!< ITM Base Address */
#define DWT_BASE            (0xE0001000UL)                            /*!< DWT Base Address */
#define TPI_BASE            (0xE0040000UL)                            /*!< TPI Base Address */
#define CoreDebug_BASE      (0xE000EDF0UL)                            /*!< Core Debug Base Address */
#define SysTick_BASE        (SCS_BASE +  0x0010UL)                    /*!< SysTick Base Address */
#define NVIC_BASE           (SCS_BASE +  0x0100UL)                    /*!< NVIC Base Address */
#define SCB_BASE            (SCS_BASE +  0x0D00UL)                    /*!< System Control Block Base Address */

#define SCnSCB              ((SCnSCB_Type    *)     SCS_BASE      )   /*!< System control Register not in SCB */
#define SCB                 ((SCB_Type       *)     SCB_BASE      )   /*!< SCB configuration struct */
#define SysTick             ((SysTick_Type   *)     SysTick_BASE  )   /*!< SysTick configuration struct */
#define NVIC                ((NVIC_Type      *)     NVIC_BASE     )   /*!< NVIC configuration struct */
#define ITM                 ((ITM_Type       *)     ITM_BASE      )   /*!< ITM configuration struct */
#define DWT                 ((DWT_Type       *)     DWT_BASE      )   /*!< DWT configuration struct */
#define TPI                 ((TPI_Type       *)     TPI_BASE      )   /*!< TPI configuration struct */
#define CoreDebug           ((CoreDebug_Type *)     CoreDebug_BASE)   /*!< Core Debug configuration struct */

 

你可能感兴趣的:(MCU_cortex,M7)