第11章 基础重点—SysTick 定时器

一、关于SysTick定时器

  SysTick定时器(又名系统滴答定时器)是存在于Cortex-M3的一个定时器,只要是ARM Cotex-M系列内核的MCU都包含这个定时器。使用内核的SysTick定时器来实现延时,可以不占用系统定时器,节约资源。由于SysTick是在CPU核内部实现的,跟MCU外设无关,因此它的代码可以在不同厂家之间移植。
  本章将使用系统滴答定时器实现延时函数, 注 意 SysTick 用于了 HAL 库的毫秒级延时函数“HAL_Delay()”,不建议日常使用SysTick去作为其它用途,这里只作为演示。
  SysTick定时器是一个24位递减定时器,即计数器可以从最大值224开始,每个时钟周期减1,当减到0时,会产生Systick异常,同时再自动重载定时初值,开始新一轮计数。通过设置这个定时初值,就可以实现得到指定时间。如下图 11.1.1 所示,y为定时器初值,然后随着时间增加,值逐渐减小,直至为0,再重新加载初值,如此往复,x1、x2、x3这些时间段,就是我们需要的延时时间。
在这里插入图片描述
  假设STM32F103工作在72MHz,即72000000Hz,意味着1s时间内,会计数72000000次。那么1ms则计数72000000/1000=72000次。这个72000就可以作为系统滴答定时器的初始值,将这个值写入系统滴答定时器,定时器在每个时钟周期减1,减到0时,就刚好是1ms,同时产生中断通知,再次加载72000如此反复。HAL库提供“HAL_SYSTICK_Config()”函数去设置这个初始值。
  系统滴答定时器只有四个控制寄存器:STK_CTRL,STK_LOAD,STK_VAL和STK_CALIB。因 为系统滴答定时器属于Cotex-M3内核的外设,相关寄存器介绍不在《参考手册》,而在《3_STM32F10xx Cortex-M3编程手册》,后简称《编程手册》。

1.1 系统滴答定时器控制和状态寄存器(STK_CTRL)

在这里插入图片描述
  重点关注Bit[0],用于使能系统滴答定时器,Bit[1]使能系统滴答定时器中断,Bit[2]系统滴答时钟的时钟来源。

1.2 系统滴答定时器加载值寄存器(STK_LOAD)

在这里插入图片描述
  Bit[23:0],一共24位,用来设置系统滴答定时器的初始值,因此范围为1~ 16777216。

1.3 系统滴答定时器当前值寄存器(STK_VAL)

在这里插入图片描述
在这里插入图片描述
  Bit[23:0],一共24位,用来获取当前系统滴答定时器的计数值。

1.4 系统滴答定时器校准值寄存器(STK_CALIB)

在这里插入图片描述
  这个寄存器没用到,可以不用管。此外,当处理器在调试期间被暂停(halt)时,系统滴答定时器也将暂停运作。

二、硬件设计

  系统滴答定时器属于Cortex-M3内核资源,不涉及外部硬件电路。

三、软件设计

3.1 软件设计思路

  实验目的:使用系统滴答定时器实现自定义延时。

  1. 分析HAL库的系统滴答定时器配置函数;
  2. 初始化系统滴答定时器(设置计数初值、使能等);
  3. 封装延时函数,设置系统滴答定时器中断处理函数;
  4. 主函数调用验证;

3.2 软件设计思路

3.2.1 分析HAL库的系统滴答定时器配置函数

  在HAL库中,使用“HAL_SYSTICK_Config()”函数配置SysTick的初始值。

/**
* @brief Initializes the System Timer and its interrupt, and starts the System Tick Timer.
* Counter is in free running mode to generate periodic interrupts.
* @param TicksNumb: Specifies the ticks Number of ticks between two interrupts.
* @retval status: - 0 Function succeeded.
* - 1 Function failed.
*/
uint32_t HAL_SYSTICK_Config(uint32_t TicksNumb)
{
	return SysTick_Config(TicksNumb);
}

  该函数调用“SysTick_Config()”函数,函数内容如下代码段 11.3.2所示。

