可以跳转最后看
24 位掩码修正法的原理与限制(需 LOAD=0xFFFFFF
)
1. 核心原理
当 SysTick 的 LOAD
值设置为 0xFFFFFF(24 位最大值)时,其计数器行为与 24 位模运算 完全一致。此时:
- VAL 寄存器 始终在
0x000000
到0xFFFFFF
之间循环递减。 - 时间差计算:通过
(LastTick - CurrentVal) & 0xFFFFFF
,利用 24 位掩码隐式处理溢出,直接得到正确的周期差。
2. 关键假设
LOAD = 0xFFFFFF
:必须确保 SysTick 的加载值为 24 位最大值。- 计数器行为:VAL 从
0xFFFFFF
开始递减,到0x000000
后自动重载为0xFFFFFF
。
3. 计算示例
假设 LastTick = 0x100
(即 256),当前 CurrentVal = 0xFFFFF000
(即 0xFFF000 的 24 位掩码值):
- 直接计算:
0x100 - 0xFFF000 = -0xFFEE00
(负值) - 应用 24 位掩码:
(-0xFFEE00) & 0xFFFFFF = 0x001200
(即 0x1200 = 4608 周期) - 实际周期差:
- LastTick 从 0x100 递减到 0x000000:256 周期
- 重载后从 0xFFFFFF 递减到 0xFFF000:0xFFFFFF - 0xFFF000 = 0x0FFF(4095 周期)
- 总周期 = 256 + 4095 = 4351 周期
- 掩码法结果误差:
0x001200 = 4608
≠ 4351(误差 257 周期)
结论:即使 LOAD=0xFFFFFF
,此方法仍存在误差,需进一步验证。
4. 正确性验证(修正逻辑)
实际正确算法应为:
周期差 = (LastTick >= CurrentVal) ? |
|
(LastTick - CurrentVal) : |
|
(LastTick + 0x1000000 - CurrentVal) |
- 当
LOAD=0xFFFFFF
,0x1000000
即 24 位模数。 - 示例修正:
LastTick=0x100
,CurrentVal=0xFFF000
周期差 =0x100 + 0x1000000 - 0xFFF000 = 0x100 + 0x1000 = 0x1100
(4352 周期)
(与实际 4351 周期误差 1,因未考虑从 0 到 0xFFFFFF 的重载周期)
5. 适用条件与限制
条件/限制 | 说明 |
---|---|
必须 LOAD=0xFFFFFF | 确保计数器周期与 24 位掩码的模数一致 |
误差来源 | 未计入从 0x000000 到 0xFFFFFF 的重载周期(偏差 ±1 周期) |
适用场景 | 对时间精度要求不严格(如粗略延时),且无法动态获取 LOAD 值的场合 |
不适用场景 | LOAD≠0xFFFFFF 或需高精度计时(如通信超时检测) |
6. 代码实现(LOAD=0xFFFFFF)
c
// 假设已设置 LOAD=0xFFFFFF |
|
uint32_t LastTick = SysTick->VAL; |
|
// ... 等待某些操作 |
|
uint32_t CurrentVal = SysTick->VAL; |
|
// 24位掩码法计算时间差 |
|
uint32_t elapsed = (LastTick - CurrentVal) & 0x00FFFFFF; |
|
// 等效正确计算(需 LOAD=0xFFFFFF) |
|
uint32_t elapsed_correct = (LastTick >= CurrentVal) ? |
|
(LastTick - CurrentVal) : |
|
(LastTick + 0x01000000 - CurrentVal); |
7. 总结
- 掩码法本质:将时间差计算转换为 24 位无符号数运算,依赖
LOAD=0xFFFFFF
保证周期性。 - 误差范围:±1 周期(因忽略重载时的
0xFFFFFF → 0x000000
跳变)。 - 推荐场景:仅当硬件强制
LOAD=0xFFFFFF
且对误差不敏感时使用,否则应使用 溢出感知算法。
正确方法选择优先级:
- 动态获取 LOAD + 溢出感知计算(通用、精确)
- 24 位掩码法(需严格满足
LOAD=0xFFFFFF
,快速但轻微误差)
验证
假设在lasttick=2,当tick递减到0随后继续递减,则nowtickvalue=0XFFFFFF,则此时计数值为0X2-0xFFFFFF=FF000003,这个值&0XFFFFFF,为3,计数值正确。