☰
【STM32】 通用定时器 TIM 详解:从概念到 PWM 速通
2026/10/8 18:28:21 网站建设 项目流程


STM32 通用定时器 TIM 详解:从概念到 PWM 实战

1. 通用定时器概念

1.1 通用定时器 vs 基础定时器

对比项基础定时器 TIM6/7通用定时器 TIM2~5
计数方向只向上(0,1,2…)向上 / 向下 / 中央对齐 三种
时钟源只内部 CK_INT内部 + 外部引脚 + 编码器 + 内部触发 四种
通道无独立通道4 个独立通道 CH1~CH4(可同时干 4 件事)
输出能力只能 TRGO 触发 DAC每个通道可输出到 GPIO(PWM、方波、脉冲)
输入能力无输入捕获(测脉宽、测频率、测外部信号)
DMA有有(且每通道独立 DMA 请求)
中断更新中断更新 + 4 个捕获/比较中断

一句话:

通用定时器 = 基础定时器(时基单元)+ 捕获/比较单元 + 更多时钟源 + 4 个对外引脚通道。

1.2 通用定时器内部框图(必读)

时钟源选择(4选1) ┌──────────────────────────┐ │ CK_INT 内部时钟 │ │ TI1/TI2 外部引脚 │ │ ETR 外部触发 │ │ ITR 其他定时器 │ └───────────┬──────────────┘ ▼ ┌─── PSC 预分频器 ───┐ │ CK_CNT = CK_PSC/(PSC+1) │ └───────────┬──────────┘ ▼ ┌─── CNT 计数器(16位)───┐ │ 向上 / 向下 / 中央对齐 │◄──► ARR 自动重装(影子寄存器) └───────────┬──────────┘ ▼ ┌──────────┬──────────┬──────────┬──────────┐ ▼ ▼ ▼ ▼ ▼ CH1 比较器 CH2 比较器 CH3 比较器 CH4 比较器 溢出 UEV │ │ │ │ │ CCR1 CCR2 CCR3 CCR4 ├─ 更新中断 (16位) (16位) (16位) (16位) ├─ DMA 请求 │ │ │ │ └─ TRGO ▼ ▼ ▼ ▼ OC1REF OC2REF OC3REF OC4REF │ │ │ │ CCMR 配置 CCMR 配置 CCMR 配置 CCMR 配置(PWM模式/输出比较模式) │ │ │ │ CC1 引脚 CC2 引脚 CC3 引脚 CC4 引脚 (PA0/PA1 (PA1/PA7 (PB10/PB11 (PB11/PA3 PA1/PA5...) PA5...) PA9...) PB...)

1.3 计数模式(CR1 寄存器 DIR + CMS 位)

① 向上计数模式(最常用,和基础定时器一样):CNT 从 0 数到 ARR,溢出后回 0 重新数。

② 向下计数模式:CNT 从 ARR 数到 0,溢出后重装 ARR。

③ 中央对齐模式(PWM 电机专用):CNT 从 0 数到 ARR-1 → 再向下数到 1 → 一个周期两次比较(上升沿+下降沿),输出更对称的 PWM,减少电机噪音。

1.4 通用定时器用到的关键寄存器(在基础定时器之上新增的)

寄存器偏移作用
TIMx_CCMR10x18通道 1、2 的模式配置(输出比较模式 / 输入捕获模式、预分频、滤波器)
TIMx_CCMR20x1C通道 3、4 的模式配置
TIMx_CCER0x20通道输出使能(CCxE)、极性(CCxP)
TIMx_CCR1~CCR40x34 / 0x38 / 0x3C / 0x40捕获/比较寄存器(16 位,设定"比较阈值")
TIMx_CR10x00比基础定时器多了 DIR(位4)、CMS[1:0](位6:5)
TIMx_SMCR0x08从模式控制(外部时钟、编码器模式)

2. 输出比较速通

2.1 什么是"输出比较"

把 CNT 的值和 CCR(捕获/比较寄存器) 的值做比较:

  • 当CNT == CCR时,硬件自动对 OCxREF(输出比较参考信号) 执行一个动作;
  • 这个动作是什么,由 CCMR 寄存器的 OCxM 位决定;
  • OCxREF 再经过极性选择(CCER),最终输出到 GPIO 引脚。

