一、问题引入

我们需要实现一个延时,是这样实现的:
// STM32F103C8T6(72MHz) 专用毫秒级延时函数 // 实测:1ms误差±0.02ms,1000ms误差±15ms,满足外设控制需求 void delay_ms(uint32_t ms) { volatile uint32_t i, j; // 72MHz主频精准校准值,一行修改完成适配,核心逻辑不变 uint32_t calibrate = 8000; // 该值严格对应72MHz下约1ms延时 for(j = 0; j < ms; j++) { for(i = 0; i < calibrate; i++) { // volatile变量保证空循环不被编译器优化,延时有效 ; } } }
calibrate = 8000 是通过实验得到的近似值,并非准确值。如果使用这个延时函数,做一些精准延时的功能,是会有问题的。在STM32 裸机开发中(非操作系统),我们可以使用SysTick定时器,实现精准延时的需求,例如实现毫秒级、微秒级的延时。

二、SysTick简介

SysTick定时器,又名系统定时器、滴答定时器,是属于Cortex-M3内核中的一个外设,内嵌在NVIC中。系统定时器是一个24bit的向下递减的计数器SysTick定时器的应用
  1. 操作系统定时器:在RTOS(实时操作系统)中,SysTick定时器常被用作系统定时器,用于实现任务调度和定时器管理。
  2. 软件定时器:在没有RTOS的情况下,也可以利用SysTick定时器实现简单的软件定时功能。
  3. 周期性任务:可以用来定期执行一些周期性的任务,如采样ADC、刷新LCD显示等。

三、SysTick定时器的寄存器

四、SysTick定时器工作原理

1. 时钟来源

SysTick定时器有两种时钟来源可选择:内核时钟、外部参考时钟。内核时钟频率为 HCLK,外部参考时钟频率为 HCLK / 8

2. 定时原理

2.1 递减计数

SysTick是一个24位递减计数器,当前值寄存器从预设的初始值开始,每个时钟周期自动减1,当计数达到0时产生中断并自动重新加载初始值,如此循环往复。

2.2 重载值设定

通过LOAD寄存器设置重装载值(预设的初始值)。

2.3 时序图理解

发生中断间隔时间 = 一个脉冲时间 * (重装载值 + 1)
注意:一个脉冲周期时间 = 1 / 频率
根据公式,使用内核时钟 72MHz ,期待每间隔 1ms,发生一次中断:
重装载值 = 1ms * 72MHz - 1 = 72000 - 1 = 71999
注意:重装载的值不能超过 24bit 存储的范围,即不能超过16777215。

五、STM32CubeMX生成的延时ms函数

利用上述定时原理,STM32CubeMX默认生成了 延时 ms 级别精度 的函数 HAL_Delay(),使用示例如下:
// 替代main函数中的while循环 void app_main(void) { while (1) { HAL_Delay(1000); // 延时1000ms HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); } }
接下来我们分析其实现的代码:

六、SysTick定时器实现us精度延时

void delay_us(uint32_t us) { uint32_t save_LOAD; // 备份原SysTick->LOAD值 uint32_t target_ticks;// 目标us对应的SysTick重载值 // 1. 备份原始LOAD值(核心!延时结束必须恢复,否则HAL_Delay无法使用) save_LOAD = SysTick->LOAD; // 2. 计算目标us对应的重载值:SystemCoreClock(Hz) → 当前内核时钟的主频位72MHz,对应1us计数为72个脉冲 target_ticks = (1UL * SystemCoreClock / 1000000) * us; // 3.关闭SysTick中断,CTRL寄存器的bit1清零 SysTick->CTRL &=~0x02; // 4. 配置SysTick为「目标us计数模式」,启动计数 SysTick->LOAD=target_ticks - 1; // 重载值=计数值-1,(999->0总共是1000个计数) SysTick->VAL=0UL; // 计数器清零,同时也会同步清空 SysTick->CTRL的COUNTFLAG标志位,立刻开始计数 // 5. 硬件等待:直到计数完成(COUNTFLAG置1) while ((SysTick->CTRL&(1<<16))==0); // 6. 完全复原:恢复原始LOAD值,保证SysTick原理周期1ms不变 SysTick->LOAD=save_LOAD; SysTick->VAL=0; // 7. 恢复SysTick中断(否则HAL_Delay无法使用) SysTick->CTRL|=0x02; }
注意:重载值最大值为16777215,即该函数最大延时约233毫秒(内核时钟72MHz)。强烈建议延时 ms 时,用 HAL_Delay() 函数。

七、STMCubemx配置的SysTick中断优先级

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