一、uwTick
的作用
1.系统时间基准
uwTick
是一个全局变量(volatile uint32_t
),记录系统启动后的毫秒级时间累计值。默认情况下,它由 SysTick 定时器每 1ms 自动递增一次(通过HAL_IncTick()
函数。- 例如,若系统运行了 5 秒,
uwTick
的值约为5000。
2.实现延时功能
HAL_Delay()
函数依赖uwTick
实现阻塞延时。其原理是通过记录起始时刻的uwTick
值,并在循环中持续比较当前值与起始值的差值,直到达到设定的延时时间。
3.时间戳生成
- 通过
HAL_GetTick()
直接返回uwTick
,用于标记事件发生的时刻或计算时间间隔(如程序执行耗时)。
二、uwTick
的使用方法
1.基本延时操作
// 阻塞延时 100ms
HAL_Delay(100);
- 内部逻辑:
HAL_Delay()
调用HAL_GetTick()
获取当前uwTick
,循环等待直至时间差达到设定值。
2.时间间隔计算
uint32_t start = HAL_GetTick();
// 执行某些操作...
uint32_t elapsed_time = HAL_GetTick() - start; // 计算耗时(ms)
- 注意事项:若时间差超过
uint32_t
最大值(约 49.7 天),需额外处理溢出问题。
3.高精度时间测量
结合 SysTick 的当前计数值(SysTick->VAL
)和 uwTick
,可提升时间分辨率至微秒级:
uint32_t start_ms, start_ticks, end_ms, end_ticks;
vGetStartTime(&start_ms, &start_ticks); // 记录起始时间
// 执行代码...
vGetIntervalTime(start_ms, start_ticks, &end_ms, &end_ticks); // 计算时间差
float us = end_ms * 1000 + (SysTick->LOAD - end_ticks) * (1e6 / SystemCoreClock); // 转换为微秒
- SysTick 是递减计数器,
SysTick->VAL
提供当前周期内的剩余计数值,与uwTick
共同实现高精度计时。
三、配置与注意事项
1.时基源选择
- 默认使用 SysTick 作为时基源,但可通过 CubeMX 切换为硬件定时器(如 TIM1),以规避中断优先级冲突或实现更高精度的延时。
- 修改方法:在 CubeMX 的
SYS
配置中,选择其他定时器作为时基源。
2.中断优先级问题
- 风险:在中断服务函数(ISR)中调用
HAL_Delay()
可能导致死锁。例如,若高优先级中断等待 SysTick(低优先级)更新uwTick
,SysTick 中断可能无法触发。 - 修改方法:
避免在中断中使用阻塞延时,改用非阻塞计时(如标志位 + 轮询)。
修改 SysTick 中断优先级至更高等级(需同步调整其他中断优先级)。
3.自定义时基频率
- 通过调整
uwTickFreq
可改变uwTick
的更新频率(如改为 10kHz):
uwTickFreq = 10; // 10kHz(每 0.1ms 更新一次)
HAL_SYSTICK_Config(SystemCoreClock / (1000U / uwTickFreq));
- 注意:需同步修改
HAL_GetTick()
相关逻辑以适配新频率。
四、uwTick和Delay函数的核心区别
特性 | uwTick | HAL_Delay() |
---|---|---|
本质 | 全局变量(volatile uint32_t ) | 阻塞延时函数 |
作用 | 记录系统启动后的毫秒级累计时间 | 基于 uwTick 实现固定时长的阻塞延时 |
更新方式 | 由 SysTick 或硬件定时器中断自动递增 | 无直接操作,依赖 uwTick 的更新 |
用途 | 时间戳生成、非阻塞计时、任务调度 | 简单延时、代码流程控制 |
中断安全性 | 可在中断中使用(需注意优先级冲突) | 禁止在高优先级中断中使用(可能导致死锁) |
五、HAL_Delay()的用法
1.底层原理
-
HAL_Delay()
是阻塞函数,通过循环检查uwTick
的差值实现延时。其核心逻辑如下:
void HAL_Delay(uint32_t Delay) {uint32_t tickstart = HAL_GetTick(); // 获取起始时间uint32_t wait = Delay;wait += uwTickFreq; // 强制至少延时一个时基周期(默认+1ms)[3,4](@ref)while ((HAL_GetTick() - tickstart) < wait) {} // 阻塞等待[5,7](@ref)
}
- 误差特性:默认存在 **+1ms** 的固定误差(如
HAL_Delay(100)
实际延时 101ms)。
2.典型应用场景
- 简单延时控制:
HAL_Delay(500); // 阻塞延时500ms(实际501ms)
- 外设初始化等待:用于传感器上电稳定、通信协议间隔等场景。
3.注意事项
- 禁止在高优先级中断中使用:可能导致 SysTick 中断无法触发,
uwTick
停止更新,函数永不返回。 - 替代方案:在高实时性场景中,改用硬件定时器或非阻塞计时(基于
uwTick
)。
六、关键差异总结
1.角色不同:
uwTick
是 时间基准变量,提供系统时间数据。HAL_Delay()
是 延时工具函数,依赖uwTick
实现功能。
2.使用场景:
uwTick
适用于需要主动获取时间信息的场景(如性能分析、任务调度)。HAL_Delay()
适用于简单的阻塞等待(如初始化等待、调试指示灯闪烁)。
3.实时性影响:
HAL_Delay()
会阻塞 CPU,影响系统响应;uwTick
的非阻塞用法更适用于多任务系统。