You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Cortex-M4单片机中用C计算定时器Ticks避免溢出的正确方法

解决Cortex-M4下SysTick定时器Ticks计算的溢出与浮点运算问题

问题描述

我需要计算运行在freq(单位Hz)下的SysTick定时器产生delay(单位ms)所需的ticks,理论公式为 ticks = freq * delay / 1000。但直接按此顺序计算容易发生32位无符号整数溢出;如果调整为freq * (delay / 1000)又会引入不必要且易出错的浮点运算。代码运行于Cortex-M4 ARM单片机,所有变量均为uint32_t或volatile uint32_t,请问如何用C语言通过纯整数运算正确实现,同时避免溢出?


方法1:利用64位中间变量(推荐,最直接高效)

Cortex-M4内核原生支持64位整数运算(ARMv7-M架构包含64位乘法指令),因此可以先将32位变量提升为64位完成乘法,再做除法,最后转回32位。这种方法完全规避浮点运算,且溢出风险为零(只要最终结果在uint32_t范围内,而SysTick的24位计数器天然限制了ticks最大值为0xFFFFFF,肯定满足)。

代码实现:

#include <stdint.h>

uint32_t calculate_systick_ticks(uint32_t freq, uint32_t delay_ms) {
    uint64_t temp = (uint64_t)freq * delay_ms;
    return (uint32_t)(temp / 1000);
}

说明

  • 强制将freq转为uint64_t后,乘法运算会以64位精度执行,彻底避免32位乘法的溢出问题。
  • Cortex-M4的硬件指令支持64位乘除的核心操作,性能损失可以忽略。

方法2:通过最大公约数(GCD)约分(无64位依赖时备选)

如果出于特殊限制不能使用64位整数(尽管Cortex-M4支持),可以先对freq和1000求最大公约数,通过约分缩小乘法操作数的规模,降低溢出概率。

代码实现:

#include <stdint.h>

// 欧几里得算法计算最大公约数
static uint32_t gcd(uint32_t a, uint32_t b) {
    while (b != 0) {
        uint32_t temp = b;
        b = a % b;
        a = temp;
    }
    return a;
}

uint32_t calculate_systick_ticks(uint32_t freq, uint32_t delay_ms) {
    uint32_t common_divisor = gcd(freq, 1000);
    uint32_t scaled_freq = freq / common_divisor;
    uint32_t scaled_divisor = 1000 / common_divisor;
    // 约分后乘法溢出概率大幅降低
    return (scaled_freq * delay_ms) / scaled_divisor;
}

说明

  • 例如,当freq为168MHz(168000000)时,与1000的最大公约数是200,约分后scaled_freq为840000,scaled_divisor为5,此时840000 * delay_ms的溢出风险远低于原始的168000000 * delay_ms。

额外优化:SysTick范围校验

由于SysTick的重载寄存器是24位(最大值为0xFFFFFF),可以在函数中增加校验,确保返回值不超出硬件限制:

uint32_t calculate_systick_ticks(uint32_t freq, uint32_t delay_ms) {
    uint64_t temp = (uint64_t)freq * delay_ms;
    uint32_t ticks = (uint32_t)(temp / 1000);
    return (ticks > 0xFFFFFF) ? 0xFFFFFF : ticks;
}

内容的提问来源于stack exchange,提问作者SRobertJames

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 21:45:08