输入捕获测频率不准?别只算差值,看看溢出与噪声
摘要:TIM 输入捕获测频率,示波器看是 1kHz,代码算出来 980Hz 甚至 1200Hz?不是信号问题,而是计数器溢出(Overflow)处理不当或噪声导致重复捕获。本文给出工程级的计算模型。
一、问题描述(现象)
**用 TIM 输入捕获测 PWM 频率;
示波器稳定 1kHz,串口打印的值却在 990~1010 Hz 跳动;
频率越低,误差越大。**
很多工程师的排查方向是:
-
晶振不准?
-
公式写错了?
-
换个 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 值自动搬运到内存。
-
软件只做平均滤波。
-
避免中断响应时间带来的抖动。
四、选型避坑建议
-
不要用 16 位 TIM 测超低频:
-
1MHz 时钟 + 16 位 ARR,最长只能测 65ms(约 15Hz)。
-
-
通道映射:
-
测频率用 CH1/CH2。
-
测占空比才需要 CH1 + CH2 交叉捕获。
-
-
极性选择:
-
默认选 上升沿。
-
如果信号有振铃,改为下降沿可能更稳定。
-
五、总结 Checklist
-
[ ] 是否在计算公式中考虑了溢出次数?
-
[ ] 是否开启了输入捕获滤波器(ICFilter)?
-
[ ] 是否在中断中正确处理了溢出标志?
-
[ ] 被测信号频率是否低于 TIM 的理论下限?
六、写在最后(关注我,少走弯路)
我是 gqqsherry,一个拒绝调包、专注底层逻辑的嵌入式工程师。
TIM 输入捕获是“看起来简单,调起来想摔示波器”的典型外设。
关注我的专栏《嵌入式底层避坑指南》,下一篇我们将深入解析 《DMA + TIM 触发异常?别只怪时钟,看看 Update 与 TRGO》。
👉 下一篇预告:《DMA 搬运 ADC 数据总错位?别只怪指针,看看 TIM 的触发源》
原创文章,转载请注明出处。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)