STM32使用Systick实现微秒(us)级延时

1、代码:(引用自立创开发板)

下列代码直接CV进自己的板子,.h文件改个#include "stm32f4xx.h"

然后把 SYSCLK 改为时钟树配的系统主频

SYS.c函数:

#include "sys.h"

#define SYSCLK 168000000

/**
 -  @brief  用内核的 systick 实现的微妙延时
 -  @note   None
 -  @param  _us:要延时的us数
 -  @retval None
*/
void delay_us(uint32_t _us)
{
    uint32_t ticks;
    uint32_t told, tnow, tcnt = 0;
 
    // 计算需要的时钟数 = 延迟微秒数 * 每微秒的时钟数
    ticks = _us * (SYSCLK / 1000000);
 
    // 获取当前的SysTick值
    told = SysTick->VAL;
 
    while (1)
    {
        // 重复刷新获取当前的SysTick值
        tnow = SysTick->VAL;
 
        if (tnow != told)
        {
            if (tnow < told)
                tcnt += told - tnow;
            else
                tcnt += SysTick->LOAD - tnow + told;
 
            told = tnow;
 
            // 如果达到了需要的时钟数,就退出循环
            if (tcnt >= ticks)
                break;
        }
    }
}
 
/**
 -  @brief  调用用内核的 systick 实现的毫秒延时
 -  @note   None
 -  @param  _ms:要延时的ms数
 -  @retval None
*/
void delay_ms(uint32_t _ms) { delay_us(_ms * 1000); }
 
void delay_1ms(uint32_t ms) { delay_us(ms * 1000); }
 
void delay_1us(uint32_t us) { delay_us(us); }


SYS.h函数


#ifndef __SYS_H__
#define __SYS_H__
        
#include "stm32f4xx.h"
 
//0,不支持ucos
//1,支持ucos
#define SYSTEM_SUPPORT_OS		0		//定义系统文件夹是否支持UCOS
	///
	
	
//定义一些常用的数据类型短关键字 
typedef int32_t  s32;
typedef int16_t s16;
typedef int8_t  s8;
 
typedef const int32_t sc32;  
typedef const int16_t sc16;  
typedef const int8_t sc8;  
 
typedef __IO int32_t  vs32;
typedef __IO int16_t  vs16;
typedef __IO int8_t   vs8;
 
typedef __I int32_t vsc32;  
typedef __I int16_t vsc16; 
typedef __I int8_t vsc8;   
 
typedef uint32_t  u32;
typedef uint16_t u16;
typedef uint8_t  u8;
 
typedef const uint32_t uc32;  
typedef const uint16_t uc16;  
typedef const uint8_t uc8; 
 
typedef __IO uint32_t  vu32;
typedef __IO uint16_t vu16;
typedef __IO uint8_t  vu8;
 
typedef __I uint32_t vuc32;  
typedef __I uint16_t vuc16; 
typedef __I uint8_t vuc8;  
 
 

void delay_us(uint32_t _us);
void delay_ms(uint32_t _ms);
void delay_1ms(uint32_t ms);
void delay_1us(uint32_t us);
 



#endif

2.原理:系统滴答定时器(SYSTick)

ARM_M4手册对SYSTick有关的寄存器的描述:

SysTick是属于Cortex-M4内核中的一个外设,内嵌在NVIC中。

系统定时器是一个24位的向下递减的计数器,计数器每计数一次的时间为1/SYSCLK。

系统时钟SYSCLK的值=HAL库时钟树配置的值

由于系统滴答定时器属于Cotex-M4内核的外设,相关寄存器介绍不在《参考手册》,而在《编程手册》

图例1 编程手册上对寄存器的定义

系统滴答定时器只有四个控制寄存器:STK_CTRL,STK_LOAD,STK_VAL和STK_CALIB。

图例2 四个控制寄存器

寄存器 中文名 描述
CTRL SysTick控制和状态寄存器 [31:17]保留位、16溢出标志位、[15:3]、2时钟源、1异常、0使能
LOAD SysTick重载寄存器 [31:24]保留位、[23:0]为重装位
VAL SysTick当前值寄存器 [31:24]保留位、[23:0]为当前值
CALIB SysTick校准值寄存器 没用到就先不管,我补充在后边,想看就记点

[31:24]保留位就是没用的位

整理一下流程:(当做定时器)

  1. 时钟源不分频
  2. 自动重装载值设置为 [SYSCLK(主频) / 1000 000] * n        这样出来的就是n us的值
  3. 在while(1)循环计算是否已经达到需要的时钟数、
  4. 到这里我们就有了us延时,封装一下就可以有毫秒和秒的延时。

       如下图

3.分析HAL库的HAL_Delay()函数

如果wait小于HAL_MAX_DELAY,则在wait上加上uwTickFreq的值,确保延时时间的准确性。

而HAL_MAX_DELAY = 0xFFFFFFFF

只要你的HAL_Delay延时时间不是超过2^32  = 4294967296ms,都会加上这个时间补偿,

既wait = wait + 1

AI对等待时间+1 的解释:

4.补充(寄存器)

4.1 STK_CTRL SysTick控制和状态寄存器

4.2 STK_LOAD SysTick重载寄存器

4.3 STK_VAL SysTick当前值寄存器

4.4 STK_CTRL SysTick校准值寄存器

5.参考资料:

【经验分享】STM32 基础重点—SysTick定时器 – STM32团队 ST意法半导体中文论坛

:16

作者:橘好き

物联沃分享整理
物联沃-IOTWORD物联网 » STM32使用Systick实现微秒(us)级延时

发表回复