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 四个控制寄存器

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

[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

本文章已经生成可运行项目
STM32实现微秒延时可以使用如方法: 1. 使用SysTick定时:SysTick定时器是一个24位的向下计数器,可以配置为不同的时钟源。你可以使用SysTick定时器来实现微秒延时。 首先,你需要初始化SysTick定时器,并将其配置为适当的时钟源。然后,使用一个循环来等待SysTick计数器达到所需的延时值。 以下是一个示例代码: ```c #include "stm32f4xx.h" void delay_us(uint32_t us) { // 配置SysTick定时器 SysTick_Config(SystemCoreClock / 1000000); // 使用CPU时钟作为时钟源,每个计数器增加1us uint32_t start = SysTick->VAL; // 记录当前计数器值 while ((start - SysTick->VAL) < us) { // 等待计数器达到所需的延时值 } } int main(void) { // 初始化系统和其他外设 while (1) { // 执行其他任务 delay_us(1000); // 延时1ms } } ``` 请注意,以上代码是基于STM32F4系列微控制器的示例。对于其他系列的STM32微控制器,你需要根据其特定的寄存器和时钟配置进行相应的修改。 2. 使用TIM定时器:另一种实现微秒延时的方法是使用TIM定时器。你可以配置一个适当的TIM定时器作为计时器,并使用其计数器值来实现微秒延时。 以下是一个示例代码: ```c #include "stm32f4xx.h" void delay_us(uint32_t us) { // 配置TIM定时器 RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; // 使能TIM2时钟 TIM2->PSC = SystemCoreClock / 1000000 - 1; // 设置预分频值,使计数频率为1MHz TIM2->ARR = us - 1; // 设置自动重载寄存器的值,确定延时时间 TIM2->CNT = 0; // 清零计数器 TIM2->CR1 |= TIM_CR1_CEN; // 启动计时器 while (!(TIM2->SR & TIM_SR_UIF)) { // 等待计时器溢出 } TIM2->SR &= ~TIM_SR_UIF; // 清除溢出标志位 } int main(void) { // 初始化系统和其他外设 while (1) { // 执行其他任务 delay_us(1000); // 延时1ms } } ``` 同样,请根据你使用STM32系列微控制器进行适当的修改。 这些是两种常见的实现微秒延时的方法,你可以根据需要选择其中之一来实现你的延时需求。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值