类比:

CNT 是秒表在走,CCR 是你设的"到这个数字就响",OCxM 是"响了之后干嘛"(亮灯?翻转?输出高电平?)。

2.2 OCxM 输出比较模式(CCMR 的位 6:4,CH1 为例)

OCxM[2:0]模式行为(CNT==CCR 时)
000冻结什么都不做(只中断/DMA,不改输出)
001匹配时置有效OCxREF 强制变为有效电平
010匹配时置无效OCxREF 强制变为无效电平
011匹配时翻转OCxREF 翻转(原来高变低,原来低变高)
100强制无效OCxREF 始终为无效(软件强制)
101强制有效OCxREF 始终为有效(软件强制)
110PWM 模式 1向上计数时:CNT < CCR → 有效;CNT ≥ CCR → 无效
111PWM 模式 2与 PWM1 相反(CNT < CCR → 无效)

2.3 用"翻转模式"做一个 1Hz 方波

配置:ARR=999、PSC=71(CK_CNT=1MHz,1us/次)、OC1M=011(翻转)。

CNT 计数:0 → 1 → 2 → ... → 999 → 溢出回 0 → 再到 CCR=500 → 翻转 每隔 (ARR+1)/2 = 500us 翻转一次 → 周期 1ms → 1kHz 方波

翻转模式是输出比较最简单的用法:不需要算占空比,硬件自动对半翻转。

2.4 输出比较的硬件时序

CNT ───0────1────...────500────...────999────0────1────... ↑ CNT==CCR=500 ↓ OC1REF ────────────────┐ ┌──────────── └───────────────────────┘ ← 500us →← 500us →

3. 软件可调占空比

3.1 占空比是什么

PWM 一个周期内,高电平时间 / 总周期时间 就是占空比。

LED 调光、舵机角度、电机转速,本质都是调占空比。

占空比 D = CCR / (ARR + 1) × 100%
  • CCR = 0 → 占空比 0% → 引脚一直低
  • CCR = ARR → 占空比 100% → 引脚一直高
  • CCR = ARR/2 → 占空比 50% → 方波

3.2 软件怎么调占空比

PWM 一旦启动(CEN=1),硬件会自动按 ARR 周期输出波形。

想改占空比?只要改 CCR 的值就行,硬件自动在下一个周期生效(CCR 有影子寄存器,默认缓冲)。

// 占空比从 50% 渐变为 100%,呼吸灯效果 for (uint16_t i = 0; i <= arr; i++) { __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, i); // 改 CCR1 HAL_Delay(5); }

关键点:

改占空比不需要停定时器、不需要重配寄存器,只要写 CCR。

这就是"软件可调占空比"——CPU 只需要在合适时机改一下 CCR,剩下的全是硬件自动完成。

3.3 一个常见误区

  • 改 ARR 会改频率(周期),改 CCR 只改占空比;
  • 想保持频率不变只调亮度 → 只动 CCR;
  • 想换 PWM 频率 → 动 ARR(必要时连 PSC 一起动)。

3.4 PWM 速通

3.4.1 PWM 两个核心数

设定决定什么怎么算
ARRPWM 的周期(频率)PWM 频率 = CK_CNT / (ARR+1) = TIMxCLK / ((PSC+1)(ARR+1))
CCRPWM 的占空比(高电平宽度)占空比 = CCR / (ARR+1);高电平时间 = CCR × 计数周期

3.4.2 PWM 模式 1 的波形(向上计数)

CCR = 400, ARR = 1000 → 占空比 = 400/1001 ≈ 40% OC1REF ┌───────┐ ┌───────┐ │ │ │ │ │ │ │ │ ──┘ └───────────────┘ └──── │← 400 →←──── 601 ────→│ │←─────1001个计数 ─────→│ 高电平时间:400us(若 CK_CNT=1MHz) 周期:1001us ≈ 1kHz

PWM 模式 1(向上计数)规则:

  • CNT < CCR→ OCxREF = 有效电平(一般是高)
  • CNT ≥ CCR→ OCxREF = 无效电平(一般是低)

PWM 模式 2 正好相反(CNT < CCR 输出无效)。

3.4.3 PWM 配置 7 步法(背下来)

