• STM32之六:SysTick系统滴答定时器


    目录

    1. SysTick简介

    2. 时钟来源

    3. SysTick寄存器

    3.1 CTRL—SysTick控制及状态寄存器

    3.2 RELOAD—SysTick重装载数值寄存器

    3.3 CURRENT—SysTick当前数值寄存器

    4. systick系统定时器配置

    5. 延时函数实现

    5.1 延时函数编写步骤

    5.2 微秒级延时函数delay_us

    5.3 毫秒级延时函数delay_ms

    5.4 秒级延时函数delay_s


    1. SysTick简介

    SysTick——系统定时器,是属于CM3内核的一个外设,内嵌在NVIC中。SysTick是一个24位的向下递减的计数器,从重装载寄存器的值递减到0,之后自动从RELOAD寄存器中重装载定时器初值。只要不使能systick定时器,它就永不停息的一直循环计数,在睡眠模式下也能使用。

    systick系统滴答定时器在没有操作系统时,用于延时;在有操作系统时候(RTOS、UCOS2)通常为操作系统提供精准的定时中断(1ms~50ms)。

    2. 时钟来源

    1. AHB时钟8分频

    2. FCLK内核时钟 ,默认选择FCLK内核时钟

    3. SysTick寄存器

    SysTick有4个寄存器,如下图所示。

    SysTick寄存器汇总(来源:野火《STM32库开发实战指南》)

    3.1 CTRL—SysTick控制及状态寄存器

    控制及状态寄存器共计24位,但只使用了其0、1、2、16位。其中第2位为是时钟选择位,置1表示使用处理器时钟,即系统时钟;

    3.2 RELOAD—SysTick重装载数值寄存器

    3.3 CURRENT—SysTick当前数值寄存器

    3.4 校准数值寄存器,这个本节不需要,暂不介绍。

    此图汇总systick的寄存器。

    systick寄存器图

    4. systick系统定时器配置

    查看core_cm3.h可以找到systick_Config()函数,该函数配置了系统定时器的时钟源、重装载值和当前值。

    1. static __INLINE uint32_t SysTick_Config(uint32_t ticks)
    2. {
    3. if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */
    4. SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; /* set reload register */
    5. NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Cortex-M0 System Interrupts */
    6. SysTick->VAL = 0; /* Load the SysTick Counter Value */
    7. SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
    8. SysTick_CTRL_TICKINT_Msk |
    9. SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
    10. return (0); /* Function successful */
    11. }

     下面是函数中使用的结构体SysTick_Type,可以看到该结构体中包含了上文介绍的各个寄存器值。

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

    下面是函数中使用的宏定义:

    1. /* SysTick Control / Status Register Definitions */
    2. #define SysTick_CTRL_COUNTFLAG_Pos 16 /*!< SysTick CTRL: COUNTFLAG Position */
    3. #define SysTick_CTRL_COUNTFLAG_Msk (1ul << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */
    4. #define SysTick_CTRL_CLKSOURCE_Pos 2 /*!< SysTick CTRL: CLKSOURCE Position */
    5. #define SysTick_CTRL_CLKSOURCE_Msk (1ul << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */
    6. #define SysTick_CTRL_TICKINT_Pos 1 /*!< SysTick CTRL: TICKINT Position */
    7. #define SysTick_CTRL_TICKINT_Msk (1ul << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */
    8. #define SysTick_CTRL_ENABLE_Pos 0 /*!< SysTick CTRL: ENABLE Position */
    9. #define SysTick_CTRL_ENABLE_Msk (1ul << SysTick_CTRL_ENABLE_Pos) /*!< SysTick CTRL: ENABLE Mask */
    10. /* SysTick Reload Register Definitions */
    11. #define SysTick_LOAD_RELOAD_Pos 0 /*!< SysTick LOAD: RELOAD Position */
    12. #define SysTick_LOAD_RELOAD_Msk (0xFFFFFFul << SysTick_LOAD_RELOAD_Pos) /*!< SysTick LOAD: RELOAD Mask */
    13. /* SysTick Current Register Definitions */
    14. #define SysTick_VAL_CURRENT_Pos 0 /*!< SysTick VAL: CURRENT Position */
    15. #define SysTick_VAL_CURRENT_Msk (0xFFFFFFul << SysTick_VAL_CURRENT_Pos) /*!< SysTick VAL: CURRENT Mask */
    16. /* SysTick Calibration Register Definitions */
    17. #define SysTick_CALIB_NOREF_Pos 31 /*!< SysTick CALIB: NOREF Position */
    18. #define SysTick_CALIB_NOREF_Msk (1ul << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */
    19. #define SysTick_CALIB_SKEW_Pos 30 /*!< SysTick CALIB: SKEW Position */
    20. #define SysTick_CALIB_SKEW_Msk (1ul << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */
    21. #define SysTick_CALIB_TENMS_Pos 0 /*!< SysTick CALIB: TENMS Position */
    22. #define SysTick_CALIB_TENMS_Msk (0xFFFFFFul << SysTick_VAL_CURRENT_Pos) /*!< SysTick CALIB: TENMS Mask */
    23. /*@}*/ /* end of group CMSIS_CM3_SysTick */

    其中,Msk表示掩码操作,掩码操作指的是对一串二进制数据,通过与msk的位操作,达到屏蔽制定位而实现需求。

    例如对一串数字的0~3位清零,则可以定制一个msk=00001111。对于cmd=01010101,则cmd & ~msk = 01010101 & 11110000 = 01010000.

    1ul,其中ul是一个后缀表示无符号长整型(unsigned long)。<<表示左移位操作,例如a<,即a<<b=a*2^{b}.

    例如CTRL寄存器,其中SysTick_CTRL_CLKSOURCE_Msk 表示将1ul左移SysTick_CTRL_CLKSOURCE_Pos位,即2位,可得第2位的值为:1*2^{2}=4-->100,即第2位值为1,联系上文,可知CTRL的第2位为systick定时器的时钟源选择位,将本位赋值1,表示使用系统内核时钟。

    如此,便能理解systick_Config()函数了。

    5. 延时函数实现

    5.1 延时函数编写步骤

    1. 失能systick系统定时器,即SysTick->CTRL 定时器第0位置0。
    2. 将新的重加载值写入到SysTick->LOAD寄存器中。
    3. 将SysTick->VAL的值置为0。
    4. 使能systick系统定时器。

    官方推荐代码如下:(参考《Cortex M3与M4权威指南.pdf》第316页)

    1. SysTick->CTRL = 0; // Disable SysTick
    2. SysTick->LOAD = 0xFF; // Count from 255 to 0 (256 cycles)
    3. SysTick->VAL = 0; // Clear current value as well as count flag
    4. SysTick->CTRL = 5; // Enable SysTick timer with processor clock
    5. while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set
    6. SysTick->CTRL = 0; // Disable SysTick

    下面分别为微秒级、毫秒级、秒级延时函数示例(摘自B站金善愚systick定时器讲解视频)。

    5.2 微秒级延时函数delay_us

    1. #define AHB_INPUT 72 //请按RCC中设置的AHB时钟频率填写到这里(单位MHz)
    2. void delay_us(u32 uS){ //uS微秒级延时程序(参考值即是延时数,72MHz时最大值233015)
    3. SysTick->CTRL = 0;
    4. SysTick->LOAD=AHB_INPUT*uS - 1;//重装计数初值(当主频是72MHz,72次为1微秒)
    5. SysTick->VAL=0x00; //清空定时器的计数器
    6. SysTick->CTRL=0x00000005;//时钟源HCLK,打开定时器
    7. while(!(SysTick->CTRL&0x00010000)); //等待计数到0
    8. SysTick->CTRL=0;//关闭定时器
    9. }

    5.3 毫秒级延时函数delay_ms

    1. void delay_ms(u16 ms){ //mS毫秒级延时程序(参考值即是延时数,最大值65535)
    2. while( ms-- != 0){
    3. delay_us(1000); //调用1000微秒的延时
    4. }
    5. }
    6. //或者
    7. void delay_ms(uint32_t ms)
    8. {
    9. while(ms --)
    10. {
    11. SysTick->CTRL = 0; // 关闭系统定时器后才能配置寄存器
    12. SysTick->LOAD = 72000 - 1; // 设置计数值,用于设置定时的时间
    13. SysTick->VAL = 0; // 清空当前值还有计数标志位
    14. SysTick->CTRL = 5; // 使能系统定时器工作,且时钟源为系统时钟的8分频(168MHz/8=21MHz)
    15. while(!(SysTick->CTRL&0x00010000)); //等待计数到0
    16. SysTick->CTRL = 0; // 关闭系统定时器
    17. }
    18. }

    5.4 秒级延时函数delay_s

    1. void delay_s(u16 s){ //S秒级延时程序(参考值即是延时数,最大值65535)
    2. while( s-- != 0){
    3. delay_ms(1000); //调用1000毫秒的延时
    4. }
    5. }
  • 相关阅读:
    Leetcode 剑指 Offer II 049. 求根节点到叶节点数字之和
    Prometheus简介和安装教程
    golang学习之七:并发编程基础(goroutine、channel、select)
    ubuntu18.04 +CUDA11.1 + pytorch1.8.1 环境配置
    解决GET请求中文乱码问题
    【SpringBoot】当AOP引发的异常与@RestControllerAdvice擦肩而过:异常处理的盲点揭秘
    FPGA HLS 基于stream的池化单元 hls优化&约束
    数据库实践 Hw05
    【Tomcat】在SpringBoot项目中,Tomcat是如何处理HTTP请求的
    uniapp小程序使用web-view组件页面分享后,点击没有home小房子解决办法
  • 原文地址:https://blog.csdn.net/guaizaiguaizai/article/details/140189442