定时器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 的结构对比图
下面这张图是我自己总结的,把两个定时器的核心结构放在一起对比,方便你理解它们的异同。
实战建议:如何选择定时器
我个人的经验是:
- 做传感器定时采集、LED 调光、简单 PWM:用 Timer_A 就够了,省电、配置快。
- 做电机控制、多路 PWM、需要高精度同步:上 Timer_B,影子寄存器能省掉很多麻烦。
- 低功耗待机场景:优先用 ACLK 驱动的 Timer_A,LPM3 模式下功耗可以做到 1μA 以下。
最后说一句:定时器的配置看似复杂,但只要你理解了「计数器 + 比较器 + 输出模式」这个核心逻辑,剩下的就是查数据手册填寄存器了。别怕,多试几次就熟了。