① 开时钟:__HAL_RCC_TIM3_CLK_ENABLE()、__HAL_RCC_GPIOB_CLK_ENABLE() ② 配 GPIO:PB4 复用推挽输出(TIM3_CH1) ③ 配时基:PSC=71(1MHz)、ARR=999(1kHz) ④ 配 CCR:TIM3->CCR1 = 400(占空比 40%) ⑤ 配模式:CCMR1 = PWM 模式 1(OC1M=110,OC1PE=1 预装载使能) ⑥ 配输出:CCER = CC1E=1 使能通道、CC1P=0 高电平有效 ⑦ 启动:CR1.CEN=1;MOE(高级定时器才有)=1

3.4.4 PWM 计算经典题

题:TIMxCLK=72MHz,要产生 1kHz、占空比 75% 的 PWM,求 PSC、ARR、CCR。

选 CK_CNT = 1MHz(1us 分辨率)→ PSC+1 = 72 → PSC = 71 1kHz → 周期 1ms → (ARR+1) = 1000 → ARR = 999 75% 占空比 → CCR = 0.75 × (ARR+1) = 750

3.5 通用定时器"4 方关系"

通用定时器在 PWM / 波形生成场景下,涉及四个角色的协作,理解这"4 方关系"就懂了定时器的实战骨架。

3.5.1 四方分别是谁

角色硬件载体职责
① 时基单元PSC / CNT / ARR

产生时间基准,定时器的"心跳"。

决定 PWM 频率

② 捕获/比较单元CCMR / CCR / CCER

把时间基准"翻译"成引脚电平变化。

决定 PWM 占空比

③ DMA 控制器DMA1_Channel5 等

自动搬运数据到 CCR,CPU 完全不参与。

比如做呼吸灯:把一组亮度值放数组,DMA 每次更新事件自动把下一个值写进 CCR

④ NVIC 中断TIMx_UP_IRQ / TIMx_CCx_IRQ

事件通知 CPU。

比如"PWM 周期到了"或"捕获到外部信号边沿了",CPU 去处理

3.5.2 四方怎么协作(以呼吸灯为例)

① 时基单元:每 1ms 产生一次更新事件 UEV(PWM 周期) │ ├─► ② 捕获/比较单元:CNT 与 CCR 比较,硬件自动输出 PWM 到引脚 │ ├─► ③ DMA:响应 UEV 请求,自动把"亮度数组[下一个值]"写入 CCR │ → 下一个 PWM 周期占空比自动变化,CPU 全程不参与 │ └─► ④ NVIC 中断:可选,如果你想在每周期做点事就开 (比如数到 100 次后换方向:亮渐暗、暗渐亮)

3.5.3 什么时候用哪一方?

场景时基比较DMA中断

简单呼吸灯

(固定渐变)

✅✅✅ 推荐(CPU 解放)❌ 不需要

舵机控制

(按键调角度)

✅✅❌ 改一次 CCR 就够✅ 按键中断
电机 PID✅✅❌✅ 高频更新(10kHz)
输入捕获测脉宽✅✅(输入模式)✅ 高速测频✅ 边沿事件

本质:

时基单元是"发动机",比较单元是"变速箱",DMA 是"自动驾驶",中断是"报警铃"。

四个模块可独立开关,按需组合。

下面用一张图把"PWM 占空比 + 四方关系"一次看清:


面试题

一、概念题

Q1. 通用定时器 TIM2~5 比基础定时器 TIM6/7 多了哪些能力?

A:

① 3 种计数模式(向上/向下/中央对齐);

② 4 个独立捕获/比较通道 CH1~CH4;

③ 更多时钟源(内部 + 外部引脚 + 编码器 + 内部触发);

④ 输出能力(每个通道可输出 PWM/方波到 GPIO);

⑤ 输入捕获(测脉宽/频率)。

一句话:

基础定时器 = 只会数数;

通用定时器 = 数数 + 把数变成引脚波形。


Q2. 什么是输出比较?OCxREF 是什么?

A:

硬件把 CNT 计数器值和 CCR 比较寄存器值做比较,

当CNT == CCR时,按 OCxM 设定的模式自动改变 OCxREF(输出比较参考信号),再经过极性选择输出到 GPIO。

