第四章 TIM模块详解:TIM通道结构、输入捕获模式、滤波与消抖
好,咱们进入TIM模块。说实话,TIM在GTM里是个特别实在的模块。它不像TOM那样要输出PWM,也不像ATOM那样搞复杂的序列。TIM的核心任务就一个——把外部信号读进来,搞清楚它是什么情况。
我刚开始接触TC3xx时,觉得TIM不就是个输入捕获嘛,有啥好讲的?后来做项目才发现,TIM的滤波和消抖功能,才是真正体现功力的地方。你想想看,如果信号进来全是毛刺,你捕获到的数据根本没法用。
4.1 TIM通道结构概览
每个TIM模块有8个通道,每个通道都是独立的。我习惯把TIM通道想象成一个信号处理流水线:
- 信号从外部引脚进来
- 经过滤波和消抖处理
- 进入捕获逻辑
- 最终产生时间戳数据
每个通道的核心寄存器就那么几个:
| 寄存器 | 功能 | 我常用的配置 |
|---|---|---|
| TIM_CHx_CTRL | 控制寄存器,配置模式、边沿、滤波等 | 这个寄存器我几乎每个项目都要反复调 |
| TIM_CHx_IRQ | 中断控制 | 一般用上升沿触发中断 |
| TIM_CHx_ECNT | 事件计数器 | 调试时看这个值就知道信号有没有进来 |
| TIM_CHx_CNTS | 捕获的时间戳 | 核心数据,做速度测量全靠它 |
嗯,这里要注意:TIM通道的时钟源是CMU_CLK0,默认频率是fGTM/2。我有个项目因为没注意时钟分频,导致捕获精度差了整整一倍,排查了半天才发现。
4.2 输入捕获模式
输入捕获,说白了就是记录信号边沿到来的时刻。TIM支持三种捕获模式:
- 单次捕获:只捕获一次,适合测量单个脉冲宽度
- 连续捕获:每次边沿都捕获,适合测量周期
- 多事件捕获:可以同时捕获上升沿和下降沿,适合测量占空比
我一般用连续捕获模式做转速测量。举个例子,你要测一个风扇的转速:
// 配置TIM通道0为连续捕获模式,上升沿触发
TIM_CH0_CTRL.B.MODE = 0x02; // 连续捕获
TIM_CH0_CTRL.B.EDGE = 0x01; // 上升沿
TIM_CH0_CTRL.B.DSL = 0x01; // 使能捕获
// 使能中断
TIM_CH0_IRQ.B.EN = 1;
// 在中断服务函数中读取时间戳
uint32_t timestamp = TIM_CH0_CNTS.U;
// 计算转速:转速 = 60 / (timestamp * 时钟周期)
这里有个坑——连续捕获模式下,CNTS寄存器是只读的。你读一次,它就会自动清零。所以一定要在中断里第一时间把值读出来,不然就丢了。我曾经因为这个丢数据,查了整整一个下午。
关键点:TIM的捕获是基于GTM的系统时钟,精度可以达到一个时钟周期。但要注意,如果信号频率太高,超过了TIM的处理能力,就会丢事件。我一般建议信号频率不要超过fGTM/4。
4.3 滤波与消抖
这才是TIM模块的精髓。你想想看,实际工程中的信号哪有那么干净?电机启动时的干扰、按键按下时的抖动、通信线上的毛刺……如果不做处理,捕获到的数据全是错的。
TIM提供了两级滤波:
- 第一级:边沿滤波(EDGE_FILTER)
- 第二级:时间滤波(TIME_FILTER)
我习惯把第一级叫硬滤波,第二级叫软滤波。为什么这么叫?因为第一级是纯硬件实现的,不消耗CPU;第二级需要配合中断,会占用CPU时间。
4.3.1 边沿滤波(EDGE_FILTER)
边沿滤波的原理很简单:只有信号稳定超过N个时钟周期,才认为边沿有效。TIM支持1到32个时钟周期的滤波长度。
// 配置边沿滤波,滤波长度为8个时钟周期
TIM_CH0_CTRL.B.EDGE_FILTER = 0x03; // 8个时钟周期
TIM_CH0_CTRL.B.EDGE_FILTER_EN = 1; // 使能滤波
我在做汽车电子项目时,遇到过一种情况:信号线上有200ns左右的毛刺。当时我设了4个时钟周期的滤波(约100ns),毛刺就被滤掉了。但要注意,滤波长度设太大,会丢失真正的信号。这个平衡点需要根据实际信号质量来调。
我的经验:调试滤波参数时,先用示波器看信号质量。如果毛刺宽度是T,滤波长度设成1.5T到2T比较合适。别设太大,否则信号延迟会很明显。
4.3.2 时间滤波(TIME_FILTER)
时间滤波更高级一些。它不是简单地滤毛刺,而是基于时间窗口来判断信号是否有效。你可以设置一个时间窗口,只有在这个窗口内出现的边沿才被捕获。
这个功能在测量PWM占空比时特别有用。比如你要测量一个50Hz的PWM信号,可以设置时间窗口为20ms,这样就能避免其他干扰信号被误捕获。
// 配置时间滤波,窗口长度为1000个时钟周期
TIM_CH0_CTRL.B.TIME_FILTER = 0x01; // 使能时间滤波
TIM_CH0_CTRL.B.TIME_FILTER_LEN = 1000; // 窗口长度
注意:时间滤波和边沿滤波可以同时使用。但要注意,同时使用会增加信号延迟。我有个项目因为同时用了两级滤波,信号延迟了将近1ms,导致控制环路响应变慢。后来我只用了边沿滤波,效果反而更好。
4.4 实际应用中的避坑指南
做TIM开发这几年,我踩过的坑真不少。挑几个典型的说说:
- 中断优先级:TIM中断优先级不要设太高,否则会影响其他实时任务。我一般设成中等优先级。
- 时钟同步:如果多个TIM通道要同步捕获,记得用同一个时钟源。我有个项目因为用了不同时钟源,导致两个通道的时间戳差了十几个时钟周期。
- 滤波参数调试:先在仿真器里看原始信号,再逐步加大滤波参数。别一上来就设最大值,那样信号延迟会让你怀疑人生。
我曾经在一个电机控制项目里,因为滤波参数设得太大,导致转速测量延迟了2ms。电机在低速时还好,一加速就振荡。后来我把滤波长度从16个时钟周期降到4个,问题就解决了。嗯,这个教训让我记住了——滤波不是越强越好,够用就行。
4.5 小结
TIM模块看似简单,但用好了能解决很多实际问题。我个人觉得,掌握TIM的关键在于理解它的信号处理流水线——信号进来后,先滤波,再捕获,最后产生中断。每一步都有讲究,每一步都可能出问题。
下一章咱们讲TOM模块,那是输出PWM的核心。到时候你会发现,TIM和TOM配合起来用,能实现很多复杂的时序控制。