欢迎光临
我们一直在努力

【STM32】 通用定时器 TIM 详解:从概念到 PWM 速通


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_CCMR1 0x18 通道 1、2 的模式配置(输出比较模式 / 输入捕获模式、预分频、滤波器)
TIMx_CCMR2 0x1C 通道 3、4 的模式配置
TIMx_CCER 0x20 通道输出使能(CCxE)、极性(CCxP)
TIMx_CCR1~CCR4 0x34 / 0x38 / 0x3C / 0x40 捕获/比较寄存器(16 位,设定"比较阈值")
TIMx_CR1 0x00 比基础定时器多了 DIR(位4)、CMS[1:0](位6:5)
TIMx_SMCR 0x08 从模式控制(外部时钟、编码器模式)

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 始终为有效(软件强制)
110 PWM 模式 1 向上计数时:CNT < CCR → 有效;CNT ≥ CCR → 无效
111 PWM 模式 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 两个核心数

设定决定什么怎么算
ARR PWM 的周期(频率) PWM 频率 = CK_CNT / (ARR+1) = TIMxCLK / ((PSC+1)(ARR+1))
CCR PWM 的占空比(高电平宽度) 占空比 = 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 就够);

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


赞(0)
未经允许不得转载:171主机测评 » 【STM32】 通用定时器 TIM 详解:从概念到 PWM 速通
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址