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模式配置的关键步骤
以TIM3通道1(PA6)输出PWM为例,配置流程如下:
- 使能TIM3和GPIOA时钟,将PA6配置为复用推挽输出。
- 设置PSC和ARR,确定PWM频率。若目标频率为1kHz,取PSC=71、ARR=999。
- 将通道1配置为PWM模式1(OC1M=110),使能预装载(OC1PE=1),这样CCR的修改在更新事件时生效,避免波形出现毛刺。
- 设置初始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值。
六、参数选择与常见问题
| 现象 | 可能原因 | 处理方向 |
|---|---|---|
| PWM无输出 | GPIO未配置为复用模式,或定时器未使能 | 检查GPIO_Mode和TIM_Cmd |
| 频率偏差大 | PSC/ARR计算错误,或时钟源不是72MHz | 核对SystemCoreClock与分频值 |
| 呼吸灯有跳变 | CCR未开预装载,或步进过大 | 开启OC1PE,减小步进 |
| 蜂鸣器声音小 | 占空比偏离50%,或驱动电流不足 | 调整CCR,增加三极管驱动 |
最后强调一个工程习惯:在图形界面产品中,呼吸灯和蜂鸣器往往与UI刷新、触摸检测共存。建议把PWM更新放在定时中断里完成,主循环只负责设置目标亮度和音调,避免在UI线程中直接操作CCR造成时序抖动。这样既保证了声光反馈的实时性,也不会拖慢界面响应。