定时器Timer详解:计数、延时、PWM输出和输入捕获一次讲清
一、本文适用场景
定时器 Timer 是单片机中非常核心的基础外设。无论是 STM32、GD32、51 单片机,还是其他 MCU,只要涉及时间控制、周期任务、PWM 输出、测频率、测脉宽,基本都会用到定时器。
很多初学者刚开始学习 Timer 时,通常只把它理解成“延时工具”。但实际上,Timer 的作用远不止延时。
定时器常见应用包括:
- 精确定时;
- 周期中断;
- LED 周期闪烁;
- 按键消抖;
- 系统心跳;
- 任务调度;
- PWM 输出;
- LED 调光;
- 风扇调速;
- 电机控制;
- 舵机控制;
- 输入捕获;
- 测频率;
- 测周期;
- 测脉宽;
- 外部脉冲计数;
- 风扇测速。
本文将从 Timer 的基本概念开始,详细介绍:
- 什么是定时器;
- PSC、CNT、ARR 分别是什么;
- 定时器为什么能实现延时;
- 定时器中断是怎么产生的;
- PWM 频率和占空比怎么计算;
- CCR 在 PWM 中的作用;
- 输入捕获如何测频率、周期和脉宽;
- 定时器常见应用;
- Timer 不工作、PWM 没波形、输入捕获不准时如何排查。
二、什么是定时器Timer
Timer,中文通常称为:
定时器从本质上看,定时器就是 MCU 内部的一个硬件计数器。
它可以按照固定节拍递增或递减计数。
这个节拍可以来自:
内部时钟也可以来自:
外部脉冲当计数值达到预设值时,Timer 可以产生一个事件,比如:
更新事件 中断事件 PWM翻转事件 输入捕获事件 输出比较事件可以简单理解为:
Timer = 按固定节拍数数的硬件模块它的核心能力是:
数时间 数脉冲 产生周期事件 输出周期波形 记录外部边沿到来的时间所以定时器不是单纯用来 delay 的,而是整个嵌入式系统里非常重要的“时间控制中心”。
三、定时器能做什么
定时器常见功能包括:
| 功能 | 说明 | 典型应用 |
|---|---|---|
| 基本计数 | 对内部时钟或外部脉冲计数 | 时间基准、外部计数 |
| 定时延时 | 计数到设定值后产生事件 | 1ms、10ms、1s 定时 |
| 定时中断 | 周期性进入中断服务函数 | 系统心跳、周期任务 |
| PWM输出 | 输出固定频率、可调占空比波形 | LED调光、风扇调速、电机控制 |
| 输出比较 | CNT 与 CCR 比较后触发动作 | 精准翻转、定时输出 |
| 输入捕获 | 捕获外部信号边沿时的 CNT 值 | 测频率、周期、脉宽 |
| 外部计数 | 对外部脉冲进行计数 | 编码器、风扇测速、脉冲计数 |
学习 Timer 时,建议先掌握三个基础概念:
PSC:预分频器 CNT:计数器 ARR:自动重装载寄存器后面无论是定时、PWM,还是输入捕获,本质都离不开这几个概念。
图1 定时器 Timer 基础与作用
Timer 本质上是单片机内部的硬件计数器,可以用于计数、定时、PWM 输出、输入捕获、外部计数和中断触发等场景。
四、定时器的基本组成
一个基础定时器通常可以简化理解为下面几个部分:
定时器时钟 ↓ 预分频器 PSC ↓ 计数器 CNT ↓ 自动重装载寄存器 ARR ↓ 更新事件 / 中断下面分别解释。
五、定时器时钟是什么
定时器需要一个时钟作为计数节拍。
这个时钟可以来自 MCU 内部总线时钟。
例如在 STM32 中,定时器时钟可能来自:
APB1 APB2不同定时器挂载在不同总线上。
需要注意的是,某些 STM32 系列中,如果 APB 预分频不为 1,定时器时钟可能会变成 APB 时钟的 2 倍。
所以在计算定时时间前,必须先确认:
当前定时器真正的输入时钟是多少如果这个时钟搞错,后面的 PSC、ARR 再怎么算都会不准。
六、PSC预分频器是什么
PSC 的全称可以理解为:
Prescaler中文叫:
预分频器它的作用是把定时器输入时钟分频,降低计数速度。
例如定时器输入时钟是:
72MHz如果 PSC 设置为:
71实际分频系数为:
PSC + 1 = 72那么计数器 CNT 得到的计数频率为:
72MHz / 72 = 1MHz也就是说,CNT 每 1 微秒加 1。
这里要注意:
实际分频值 = PSC + 1不是 PSC 本身。
这是初学者很容易搞错的地方。
七、CNT计数器是什么
CNT 是当前计数值。
定时器工作时,CNT 会按照定时器计数频率递增或递减。
常见向上计数方式是:
0 → 1 → 2 → 3 → ... → ARR当 CNT 计数到 ARR 后,会产生更新事件,然后 CNT 重新从 0 开始计数。
所以 CNT 可以理解为:
Timer当前已经数到哪里了在调试定时器时,如果能看到 CNT 正在变化,通常说明:
定时器时钟已经工作 定时器已经启动 计数器正在运行如果 CNT 一直不变,就要检查:
- 定时器时钟是否开启;
- 定时器是否启动;
- 计数模式是否正确;
- 外部时钟模式是否配置错误;
- 是否被调试器暂停。
八、ARR自动重装载寄存器是什么
ARR 的全称可以理解为:
Auto Reload Register中文叫:
自动重装载寄存器它决定计数器的上限。
在向上计数模式中:
CNT 从 0 开始计数 CNT 数到 ARR 产生更新事件 CNT 清零重新开始所以 ARR 决定一个定时周期内需要计多少个数。
注意:
实际计数个数 = ARR + 1因为 CNT 是从 0 开始数的。
例如 ARR = 999,则 CNT 会数:
0 ~ 999一共是:
1000 个计数九、定时器为什么能实现延时
定时器实现延时的原理非常简单:
固定频率计数 ↓ 数到设定值 ↓ 产生事件 ↓ 说明经过了一段固定时间假设定时器计数频率为:
1MHz也就是:
CNT 每 1 微秒加 1如果 ARR = 999,那么 CNT 从 0 数到 999,一共 1000 个计数。
耗时为:
1000 × 1us = 1000us = 1ms所以每次更新事件就表示经过了 1ms。
十、定时周期计算公式
定时器定时周期常用公式为:
定时周期 = (PSC + 1) × (ARR + 1) ÷ 定时器时钟也可以写成:
Tout = (PSC + 1) × (ARR + 1) / Ftimer其中:
PSC:预分频器值 ARR:自动重装载值 Ftimer:定时器输入时钟频率对应的更新频率为:
更新频率 = 定时器时钟 ÷ [(PSC + 1) × (ARR + 1)]十一、1ms定时示例
假设定时器时钟为:
72MHz想得到:
1ms可以设置:
PSC = 71 ARR = 999计算过程:
PSC + 1 = 72 ARR + 1 = 1000定时周期:
(71 + 1) × (999 + 1) ÷ 72,000,000 = 72 × 1000 ÷ 72,000,000 = 0.001s = 1ms所以每 1ms 会产生一次更新事件。
十二、1s定时示例
假设定时器时钟为:
1MHz想得到:
1s可以设置:
PSC = 999 ARR = 999计算过程:
PSC + 1 = 1000 ARR + 1 = 1000定时周期:
1000 × 1000 ÷ 1,000,000 = 1s所以每 1s 产生一次更新事件。
十三、定时器中断是怎么产生的
当 CNT 计数到 ARR 后,会产生更新事件。
如果同时打开了定时器更新中断,那么 CPU 就会进入定时器中断服务函数。
完整流程为:
定时器时钟输入 ↓ PSC分频 ↓ CNT开始计数 ↓ CNT计数到ARR ↓ 产生更新事件 ↓ 更新中断标志置位 ↓ NVIC响应中断 ↓ CPU进入定时器ISR ↓ 清除中断标志 ↓ 执行定时任务定时器中断常用于:
- 系统心跳;
- 定时扫描;
- 软件计时;
- 任务调度;
- 按键消抖;
- 超时检测。
图2 定时器计数与定时延时详解
PSC 用于分频,CNT 负责计数,ARR 决定计数上限。CNT 从 0 数到 ARR 后产生更新事件,从而实现固定周期定时。
十四、PWM是什么
PWM 的英文全称是:
Pulse Width Modulation中文叫:
脉冲宽度调制PWM 本质上是一种周期性的高低电平波形。
它通过调节高电平持续时间占整个周期的比例,来控制输出信号的平均电压或平均功率。
PWM 有两个核心参数:
频率 占空比十五、PWM频率是什么
PWM 频率表示:
1秒内PWM周期重复多少次单位是:
Hz例如:
1kHz表示每秒有 1000 个 PWM 周期。
PWM 频率由定时器的计数周期决定。
常用公式为:
PWM频率 = 定时器时钟 ÷ [(PSC + 1) × (ARR + 1)]可以看到,PWM 频率和定时器更新频率本质上是一样的。
十六、PWM占空比是什么
占空比表示:
高电平时间占整个周期的比例公式为:
占空比 = 高电平时间 ÷ 周期 × 100%在定时器 PWM 中,高电平时间通常由 CCR 决定。
CCR 可以理解为:
比较寄存器在常见 PWM 模式中,CNT 从 0 开始计数,当 CNT 小于 CCR 时输出一种电平,当 CNT 大于或等于 CCR 时输出另一种电平。
常见占空比计算公式为:
占空比 = CCR ÷ (ARR + 1) × 100%例如:
ARR = 999 CCR = 500占空比约为:
500 ÷ 1000 × 100% = 50%十七、PWM中的ARR和CCR分别控制什么
可以这样理解:
ARR 决定 PWM 的周期 CCR 决定 PWM 的高电平持续时间也就是说:
ARR 影响频率 CCR 影响占空比例如:
ARR 增大 → 周期变长 → PWM频率降低 ARR 减小 → 周期变短 → PWM频率升高 CCR 增大 → 高电平时间变长 → 占空比增大 CCR 减小 → 高电平时间变短 → 占空比减小所以调 PWM 时,必须区分:
改频率:主要改 PSC / ARR 改占空比:主要改 CCR十八、PWM占空比示例
假设:
ARR = 999那么一个周期有:
1000 个计数如果:
CCR = 250占空比为:
250 / 1000 = 25%如果:
CCR = 500占空比为:
500 / 1000 = 50%如果:
CCR = 750占空比为:
750 / 1000 = 75%占空比越大,高电平持续时间越长。
对于多数低通或平均功率型负载来说,占空比越大,平均电压或平均功率越大。
十九、PWM常见应用
PWM 常见应用包括:
1. LED调光
通过改变占空比改变 LED 的平均亮度。
占空比小 → LED暗 占空比大 → LED亮2. 风扇调速
改变 PWM 占空比,可以改变风扇的平均驱动功率,从而调节转速。
3. 电机控制
PWM 常用于直流电机调速。
实际项目中通常配合:
- MOSFET;
- H桥;
- 电机驱动芯片;
- 电流采样;
- 速度反馈。
4. 蜂鸣器
通过改变 PWM 频率,可以改变蜂鸣器音调。
通过改变占空比,可以影响声音效果。
5. 舵机控制
舵机通常根据固定周期内的高电平脉宽判断角度。
例如常见舵机可能使用:
20ms周期 0.5ms ~ 2.5ms高电平脉宽不同舵机参数可能不同,应以实际产品手册为准。
图3 PWM 输出原理与应用详解
PWM 通过频率和占空比描述波形。ARR 决定周期和频率,CCR 决定高电平时间和占空比。PWM 常用于 LED 调光、风扇调速、电机控制和舵机控制。
二十、输入捕获是什么
输入捕获是定时器的一种重要功能。
它可以在外部输入信号出现指定边沿时,把当前 CNT 的值自动保存到 CCR 捕获寄存器中。
可以简单理解为:
外部边沿到来的一瞬间 Timer立刻记录当前时间点输入捕获常用于测量:
- 周期;
- 频率;
- 高电平脉宽;
- 低电平脉宽;
- 占空比;
- 外部脉冲时间间隔;
- 风扇转速;
- 超声波回波时间;
- PWM输入信号参数。
二十一、输入捕获的基本流程
输入捕获的基本流程如下:
外部信号接入定时器通道 ↓ 选择捕获边沿 ↓ 外部边沿到来 ↓ 定时器把当前CNT锁存到CCR ↓ 捕获标志置位 ↓ 可触发捕获中断 ↓ 软件读取CCR计算时间关键点是:
CCR中保存的是边沿到来那一刻的CNT值所以输入捕获本质上是让定时器“看见边沿,并记下时间点”。
二十二、输入捕获测频率
如果要测一个周期信号的频率,可以连续捕获两个上升沿。
例如:
第1个上升沿捕获值 = CCR1 第2个上升沿捕获值 = CCR2两个捕获值的差为:
周期计数值 = CCR2 - CCR1如果定时器计数频率为:
Ftimer那么周期为:
T = 周期计数值 ÷ Ftimer频率为:
f = Ftimer ÷ 周期计数值如果发生计数器溢出,则需要考虑 ARR 溢出修正。
二十三、输入捕获测脉宽
如果要测高电平脉宽,可以:
上升沿捕获作为起点 下降沿捕获作为终点假设:
上升沿捕获值 = CCR_rise 下降沿捕获值 = CCR_fall那么高电平计数值为:
CCR_fall - CCR_rise脉宽时间为:
高电平计数值 ÷ Ftimer例如定时器计数频率为:
1MHz也就是 1 个计数等于 1 微秒。
如果上升沿和下降沿差值为:
1500那么高电平脉宽就是:
1500us = 1.5ms这类测量常用于:
- 舵机信号测量;
- PWM 输入占空比测量;
- 超声波回波时间;
- 脉冲宽度检测。
二十四、输入捕获测风扇转速
风扇通常会输出测速脉冲。
假设风扇每转一圈输出 2 个脉冲。
通过输入捕获测得脉冲频率后,可以计算 RPM。
如果测得脉冲频率为:
Fpulse每圈脉冲数为:
PPR则转速为:
RPM = Fpulse × 60 ÷ PPR例如:
Fpulse = 100Hz PPR = 2则:
RPM = 100 × 60 ÷ 2 = 3000 RPM实际项目中还要考虑滤波、抖动、低速测量、超时判断等问题。
二十五、输入捕获注意事项
输入捕获常见注意点包括:
1. 边沿选择要正确
根据测量目的选择:
上升沿捕获 下降沿捕获 双边沿捕获如果边沿选错,计算结果就会错误。
2. 定时器计数频率要合适
计数频率太低:
分辨率不够 测量精度差计数频率太高:
容易溢出 需要频繁处理3. 要考虑溢出
如果两次捕获之间 CNT 发生了溢出,就不能简单直接相减。
需要根据溢出次数修正。
例如:
真实计数差 = 溢出次数 × (ARR + 1) + 当前捕获值 - 上次捕获值4. 信号要滤波
输入信号如果有毛刺,可能导致误捕获。
可以使用:
- 硬件滤波;
- 定时器输入滤波;
- 软件滤波;
- 外部整形电路。
图4 输入捕获 Input Capture 详解
输入捕获可以在外部信号边沿到来时锁存 CNT 值。连续两次捕获可以测周期和频率,上升沿与下降沿捕获可以测高电平脉宽。
二十六、输出比较是什么
输出比较也是定时器常见功能。
它的基本思想是:
CNT不断计数 当CNT等于CCR时 定时器产生比较事件根据配置不同,比较事件可以触发:
- 输出翻转;
- 输出置位;
- 输出复位;
- 产生中断;
- 触发 DMA;
- 控制 PWM 波形。
PWM 本质上也和比较功能密切相关。
在 PWM 模式中,定时器不断比较:
CNT 和 CCR然后根据比较结果决定输出高电平还是低电平。
二十七、外部计数是什么
除了使用内部时钟计数,Timer 也可以对外部脉冲进行计数。
这就是外部计数模式。
例如:
外部每来一个脉冲 CNT加1外部计数常用于:
- 编码器脉冲计数;
- 流量计脉冲计数;
- 风扇转速脉冲统计;
- 外部事件计数;
- 频率较低的脉冲累计。
外部计数和输入捕获的区别是:
外部计数:关心来了多少个脉冲 输入捕获:关心脉冲什么时候来二十八、Timer常见调试问题
1. 定时器不计数
可能原因包括:
- 定时器外设时钟没开启;
- 定时器没有启动;
- 计数模式配置错误;
- PSC / ARR 设置不合理;
- 使用了外部时钟但外部没有脉冲;
- 调试模式下定时器被暂停;
- 定时器实例选错。
排查时可以先查看:
CNT 是否在变化如果 CNT 不变,说明 Timer 还没有真正跑起来。
2. 定时时间不准
可能原因包括:
- 定时器输入时钟算错;
- APB 分频导致定时器时钟倍频没考虑;
- PSC / ARR 公式使用错误;
- 忘记 PSC 和 ARR 实际都要加 1;
- 中断处理时间太长;
- 软件中重复修改计数器;
- 使用阻塞延时代替硬件定时。
最常见错误是把公式写成:
PSC × ARR而不是:
(PSC + 1) × (ARR + 1)3. PWM没有波形
可能原因包括:
- GPIO 没配置成复用功能;
- 定时器通道没有映射到正确引脚;
- PWM 通道没有使能;
- 定时器没有启动;
- CCR 设置为 0;
- CCR 大于 ARR 导致占空比异常;
- ARR / PSC 设置错误;
- 高级定时器没有使能主输出 MOE;
- 输出极性配置错误;
- 示波器测错引脚。
排查 PWM 时,建议按顺序检查:
定时器是否启动 GPIO是否是AF复用 通道是否正确 ARR/PSC/CCR是否合理 通道输出是否使能 实际引脚是否有波形4. 输入捕获不准
可能原因包括:
- 捕获边沿选错;
- 输入引脚复用错误;
- 信号没有真正到达引脚;
- 计数频率太低导致分辨率不足;
- 计数频率太高导致溢出频繁;
- 没有处理计数器溢出;
- 输入滤波设置不合理;
- 信号毛刺导致误捕获;
- 软件读取 CCR 顺序错误;
- 捕获中断处理太慢。
排查输入捕获时,建议先用示波器确认外部信号本身是否正常。
二十九、Timer调试推荐顺序
Timer 相关问题建议按下面顺序排查:
第1步:确认定时器外设时钟是否开启 第2步:确认定时器实例是否正确 第3步:确认定时器是否启动 第4步:查看CNT是否在变化 第5步:确认PSC、ARR、CCR计算是否正确 第6步:确认GPIO复用功能是否正确 第7步:确认通道映射是否正确 第8步:如果使用中断,确认中断使能和NVIC配置 第9步:确认中断标志是否正确清除 第10步:如果使用PWM,用示波器看输出波形 第11步:如果使用输入捕获,用示波器看输入信号 第12步:最后再检查业务逻辑Timer 的调试核心是:
先看时钟和计数 再看寄存器配置 最后看引脚和波形图5 定时器调试与故障排查指南
Timer 不工作、PWM 没输出、输入捕获不准时,应从时钟、GPIO 复用、PSC/ARR/CCR、模式配置、中断/DMA 和实际波形逐层排查。
三十、STM32 HAL定时器中断示例
下面代码只作为理解思路,不同芯片和库函数会有差异。
1. 启动定时器中断
HAL_TIM_Base_Start_IT(&htim2);2. 定时器中断回调
voidHAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef*htim){if(htim->Instance==TIM2){/* 例如每1ms进入一次 */system_tick++;}}通常建议中断中只做轻量处理,例如计数或置标志。
三十一、STM32 HAL PWM输出示例
1. 启动PWM
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1);2. 修改占空比
__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,500);如果:
ARR = 999 CCR = 500则占空比约为 50%。
实际工程中可以封装函数:
voidpwm_set_duty(uint16_tduty){if(duty>1000){duty=1000;}__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,duty);}三十二、STM32 HAL输入捕获示例
1. 启动输入捕获中断
HAL_TIM_IC_Start_IT(&htim4,TIM_CHANNEL_1);2. 捕获回调
volatileuint32_tcapture1=0;volatileuint32_tcapture2=0;volatileuint8_tcapture_done=0;voidHAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef*htim){if(htim->Instance==TIM4&&htim->Channel==HAL_TIM_ACTIVE_CHANNEL_1){if(capture_done==0){capture1=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1);capture_done=1;}else{capture2=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1);uint32_tdiff;if(capture2>=capture1){diff=capture2-capture1;}else{diff=(htim->Instance->ARR-capture1+1)+capture2;}/* diff就是两次捕获之间的计数差 */capture1=capture2;}}}实际项目中还需要根据定时器计数频率计算周期和频率。
三十三、Timer学习重点总结
学习 Timer 可以先记住以下结论:
Timer 本质是硬件计数器。
Timer 可以对内部时钟或外部脉冲计数。
PSC 是预分频器。
CNT 是当前计数值。
ARR 是自动重装载值,也就是计数上限。
实际分频系数是 PSC + 1。
实际计数个数是 ARR + 1。
定时周期由定时器时钟、PSC 和 ARR 共同决定。
定时周期 = (PSC + 1) × (ARR + 1) ÷ 定时器时钟。
CNT 数到 ARR 后会产生更新事件。
打开更新中断后,更新事件可以触发定时器中断。
PWM 是周期性的高低电平波形。
PWM 频率由 PSC 和 ARR 决定。
PWM 占空比由 CCR 和 ARR 决定。
占空比 = CCR ÷ (ARR + 1) × 100%。
ARR 主要影响 PWM 周期和频率。
CCR 主要影响 PWM 高电平时间和占空比。
输入捕获可以记录外部边沿到来时的 CNT 值。
两次上升沿捕获值相减可以测周期和频率。
上升沿和下降沿捕获值相减可以测高电平脉宽。
外部计数关心脉冲数量。
输入捕获关心边沿到来的时间点。
Timer 调试要先看时钟和 CNT 是否变化。
PWM 没波形要检查 GPIO 复用、通道使能和 CCR。
输入捕获不准要检查边沿、时钟、滤波和溢出处理。
三十四、结语
Timer 是单片机中非常重要的基础外设。
它看起来只是“计数器”,但实际能完成很多关键功能:
延时 周期中断 PWM输出 输入捕获 输出比较 外部计数 测频率 测脉宽 风扇测速 电机控制真正理解 Timer,需要把下面这些概念串起来:
定时器时钟 + PSC + CNT + ARR + CCR + 更新事件 + 中断 + PWM + 输入捕获可以用一句话总结:
Timer 的本质是计数; 定时是数时间; PWM 是按计数比较输出波形; 输入捕获是记录外部边沿到来的计数值。当你能理解 PSC、ARR、CNT、CCR 之间的关系时,Timer 的大部分功能就已经入门了。