摘要:TIM 输入捕获测频率,示波器看是 1kHz,代码算出来 980Hz 甚至 1200Hz?不是信号问题,而是计数器溢出(Overflow)处理不当或噪声导致重复捕获。本文给出工程级的计算模型。


一、问题描述(现象)

**用 TIM 输入捕获测 PWM 频率;

示波器稳定 1kHz,串口打印的值却在 990~1010 Hz 跳动;

频率越低,误差越大。**

很多工程师的排查方向是:

  1. 晶振不准?

  2. 公式写错了?

  3. 换个 TIM 试试?


二、原理分析

1. 物理模型

输入捕获本质是测量两个边沿之间的计数值

CNT: 0 -> 1000 -> 2000 -> OVERFLOW -> 500
              ↑                ↑
           第一次捕获         第二次捕获

2. 核心参数

  • TIM_CLK:定时器时钟(如 1MHz)。

  • ARR:自动重装值(如 65535)。

  • IC_Value:捕获寄存器值。

3. 反直觉真相

频率 = TIM_CLK / IC_Value 这个公式只在“无溢出”时成立。

实际情况是:

  • 低频信号(< 100Hz)必然发生多次溢出。

  • 高频信号(> 10kHz)容易受噪声影响,触发多次捕获。


三、工程级解决方案

方案 1:正确处理溢出(必须做)

计算频率的标准公式:

// diff = (overflow_count * (ARR + 1)) + (IC2 - IC1)
uint32_t diff;
if (IC2 >= IC1) {
    diff = IC2 - IC1;
} else {
    diff = (overflow_count * (ARR + 1)) + IC2 - IC1;
}
float freq = (float)TIM_CLK / diff;

关键:​ 必须在 Update 中断里维护 overflow_count

方案 2:开启数字滤波(消抖神器)

TIM 自带输入滤波,不依赖软件消抖。

// STM32 HAL 示例
TIM_IC_InitTypeDef sConfigIC;
sConfigIC.ICFilter = 4; // 采样频率 = fCK_INT / (2*N)

经验值:

  • 1kHz 信号:ICFilter = 4~8

  • 10kHz 信号:ICFilter = 0~2

方案 3:使用 DMA 搬运(高阶)

对于高频信号:

  • 配置 DMA 将 CCR 值自动搬运到内存。

  • 软件只做平均滤波。

  • 避免中断响应时间带来的抖动。


四、选型避坑建议

  1. 不要用 16 位 TIM 测超低频

    • 1MHz 时钟 + 16 位 ARR,最长只能测 65ms(约 15Hz)。

  2. 通道映射

    • 测频率用 CH1/CH2

    • 测占空比才需要 CH1 + CH2​ 交叉捕获。

  3. 极性选择

    • 默认选 上升沿

    • 如果信号有振铃,改为下降沿可能更稳定。


五、总结 Checklist

  • [ ] 是否在计算公式中考虑了溢出次数?

  • [ ] 是否开启了输入捕获滤波器(ICFilter)?

  • [ ] 是否在中断中正确处理了溢出标志?

  • [ ] 被测信号频率是否低于 TIM 的理论下限?


六、写在最后(关注我,少走弯路)

我是 gqqsherry,一个拒绝调包、专注底层逻辑的嵌入式工程师。

TIM 输入捕获是“看起来简单,调起来想摔示波器”的典型外设。

关注我的专栏《嵌入式底层避坑指南》,下一篇我们将深入解析 《DMA + TIM 触发异常?别只怪时钟,看看 Update 与 TRGO》

👉 下一篇预告:《DMA 搬运 ADC 数据总错位?别只怪指针,看看 TIM 的触发源》

原创文章,转载请注明出处。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