OCxREF 是通道内部的"波形原型",CCER 决定它最终是高电平还是低电平出去。


Q3. OCxM 的 7 种模式分别是干什么的?

A:

000 冻结(只发事件不改输出);

001 匹配时置有效;

002 匹配时置无效;

011 匹配时翻转(最简单的方波);

100/101 强制输出无效/有效;

110 PWM 模式 1、111 PWM 模式 2(最常用)。


二、PWM 计算题(高频)

Q4. PWM 的频率和占空比分别由什么寄存器决定?写出公式。

A:

频率由 ARR(配合 PSC)决定:

PWM 频率 = CK_CNT / (ARR+1) = TIMxCLK / ((PSC+1)(ARR+1))。

占空比由 CCR 决定:

占空比 = CCR / (ARR+1) × 100%。

改 ARR 改频率、改 CCR 只改占空比。


Q5. TIMxCLK=72MHz,要产生 1kHz、占空比 75% 的 PWM,求 PSC、ARR、CCR。

A:

取 CK_CNT=1MHz(1us 分辨率)→ PSC+1=72 → PSC=71;

1kHz 周期 1ms → ARR+1=1000 → ARR=999;

75% → CCR = 0.75 × 1000 = 750。


Q6. 想保持 PWM 频率不变,只调 LED 亮度,应该改哪个寄存器?为什么不需要停定时器?

A:

只改 CCR。

因为 CCR 有影子寄存器(OCxPE=1 预装载使能),改值后下一个更新事件 UEV 自动生效,当前周期完整跑完,不会打断波形,硬件自动完成,CPU 只需要写一次寄存器。


三、模式与配置题

Q7. PWM 模式 1 和模式 2 的区别?

A:

向上计数时:

PWM 模式 1(OCxM=110)

CNT < CCR 输出有效电平, CNT ≥ CCR 输出无效电平;

**PWM 模式 2(OCxM=111)**正好相反。

初学只用 PWM 模式 1 + 高电平有效即可。


Q8. 输出比较配置的 7 步是什么?

A:

① 开 TIM 和 GPIO 时钟;

② GPIO 配复用推挽输出;

③ 写 PSC、ARR 定频率;

④ 写 CCR 定占空比;

⑤ CCMR 选 PWM 模式 + 开预装载(OCxPE=1);

⑥ CCER 使能通道(CCxE=1)+ 选极性;

⑦ CR1.CEN=1 启动计数。


Q9. 什么是"软件可调占空比"?为什么它很有用?

A:

PWM 启动后,CPU 只要在合适时机修改 CCR 的值,硬件自动在下一周期用新占空比输出。

无需停定时器、无需重配寄存器。

呼吸灯(CCR 从 0 渐加到 ARR)、舵机(按键改 CCR)、电机调速(PID 输出写 CCR)都靠它。


四、四方关系题(重点)

Q10. 通用定时器实战中的"4 方"指哪 4 个模块?各自职责?

A:

① 时基单元(PSC/CNT/ARR):产生时间基准,定频率;

② 捕获/比较单元(CCMR/CCR/CCER):把时间基准翻译成引脚波形,定占空比;

③ DMA 控制器:响应 UEV 自动搬运数据到 CCR,CPU 完全不参与;

④ NVIC 中断:事件通知 CPU(更新/捕获/比较)。


Q11. 做一个呼吸灯,为什么推荐用 DMA + 定时器,而不是 CPU 循环改 CCR?

A:

CPU 循环改 CCR 要不停HAL_Delay + 改 CCR,占用 CPU 且定时不准。

用 DMA 响应 UEV 自动把"亮度数组"下一个值写入 CCR,CPU 完全解放,只需要在初始化时配一次,剩下的硬件自动跑;

只有在需要"亮渐暗/暗渐亮切换方向"时才开一个更新中断做计数。


Q12. 一个舵机控制场景,按键按下调角度,应该用哪几方?

A:

时基单元(产生 50Hz PWM 周期 20ms)+ 捕获/比较单元(CCR 决定 0.5ms~2.5ms 高电平,对应角度);

不需要 DMA(角度不常变,按键改一次 CCR 就够);

用外部中断或按键扫描中断检测按键。


需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询