定时器基础 
Author:余生
一、引入:为什么需要定时器? 
- 生活类比:用 “沙漏”、“闹钟”、“秒表” 来比喻定时器,帮助学生建立直观印象。
- 实际需求: - 精确延时: delay_ms(1000)为什么比for循环更可靠?
- 周期性任务:每隔 1 秒读取一次传感器数据,如何实现?
- 信号生成:如何产生让 LED 呼吸灯的 PWM 信号?
- 事件测量:如何测量按键按下的时长?
 
- 精确延时: 
- 结论:定时器是 MCU 的 “内置时钟”,能独立于 CPU 工作,实现高精度、低功耗的时间相关功能。
二、什么是定时器 
- TIM(Timer)定时器
- 定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断
- 16 位计数器、预分频器、自动重装寄存器的时基单元,在 72MHz 计数时钟下可以实现最大 59.65s 的定时
- 不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能
- 根据复杂度和应用场景分为了高级定时器、通用定时器、基本定时器三种类型
三、定时器基础概念 
1. 从 “波” 和 “频率” 开始 
想象一下水面上的波浪:一个波峰接着一个波谷,再一个波峰…… 如此往复。这种周期性的运动是理解定时器的基础。
- 周期 (Period, T):完成一个完整循环(例如,从一个波峰到下一个波峰)所需的时间。单位是秒(s)。
- 频率 (Frequency, f):在 1 秒钟内,完成了多少个这样的完整循环。单位是赫兹(Hz)。
- 核心关系:频率 (f) = 1 / 周期 (T) 或 周期 (T) = 1 / 频率 (f)。 - 例如:一个波每 0.5 秒重复一次(T=0.5s),那么它的频率就是 f = 1 / 0.5 = 2 Hz,表示每秒振荡 2 次。
- 再如:市电是 50Hz,意味着电流方向每秒改变 50 次,周期 T = 1/50 = 0.02秒 = 20毫秒。
 
- 例如:一个波每 0.5 秒重复一次(T=0.5s),那么它的频率就是 
在数字电路中,最常见的 “波” 是方波。它只有两个状态:高电平(通常代表 1 或 3.3V)和低电平(通常代表 0 或 0V)。方波同样有周期和频率。
2. 如何产生一个方波?—— 需要一个 “计时器” 
假设我们想让一个 LED 以 1Hz 的频率闪烁(亮 1 秒,灭 1 秒,周期 2 秒)。最笨的方法是用 CPU 不停地数数:
cpp
while(1) {
    LED_ON();
    delay_long_time(); // 这个函数内部可能是一个巨大的for循环
    LED_OFF();
    delay_long_time();
}1
2
3
4
5
6
2
3
4
5
6
这种方法占用 CPU 资源,CPU 在这段时间内什么都不能做,效率极低。
解决方案:使用一个独立的 “小闹钟”—— 这就是定时器 (Timer)。CPU 只需要设置好这个 “闹钟”,然后就可以去干别的事了。当 “闹钟” 时间到,它会 “叫醒” CPU(通过中断),或者自己直接去翻转 LED 的状态。
3. 定时器的核心:计数器 (Counter) 
STM32 的定时器本质上是一个数字计数器。它是一个可以自动加 1(或减 1)的寄存器。
- 时钟源 (Clock Source):这个计数器需要一个 “心跳” 来驱动它。这个心跳就是时钟信号。STM32 的定时器通常使用 APB 总线时钟(如 72MHz)作为源头。
- 预分频器 (Prescaler, PSC):72MHz 的时钟太快了!如果计数器直接接 72MHz,它每秒要加 7200 万次!我们通常需要更慢、更精确的 “滴答” 声。预分频器的作用就是把高速时钟 “切碎”。 - 工作原理:预分频器接收高速时钟,每累计 PSC + 1个时钟脉冲,才输出一个 “滴答” 给计数器。
- 公式:计数器时钟频率 (f_counter) = 输入时钟频率 / (PSC + 1)
- 例子:输入时钟 = 72MHz,PSC = 7199。那么 - f_counter = 72,000,000 / (7199 + 1) = 72,000,000 / 7200 = 10,000 Hz = 10kHz。
 
- 计数器每秒加 1 万次,每次 “滴答” 间隔 T_tick = 1 / 10,000 = 0.0001秒 = 100微秒 (μs)。
 
