STM32使用Systick实现微秒(us)级延时_stm32 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 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_OS0//定义系统文件夹是否支持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 四个控制寄存器
[31:24]保留位就是没用的位
整理一下流程:(当做定时器)
- 时钟源不分频
- 自动重装载值设置为 [SYSCLK(主频) / 1000 000] * n 这样出来的就是n us的值
- 在while(1)循环计算是否已经达到需要的时钟数、
- 到这里我们就有了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


