定时器基础:STM32定时器家族
说到定时器,我刚开始学STM32时也觉得挺简单的——不就是计时嘛。后来做项目才发现,这玩意儿的水比想象中深得多。你想想看,一个电机控制项目,PWM频率不对,电机就嗡嗡响;一个脉冲采集项目,输入捕获没配好,数据全乱套。嗯,今天我们就把它彻底搞明白。
STM32定时器家族
STM32的定时器分三类:基本定时器、通用定时器、高级定时器。它们的关系有点像汽车——基本型是代步车,通用型是家用SUV,高级型就是带越野套装的顶配版。
| 类型 | 典型型号 | 主要功能 | 适用场景 |
|---|---|---|---|
| 基本定时器 | TIM6、TIM7 | 基础计时、触发DAC | 定时中断、软件延时 |
| 通用定时器 | TIM2~TIM5 | PWM、输入捕获、输出比较 | 电机控制、信号测量 |
| 高级定时器 | TIM1、TIM8 | 互补PWM、刹车功能、死区插入 | 三相电机、电源变换 |
核心区别一句话:基本定时器只能向上计数;通用定时器可以向上/向下/中央对齐计数;高级定时器在通用基础上多了互补输出和刹车控制。
我个人习惯,做普通LED呼吸灯用通用定时器就够了。但如果你要驱动无刷电机,必须上高级定时器——它的死区插入功能是硬件级的,软件模拟根本做不到那么精准。
定时器时钟源与时基单元
定时器要工作,首先得有时钟。STM32的定时器时钟源有几种选择:
- 内部时钟(CK_INT)——来自APB总线,最常用
- 外部时钟模式1(TIx)——从GPIO引脚输入
- 外部时钟模式2(ETR)——专用外部触发引脚
- 内部触发(ITRx)——其他定时器级联
我在项目中遇到过一个问题:用外部脉冲计数时,信号频率太高导致漏计数。后来查手册才发现,外部时钟模式1的最大频率不能超过APB时钟的1/4。这个坑,我踩过一次就记住了。
时基单元是定时器的核心,它由三个寄存器组成:
- 预分频器(PSC)——对时钟分频,16位,范围0~65535
- 自动重装载寄存器(ARR)——决定计数周期
- 计数器(CNT)——当前计数值
计算公式很简单:
定时频率 = 时钟频率 / (PSC + 1) / (ARR + 1)
定时周期 = 1 / 定时频率
举个例子,APB时钟72MHz,要产生1ms中断:
PSC = 71 // 72MHz / (71+1) = 1MHz
ARR = 999 // 1MHz / (999+1) = 1kHz → 1ms
小技巧:PSC和ARR都是16位寄存器,最大值65535。如果你需要很长的定时时间,可以考虑用定时器级联——把两个定时器串起来用。我做过一个项目需要定时1小时,就是用TIM2和TIM5级联实现的。
PWM与输入捕获概念
这两个功能是定时器最常用的外设接口。说白了,PWM是定时器往外发信号,输入捕获是定时器往里收信号。
PWM(脉冲宽度调制)
PWM的核心思想:通过调节高电平占整个周期的比例(占空比),来模拟不同的电压值。频率固定,占空比可变。
STM32的PWM生成原理:
- 计数器CNT从0开始向上计数
- 当CNT < CCR(捕获比较寄存器)时,输出高电平
- 当CNT >= CCR时,输出低电平
- CNT达到ARR后归零,重新开始
占空比 = CCR / (ARR + 1) × 100%
// LL库配置PWM示例
LL_TIM_EnableCounter(TIM2);
LL_TIM_OC_EnablePreload(TIM2, LL_TIM_CHANNEL_CH1);
LL_TIM_OC_SetCompareCH1(TIM2, 500); // 50%占空比(假设ARR=999)
注意:修改占空比时,一定要在更新事件之后修改,否则会出现输出异常。我曾经在中断里直接改CCR,结果波形乱跳了半个周期。正确的做法是等定时器溢出中断标志位置位后再修改。
输入捕获
输入捕获是用来测量外部信号的。它可以捕获到外部信号的上升沿或下降沿,并记录下当时的CNT值。通过两次捕获的差值,就能算出信号的周期或脉宽。
典型应用场景:
- 测量PWM信号的频率和占空比
- 编码器转速测量
- 超声波测距(测量回波脉宽)
输入捕获的配置步骤:
- 设置GPIO为复用功能输入
- 配置定时器的捕获通道(选择上升沿/下降沿)
- 使能捕获中断
- 在中断中读取CCR值并计算
// LL库配置输入捕获示例
LL_TIM_IC_Config(TIM3, LL_TIM_CHANNEL_CH1,
LL_TIM_ACTIVEINPUT_TI1FP1,
LL_TIM_IC_POLARITY_RISING,
LL_TIM_IC_PRESCALER_DIV1,
LL_TIM_IC_FILTER_FDIV1);
LL_TIM_EnableIT_CC1(TIM3);
LL_TIM_EnableCounter(TIM3);
经验之谈:输入捕获的滤波器参数很关键。如果信号有毛刺,建议开启数字滤波(ICF字段)。我做过一个项目,编码器信号线长了之后有抖动,开了4级滤波就稳了。但滤波级别越高,信号延迟越大,这个要权衡。
定时器知识体系总览
下面这张图把本章的核心知识点串起来了,你可以对照着理解:
这张图把定时器从分类到时基单元,再到PWM和输入捕获,最后到应用场景的完整链路展示出来了。你写代码的时候,脑子里要有这张图——知道自己现在配置的是哪个模块,它跟其他模块是什么关系。
我的建议:刚开始学的时候,别急着把所有功能都试一遍。先拿通用定时器做一个PWM呼吸灯,再做一个输入捕获测频率。这两个实验做通了,定时器这块你就入门了。剩下的高级功能,遇到具体项目再查手册也来得及。