- 工作原理:预分频器接收高速时钟,每累计 
4. 计数器如何 “闹钟”?—— 自动重装载 (Auto-Reload, ARR) 
现在计数器有了自己的 “滴答” 节奏(10kHz)。我们需要设定它多久 “闹” 一次。
- 自动重装载寄存器 (ARR):这是一个设定值。计数器从 0 开始,每收到一个 “滴答” 就加 1。当计数器的值等于 ARR 时,会发生两件事: - 溢出 (Overflow):计数器的值被清零(或根据模式重新加载),准备开始下一轮计数。
- 事件触发:可以配置定时器在此时产生一个更新事件 (Update Event)。这个事件可以: - 触发一个中断 (Interrupt),让 CPU 执行中断服务程序(ISR)。
- 触发一个 DMA 请求。
- 让某个输出通道翻转状态(用于 PWM)。
 
 
- 计算定时周期: - 定时器溢出周期 (T_timer):计数器从 0 数到 ARR 再清零所需的时间。
- 公式:T_timer = (ARR + 1) /f_counter - (ARR + 1)是因为计数器从 0 数到 ARR,总共经历了- ARR + 1个 “滴答”。
 
- 例子: f_counter = 10kHz (T_tick = 100μs),我们想要 1 秒的周期。- 需要的 “滴答” 数 N = T_timer / T_tick = 1s / 0.0001s = 10,000。
- 因为 N = ARR + 1,所以ARR = N - 1 = 10,000 - 1 = 9999。
- 验证: T_timer = (9999 + 1) / 10,000 Hz = 10,000 / 10,000 = 1秒。完美!
 
- 需要的 “滴答” 数 
 
5. 定时器的 “工作模式” 
根据计数器的计数方式,主要有:
- 向上计数模式 (Up Counter):计数器从 0 开始,递增到 ARR,然后溢出清零。这是最常用的模式。
- 向下计数模式 (Down Counter):计数器从 ARR 开始,递减到 0,然后溢出并重载 ARR。
- 中央对齐模式 (Center-Aligned):计数器先向上计数到 ARR-1,再向下计数到 1,最后溢出。主要用于生成对称 PWM。
6. 定时器如何控制 LED?—— 输出比较 (Output Compare, OC) 
定时器不仅能 “闹”,还能 “动手”。通过输出比较通道,它可以精确地在某个时间点改变 GPIO 引脚的状态。
- 比较寄存器 (Compare Register, CCRx):每个输出通道(如 CH1, CH2)都有一个对应的 CCR(如 CCR1, CCR2)。
- 工作原理: - 计数器不断运行。
- 定时器硬件会持续比较计数器的当前值和 CCRx 的值。
- 当 计数器值 == CCRx 值 时,会发生比较匹配 (Compare Match) 事件。
- 根据通道的配置模式,可以: - 翻转输出引脚的电平(Toggle)。
- 将输出引脚置高(Set)。
- 将输出引脚置低(Reset)。
 
 
- 实现 PWM:这是输出比较最强大的应用。 - PWM 频率:由 ARR和PSC共同决定(f_pwm = f_counter / (ARR + 1))。
- 占空比 (Duty Cycle):高电平时间占整个周期的比例。由 CCR值决定。- 占空比 = CCRx / (ARR + 1)
 
- 例子: ARR=99(周期 100 个滴答),f_counter=1MHz->T_period=100μs,f_pwm=10kHz。- 如果 CCR1=25,则占空比= 25 / 100 = 25%。输出波形:高电平 25μs,低电平 75μs。
- 如果 CCR1=75,则占空比= 75 / 100 = 75%。输出波形:高电平 75μs,低电平 25μs。
 
- 如果 
- 模式:通常使用 PWM 模式 1(计数器 <CCRx 时输出有效电平,>= CCRx 时输出无效电平)或 PWM 模式 2。
 
- PWM 频率:由 
7. 总结:定时器的完整工作流 
- 配置时钟:选择定时器时钟源(通常是 APB 时钟)。
- 设置预分频器 (PSC):将高速时钟分频,得到计数器的 “滴答” 频率 f_counter。
- 设置自动重装载值 (ARR):决定计数器的计数范围,从而确定定时器的基本周期 T_timer。
- 选择计数模式:通常为向上计数。
- (可选)配置输出通道 (OC): - 将 GPIO 引脚复用为定时器通道。
- 设置比较寄存器 CCR的值。
- 配置通道模式(如 PWM 模式)。
 
- (可选)使能中断:在 NVIC 中使能定时器中断,以便在溢出或比较匹配时执行 ISR。
- 启动定时器:调用 HAL_TIM_xxx_Start()或HAL_TIM_xxx_Start_IT()。
- 运行: - 计数器在 f_counter的驱动下开始计数。
- 当计数器值达到 ARR时,发生更新事件(溢出),计数器清零,可触发中断。
- 当计数器值等于某个 CCR时,发生比较匹配事件,可改变对应 GPIO 引脚的状态(如 PWM)。
- 循环往复。
 
- 计数器在 
通过这种方式,STM32 定时器就能独立于 CPU,精确地产生时间延迟、周期性中断和 PWM 信号,是嵌入式开发中不可或缺的工具。