• 使用系统定时器SysTick实现精确延时微秒和毫秒函数


    SysTick定时器简介

    SysTick定时器是存在于系统内核的一个滴答定时器,只要是ARM Cortex-M0/M3/M4/M7内核的MCU都包含这个定时器,它是一个24位的递减定时器,当计数到 0 时,将从RELOAD 寄存器中自动重装载定时初值,开始新一轮计数。使用内核的SysTick定时器来实现延时,可以不占用系统定时器,由于和MCU外设无关,所以代码的移植,在不同厂家的Cortex-M内核MCU之间,可以很方便的实现。而东芝的这款TT_M3HQ开发板使用的TMPM3HQFDFG芯片,正好是ARM Cortex-M3内核,所以以前使用的延时函数,可以直接拿过来使用,无需任何修改。

    精确延时函数的实现

    在core_cm3.h文件中,有这样一个SysTick_Config函数:

    __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 */
    }
    

    通过后面的注释也可以看出,这是对SysTick定时器进行初始化,配置初始计数值,使能中断,使能定时器等。对应的中断函数为:

    void SysTick_Handler(void)
    {	
    }
    

    这个默认是空的,需要我们自己来实现。

    如果SysTick初始化为:

    SysTick_Config(SystemCoreClock / 1000);     //定时1ms
    

    即SysTick定时器每1ms中断一次,如果我们定义全局变量,然后在中断函数中,让此变量递减,而在延时函数中,一直判断此变量是否减到了0,那么这样就实现了一个延时毫秒的函数。同理改变定时器的计数值为:

    SysTick_Config(SystemCoreClock / 1000000);  //定时1us
    

    那么就实现了每1us中断一次,所以延时微秒和延时毫秒函数的实现:

    uint32_t fac_us=0;							//us延时倍乘数			   
    uint32_t fac_ms=0;							//ms延时倍乘数,在ucos下,代表每个节拍的ms数
    	
    void delay_init(void)
    {
        SystemCoreClockUpdate();        //可以省略
    }
    void SysTick_Handler(void)
    {
        if(fac_us) fac_us--;
        if(fac_ms) fac_ms--;
    }
    void delay_us(uint32_t nus)
    {	
        SysTick_Config(SystemCoreClock / 1000000);  //定时1us
        fac_us = nus;
        while(fac_us != 0);	 
    }
    
    void delay_ms(uint32_t nms)
    {	 		  	  
        SysTick_Config(SystemCoreClock / 1000);     //定时1ms
        fac_ms = nms;
        while(fac_ms != 0);	 	  	    
    } 
    

    在使用延时函数之前,只需要进行系统时钟的更新即可,当然也可以不更新,因为在程序之前之前,系统启动文件中已经执行了系统时钟更新。

    总结

    由于SysTick定时器是所有的ARM Cortex-M内核MCU都有的一个定时器,所以以上延时微秒和延时毫秒的函数适用于任何 Cortex-M内核的MCU。有了精确延时函数,那么使用通用GPIO软件模拟一些通信协议,如IIC、SPI等串行协议,就可以驱动很多硬件设备了,如EEPROM、温湿度传感器、显示屏等等。


    推荐阅读


    • 我的个人博客:www.wangchaochao.top
    • 我的公众号:mcu149

  • 相关阅读:
    ResponsibleChain(责任链模式)
    IteratorPattern(迭代子模式)
    为什么抽象类不能实例化却有构造方法
    ObserverPattern(观察者模式)
    TemplateMethod(模块方法模式)
    java 定义一个同步map内存去重法
    oracle sql修改序列为当前序列开始
    oracle sql 当初始化数据时避免重复主键
    搭建基于express框架运行环境
    vue路由基础介绍
  • 原文地址:https://www.cnblogs.com/whik/p/11488635.html
Copyright © 2020-2023  润新知