第二章 TOM模块详解:TOM通道结构、信号路由、单次与连续比较模式
好,咱们接着聊TOM模块。说实话,TC3xx里这么多定时器模块,TOM是我用得最多的一个。为什么?因为它够灵活,够简单。你想想看,做PWM输出、做步进电机控制、做简单的时序生成,TOM几乎都能搞定。我有个项目,用TOM驱动了8路伺服电机,一路都没出过问题。
2.1 TOM通道结构——每个通道都是一个独立的小世界
每个TOM通道,说白了就是一个独立的PWM发生器。它有自己的计数器、比较寄存器、输出控制逻辑。我个人习惯把TOM通道想象成一个“迷你CPU”——它只干一件事,就是比较和翻转。
来看核心结构:
- 计数器(CN0):从0开始往上数,数到某个值就重置。这个值由SL(Signal Level)寄存器决定。
- 比较寄存器(CM0、CM1):两个比较点。一个决定什么时候翻转输出,一个决定什么时候重置计数器。
- 输出控制:根据比较结果,决定输出是高电平还是低电平。
嗯,这里要注意:每个通道的计数器是独立的,但时钟源可以共享。我在项目中遇到过一个问题,就是多个通道共用一个时钟源,结果某个通道的计数器跑偏了。后来发现是时钟分频没配好,导致计数器溢出时间不一致。
核心要点:TOM通道的计数器是16位的,最大值65535。如果你需要更长的周期,可以考虑用多个通道级联,或者用ARU(Advanced Routing Unit)做扩展。
2.2 信号路由——怎么把TOM的输出送到正确的地方
信号路由这块,说实话,刚开始看手册的时候我也懵。TOM的输出不是直接到GPIO的,中间要经过好几层。我画了个简化的路径:
TOM通道输出 → TOM输出多路选择器 → TBU(Timer Bus Unit) → 端口输出控制 → GPIO引脚
为什么要这么绕?因为TC3xx的引脚复用太多了。一个引脚可能同时被好几个模块抢着用。所以你得明确告诉芯片:这个TOM通道的输出,要走哪条路到哪个引脚。
我建议你记住这几个关键寄存器:
| 寄存器 | 作用 | 我的经验 |
|---|---|---|
| TOM_CHx_CTRL | 通道控制,选择输出模式 | 记得把SL位配好,否则输出可能一直为0 |
| TOM_TGCx_GLB_CTRL | 全局控制,使能/禁止通道组 | 我曾经忘了使能这个,折腾了半天 |
| PORT_IOCR0 | 端口输出控制,选择复用功能 | 这个最容易漏,配完TOM还得配端口 |
小技巧:调试信号路由时,可以先配一个简单的PWM输出,用示波器看引脚。如果没波形,八成是路由没配通。我一般从TOM通道开始,一级一级往上查。
2.3 单次比较模式——简单粗暴,适合一次性任务
单次比较模式,说白了就是计数器只跑一次。计数器从0开始,数到CM0的值就翻转输出,数到CM1的值就停止。嗯,这个模式适合什么场景?比如你只需要产生一个单脉冲,或者做一次延时触发。
配置代码示例:
// 配置TOM通道0为单次比较模式
TOM_CH0_CTRL = 0x0000; // 先复位通道控制
TOM_CH0_CTRL_B.MODE = 0x01; // 设置为单次比较模式
TOM_CH0_CTRL_B.SL = 0x01; // 输出极性:高电平有效
TOM_CH0_CM0 = 1000; // 第一个比较点:1000个时钟周期后翻转
TOM_CH0_CM1 = 2000; // 第二个比较点:2000个时钟周期后停止
TOM_CH0_CTRL_B.ENDIS = 0x01; // 使能通道
我在项目中用过这个模式做电机启动的软启动。一开始给一个窄脉冲,然后慢慢加宽。单次模式的好处是,你不需要一直盯着计数器,它跑完就停,省CPU资源。
避坑指南:我曾经在单次模式下忘了重置计数器,结果第二次触发时,计数器从上次停止的地方继续跑。输出完全乱套了。所以每次触发前,记得把CN0清零。
2.4 连续比较模式——PWM的标配,永不停歇
连续比较模式,就是计数器一直循环。从0数到CM1,然后重置,再数。这个模式是PWM的标配。你想想看,电机控制、LED调光、开关电源,哪个不是靠连续PWM?
配置代码示例:
// 配置TOM通道1为连续比较模式
TOM_CH1_CTRL = 0x0000;
TOM_CH1_CTRL_B.MODE = 0x02; // 连续比较模式
TOM_CH1_CTRL_B.SL = 0x01; // 输出极性
TOM_CH1_CM0 = 500; // 占空比:500/1000 = 50%
TOM_CH1_CM1 = 1000; // 周期:1000个时钟周期
TOM_CH1_CTRL_B.ENDIS = 0x01; // 使能
这里有个关键点:CM0决定占空比,CM1决定周期。你可以在运行时动态修改CM0,实现占空比调节。我做过一个呼吸灯效果,就是每隔10ms改一次CM0,从0慢慢增加到CM1,再慢慢减回来。
为什么会这样?因为连续模式下,计数器每到一个周期结束,会自动加载新的CM0值。所以你改完CM0,下一个周期就生效了。不需要停掉通道再重启。
性能提示:连续模式下,CM0和CM1的更新时机很重要。我建议在计数器溢出中断里更新,这样能保证同步。否则你改CM0的时候,计数器刚好过了比较点,那这个周期的占空比就错了。
2.5 两种模式的对比——什么时候该用哪个?
我整理了个对比表,方便你快速决策:
| 特性 | 单次比较模式 | 连续比较模式 |
|---|---|---|
| 计数器行为 | 跑一次就停 | 一直循环 |
| 典型应用 | 单脉冲、延时触发 | PWM、周期信号 |
| CPU干预 | 每次触发需要重新启动 | 自动运行,无需干预 |
| 占空比调节 | 每次都要重新配置 | 运行时动态修改CM0即可 |
| 我的推荐 | 一次性任务,比如点火信号 | 周期性任务,比如电机控制 |
嗯,其实还有个隐藏模式——单次触发连续模式。这个模式我用的不多,但有个场景很合适:你希望PWM在某个外部事件触发后才开始跑。比如传感器检测到物体,然后PWM才开始输出。这个模式结合了单次的触发方式和连续的运行方式。
个人经验:如果你不确定用哪个模式,先选连续模式。因为连续模式可以模拟单次模式(通过软件控制使能位),但反过来不行。我刚开始做项目时,就因为这个吃了亏。
2.6 实战中的坑——我踩过的那些雷
最后分享几个我实际项目中遇到的坑,希望能帮你少走弯路:
- 时钟源没配好:TOM的时钟源来自CMU(Clock Management Unit)。我有个项目,TOM输出频率一直不对,查了半天发现是CMU的时钟分频配错了。记住:TOM的时钟源要先使能,再分频。
- 输出极性搞反:SL位控制输出极性。0是低电平有效,1是高电平有效。我有个同事,配成了0,结果PWM输出一直是低电平,他以为是芯片坏了。
- 中断标志没清:TOM通道有中断标志位,触发后要手动清除。我曾经忘了清标志,结果中断服务函数一直进,CPU跑飞了。
- 多通道同步问题:如果你用多个TOM通道做同步输出,记得用TGC(Timer Gating Control)做同步启动。否则每个通道的启动时间可能差几个时钟周期。
好了,TOM模块的核心内容就这些。下一章咱们聊ATOM模块,那个更复杂,但也更强大。到时候我会分享一个用ATOM做步进电机加减速控制的实战案例,保证让你收获满满。