#if defined (__Vendor_SysTickConfig) && (__Vendor_SysTickConfig == 0U)

/**
  \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 <b>__Vendor_SysTickConfig</b> is set to 1, then the
           function <b>SysTick_Config</b> is not included. In this case, the file <b><i>device</i>.h</b>
           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 */
}

#endif

  通过对“HAL_SYSTICK_Config()”函数分析,可知只需要传入SysTick初始值,其它的都默认已经设置完成了。

3.2.2 初始化系统滴答定时器

/*
 *  函数名:void SysTickInit(uint32_t cycle)
 *  输入参数:cycle,设置系统滴答时钟周期
 *  输出参数:无
 *  返回值:无
 *  函数作用:初始化系统滴答时钟的频率和中断优先级
*/
void SysTickInit(uint32_t cycle)
{
    uint32_t init_t = 0;

    init_t = SystemCoreClock/cycle;
  
    /* 时间(单位:s)=1/频率(单位:HZ)
     * SystemCoreClock频率: 72MHz = 72,000,000
     * 即MCU 1秒会计数72,000,000次
     *       1ms则计数 72MHz/1000 = 72000次
     * 72000就是滴答时钟的初始值,它向下计数72000次,计数将变为0,就会产生一次中断
     * 滴答时钟初始值范围:1~16777216
     *
     * SystemCoreClock/1000:    1ms中断一次
     * SystemCoreClock/100000:  10us中断一次
     * SystemCoreClock/1000000: 1us中断一次
     */
    if(HAL_SYSTICK_Config(init_t) != HAL_OK)
    {
        Error_Handler();
    }
    
    // 设置滴答定时器中断优先级:最高
    HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
    // 使能滴答定时器中断
    HAL_NVIC_EnableIRQ(SysTick_IRQn);
}

  为了方便修改SysTick的初始值,这里定义几个常见的延时周期:

#define CYCLE_100MS   10
#define CYCLE_10MS    100
#define CYCLE_1MS     1000 
#define CYCLE_100US   10000
#define CYCLE_10US    100000
#define CYCLE_1US     1000000

3.2.3 封装延时函数,设置系统滴答定时器中断处理函数

  创建延时函数“SysTickDelay()”,在该函数里设置自定义全局变量systick_t的初始值,SysTick每计数完一次则进入SysTick中断,将全局变量systick_t的值减1,如代码段 11.3.6 所示。一直到systick_t变为零,结束延时,如代码段 11.3.5 所示。
在这里插入图片描述
在这里插入图片描述

3.2.4 主函数调用验证

int main(void)
{    
    // 初始化HAL库函数必须要调用此函数
    HAL_Init();

    /*
     * 系统时钟即AHB/APB时钟配置
     * 使用外部高速时钟HSE(8MHz)配置系统时钟,经过PLL放大9倍,得到72MHz
    */
    SystemClock_Config();
    
    // 调用库函数来检验自己的配置是否成功配置为系统频率72MHz
    sys_clk = HAL_RCC_GetSysClockFreq();
    
    /* 
     * 初始化滴答时钟
     * 通过改变传入参数改变滴答时钟的频率,即SysTickDelay(1)的时长
    */
    SysTickInit(CYCLE_1MS);
    
    // 初始化LED
    LedGpioInit();
    while(1)
    {
        /* 通过延时一段时间让LED亮灭实现LED闪烁,可以通过示波器打LED的引脚反转周期,精确看时间是否与设置的一致*/
        RLED(ON);             // 点亮LED
        SysTickDelay(1000);   // 延时CYCLE_1MS*1000=1s
        RLED(OFF);            // 熄灭LED
        SysTickDelay(1000);   // 延时CYCLE_1MS*1000=1s
    }
}

四、代码工程

工程链接:基本重点-SysTick

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值