定时器A与B详解:Timer_A与Timer_B结构、捕获/比较模块、PWM生成、低功耗定时器应用

定时器,在嵌入式系统里就像人的心跳。没有它,系统就没了节奏。MSP430 的定时器模块,说实话,是我见过最灵活、最省电的硬件外设之一。今天咱们就把 Timer_A 和 Timer_B 掰开揉碎了讲清楚。

Timer_A 与 Timer_B 的核心差异

很多人刚接触 MSP430 时,会问:为什么要有两个定时器?直接用一个功能更强的不好吗?

我个人的理解是:TI 的设计思路是「按需分配」。Timer_A 是通用型,够用、省电、配置简单;Timer_B 则是为复杂应用准备的,比如电机控制、高精度 PWM。

特性 Timer_A Timer_B
计数器宽度 16 位 16 位(部分型号支持 20 位)
捕获/比较通道 最多 3 个 最多 7 个
比较寄存器影子 无 有(双缓冲)
输出模式 7 种 8 种
典型功耗 极低 略高

关键点:Timer_B 的「影子寄存器」是个好东西。你在更新比较值时,新值不会立即生效,而是等到计数器归零或达到周期值时才加载。这能避免 PWM 输出出现「毛刺」。我在做无刷电机驱动时,就靠这个特性避免了多次炸管。

捕获/比较模块:不只是数数

捕获和比较,其实是两个完全不同的功能,只是共用了一套硬件通道。

捕获模式

捕获模式用来测量外部信号的脉宽、周期或频率。当捕获引脚上出现指定的边沿(上升沿、下降沿或两者)时,定时器会把当前的计数值「冻结」到捕获寄存器里。

我曾经用 Timer_A 的捕获模式测量一个红外传感器的脉冲宽度。当时遇到一个坑:捕获中断里做了太多计算,导致下一次捕获事件丢失。后来我把数据扔进环形缓冲区,中断里只做标记,主循环再处理,问题就解决了。

// 捕获模式配置示例:捕获上升沿
TA0CCTL0 = CM_1 + SCS + CAP + CCIE;  // 上升沿捕获,同步,使能中断
TA0CTL = TASSEL_2 + MC_2 + TACLR;    // SMCLK,连续模式

比较模式

比较模式更常用。定时器计数器不断增长,当它等于比较寄存器中的值时,就会触发事件——比如翻转引脚、产生中断、或者改变输出电平。

说白了,这就是 PWM 和定时中断的基础。

PWM 生成:从原理到实战

PWM(脉宽调制)是定时器最广泛的应用之一。MSP430 的定时器可以输出硬件 PWM,不需要 CPU 干预,这对低功耗设计来说太重要了。

输出模式选择

Timer_A 支持 7 种输出模式,Timer_B 支持 8 种。最常用的是「复位/置位」模式(Reset/Set)和「置位/复位」模式(Set/Reset)。

  • 复位/置位:计数器等于 CCR0 时输出复位(低电平),等于 CCR1 时输出置位(高电平)。用于产生正极性 PWM。
  • 置位/复位:反过来,用于产生负极性 PWM。
  • 翻转/复位:适合产生 50% 占空比的对称波形。

我的习惯:做 LED 调光时,我通常用 Timer_A 的复位/置位模式,CCR0 设周期,CCR1 设占空比。这样改占空比只需要写 CCR1,周期不变,非常干净。

// PWM 配置示例:P1.2 输出 PWM,周期 1ms,占空比 50%
TA0CCR0 = 1000 - 1;                    // 周期值
TA0CCTL1 = OUTMOD_7;                   // 复位/置位模式
TA0CCR1 = 500;                         // 占空比值
TA0CTL = TASSEL_2 + MC_1 + TACLR;     // SMCLK,增计数模式
P1DIR |= BIT2;                         // P1.2 设为输出
P1SEL |= BIT2;                         // 选择定时器输出功能

低功耗定时器应用:让系统「睡」着干活

MSP430 的低功耗定时器,核心思想是:CPU 可以睡觉,但定时器不能停。

ACLK 与 LPM3 模式

ACLK 通常由 32.768kHz 晶振驱动,功耗极低。在 LPM3 模式下,CPU 和主时钟都停了,但 ACLK 还在跑,定时器依然可以工作。

我记得有个项目需要每隔 10 秒唤醒一次系统采集传感器数据。如果用主时钟定时,功耗根本压不下去。后来改用 ACLK 驱动的 Timer_A,LPM3 模式下整机功耗只有 2μA 左右。

// 低功耗定时配置:ACLK,LPM3 下运行
TA0CTL = TASSEL_1 + MC_1 + TACLR;     // ACLK,增计数模式
TA0CCR0 = 3277;                        // 10 秒中断(32768 / 3277 ≈ 10)
TA0CCTL0 = CCIE;                       // 使能中断
_BIS_SR(LPM3_bits + GIE);             // 进入 LPM3,全局中断使能

定时器分频与低功耗权衡

分频越大,定时器计数越慢,功耗越低,但分辨率也越低。你需要根据应用场景做权衡。

分频系数 ACLK 下计数频率 最大定时时间(16 位) 典型应用
1 32.768 kHz 2 秒 高精度测量
2 16.384 kHz 4 秒 通用定时
4 8.192 kHz 8 秒 传感器轮询
8 4.096 kHz 16 秒 超低功耗待机

避坑指南:我曾经在 LPM3 下用 Timer_A 做 1 小时定时,结果发现定时不准。查了半天,原来是 32.768kHz 晶振的温漂导致的。后来我改用内部 REFO 时钟,虽然精度差一点,但胜在稳定。如果你需要长时间精确定时,记得考虑晶振的温度特性。

Timer_A 与 Timer_B 的结构对比图

下面这张图是我自己总结的,把两个定时器的核心结构放在一起对比,方便你理解它们的异同。

Timer_A 与 Timer_B 结构对比 Timer_A 16 位计数器 3 个 CC 通道 7 种输出模式 无影子寄存器 Timer_B 16/20 位计数器 7 个 CC 通道 8 种输出模式 有影子寄存器 Timer_B 的影子寄存器能避免 PWM 更新时的毛刺 适合电机控制、高精度电源等对输出波形要求严苛的场景 Timer_A:通用定时、PWM、捕获 Timer_B:多通道 PWM、高精度控制 低功耗设计:ACLK + LPM3,定时器独立运行

实战建议:如何选择定时器

我个人的经验是:

  • 做传感器定时采集、LED 调光、简单 PWM:用 Timer_A 就够了,省电、配置快。
  • 做电机控制、多路 PWM、需要高精度同步:上 Timer_B,影子寄存器能省掉很多麻烦。
  • 低功耗待机场景:优先用 ACLK 驱动的 Timer_A,LPM3 模式下功耗可以做到 1μA 以下。

最后说一句:定时器的配置看似复杂,但只要你理解了「计数器 + 比较器 + 输出模式」这个核心逻辑,剩下的就是查数据手册填寄存器了。别怕,多试几次就熟了。