4. 定时器与PWM输出

在STM32的智能终端产品中,定时器是最“忙碌”的外设之一:它既负责产生精确的时间基准,又负责输出PWM波形驱动LED调光、蜂鸣器发声、电机调速。理解定时器的分类与PWM生成机制,是嵌入式图形界面产品实现声光反馈的基础。本节从定时器结构出发,逐步落到呼吸灯与蜂鸣器两个典型应用。

一、STM32定时器的分类与能力边界

STM32F1系列通常包含基本定时器(TIM6、TIM7)、通用定时器(TIM2~TIM5)和高级定时器(TIM1、TIM8)。三者的核心差异在于功能丰富度:

  • 基本定时器:只有计数器和自动重装载寄存器,能产生更新中断和触发DAC,没有外部引脚输出,适合做纯定时任务。
  • 通用定时器:在基本定时器基础上增加输入捕获、输出比较、PWM输出、编码器接口,拥有4个独立通道,是呼吸灯和蜂鸣器驱动的主力。
  • 高级定时器:在通用定时器基础上增加互补输出、死区插入、刹车输入,面向电机控制,本节的简单应用暂不涉及。

选择原则很直接:只需要定时中断就用基本定时器;需要引脚输出波形就用通用定时器;需要驱动三相桥或带死区互补信号才用高级定时器。

二、定时器的时间基准:从时钟到周期

定时器的核心是一个向上计数的计数器CNT,它从0累加到自动重装载寄存器ARR的值,然后溢出并重新开始。计数速度由预分频器PSC决定。若定时器时钟为72MHz,PSC=71,则计数频率为72MHz/(71+1)=1MHz,即每1μs计数一次。此时若ARR=999,则溢出周期为(999+1)×1μs=1ms,对应1kHz的更新频率。

这个关系可以写成两个公式:

计数频率 f_CNT = f_TIM / (PSC + 1)
溢出周期 T = (ARR + 1) / f_CNT = (ARR + 1) × (PSC + 1) / f_TIM

PWM模式下,ARR决定PWM周期,比较寄存器CCR决定高电平时间,占空比 = CCR / (ARR + 1)。例如ARR=999、CCR=300时,占空比为30%。改变CCR即可改变亮度或音调,而无需改动ARR。

通用定时器PWM生成链路与占空比关系 TIMxCLK 72 MHz PSC 预分频 PSC=71 → 1 MHz CNT 计数器 0 → ARR CCR 比较 CNT < CCR ? TIMx_CH 引脚输出 PWM波形(ARR=999) CCR=300 → 30% CCR=700 → 70% 呼吸灯:CCR 0→999→0 循环 暗 → 亮 → 暗(占空比连续变化)

三、PWM模式配置的关键步骤

以TIM3通道1(PA6)输出PWM为例,配置流程如下:

  1. 使能TIM3和GPIOA时钟,将PA6配置为复用推挽输出。
  2. 设置PSC和ARR,确定PWM频率。若目标频率为1kHz,取PSC=71、ARR=999。
  3. 将通道1配置为PWM模式1(OC1M=110),使能预装载(OC1PE=1),这样CCR的修改在更新事件时生效,避免波形出现毛刺。
  4. 设置初始CCR值,调用TIM_Cmd使能定时器,再调用TIM_CtrlPWMOutputs(高级定时器需要,通用定时器可省略)。

需要特别注意的是:修改CCR时若未使能预装载,新值会立即写入,可能导致当前周期出现异常窄脉冲。对于呼吸灯这种连续调光的场景,建议开启预装载,让亮度变化平滑。

四、呼吸灯实现:用CCR做渐变

呼吸灯的本质是让LED的亮度按正弦或三角规律缓慢变化。由于人眼对亮度感知近似对数关系,直接线性改变CCR会显得“中间亮、两头变化快”,实际产品中常用查表法或指数曲线修正。

一个简单可行的实现思路是:在1ms的定时中断中维护一个方向变量,每次让CCR加1或减1,到达0或999时翻转方向。这样呼吸周期约为2秒。示例代码片段:

// 1ms 定时中断内
static int16_t ccr = 0;
static int8_t  dir = 1;
ccr += dir;
if (ccr >= 999) { ccr = 999; dir = -1; }
if (ccr <= 0)   { ccr = 0;   dir = 1;  }
TIM_SetCompare1(TIM3, ccr);

观察结果时,用示波器看PA6引脚,应看到占空比从0%缓慢升到100%再降回0%的连续波形;用肉眼观察LED,应呈现均匀的明暗呼吸,而不是跳变。若发现亮度变化集中在两端,说明需要改用正弦表或伽马校正。

五、蜂鸣器驱动:频率决定音调

蜂鸣器分有源和无源两种。有源蜂鸣器内部自带振荡电路,给高电平就响,音调固定;无源蜂鸣器需要外部提供方波,频率决定音调。智能终端产品中常用无源蜂鸣器实现按键音、报警音等不同提示音。

驱动无源蜂鸣器时,PWM频率应设置在2kHz~4kHz之间,这是人耳最敏感的频段。例如要发出2.7kHz的提示音,取PSC=0、ARR=26666(72MHz/26666≈2.7kHz),占空比设为50%即可获得最大响度。若要播放不同音调,只需在定时中断中按节拍切换ARR值。

无源蜂鸣器不能直接接在GPIO上驱动,因为引脚驱动电流有限。建议使用三极管或MOS管扩流,并在蜂鸣器两端反向并联续流二极管,抑制关断瞬间的反向电动势。

六、参数选择与常见问题

现象可能原因处理方向
PWM无输出GPIO未配置为复用模式,或定时器未使能检查GPIO_Mode和TIM_Cmd
频率偏差大PSC/ARR计算错误,或时钟源不是72MHz核对SystemCoreClock与分频值
呼吸灯有跳变CCR未开预装载,或步进过大开启OC1PE,减小步进
蜂鸣器声音小占空比偏离50%,或驱动电流不足调整CCR,增加三极管驱动

最后强调一个工程习惯:在图形界面产品中,呼吸灯和蜂鸣器往往与UI刷新、触摸检测共存。建议把PWM更新放在定时中断里完成,主循环只负责设置目标亮度和音调,避免在UI线程中直接操作CCR造成时序抖动。这样既保证了声光反馈的实时性,也不会拖慢界面响应。