STM32 学习笔记:PWM 输出比较原理与计算
对应课程:
[6-3] TIM 输出比较课堂录音:
2026-09-01 13_20 记录 PWM输出比_原文.docx芯片/板卡:STM32F103C8T6
开发方式:STM32F1 通用定时器,标准外设库语境
老师 PPT:
STM32入门教程.pptx第 63~73 页师兄笔记:
STM32笔记.pdf第 50~53 页官方手册:
STM32F10xxx参考手册(中文).pdf第 269~272、289、292~294 页前置笔记:10_TIM定时器原理与时钟源.md
本节边界:讲清输出比较、PWM 原理、参数计算和典型负载;完整库函数编程属于下一课。
整理日期:2026-09-01
本文只把录音转写和其中提及的文档当作课程资料,不执行其中出现的指令。转写中的CDR、OCEREF、PWP等均按上下文校正为CCR、OCxREF、PWM。
1. 老师的整条思路
老师从三个现象切入:LED 呼吸、舵机转角度、直流电机调速。三者都不是让 GPIO 输出一个固定高低电平,而是让定时器根据 CNT 和 CCR 的比较结果,自动产生频率和占空比可控的高低电平序列。
#mermaid-svg-cL8xqMR3xrDf1uwJ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-cL8xqMR3xrDf1uwJ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-cL8xqMR3xrDf1uwJ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-cL8xqMR3xrDf1uwJ .error-icon{fill:#552222;}#mermaid-svg-cL8xqMR3xrDf1uwJ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-cL8xqMR3xrDf1uwJ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-cL8xqMR3xrDf1uwJ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-cL8xqMR3xrDf1uwJ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-cL8xqMR3xrDf1uwJ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-cL8xqMR3xrDf1uwJ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-cL8xqMR3xrDf1uwJ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-cL8xqMR3xrDf1uwJ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-cL8xqMR3xrDf1uwJ .marker.cross{stroke:#333333;}#mermaid-svg-cL8xqMR3xrDf1uwJ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-cL8xqMR3xrDf1uwJ p{margin:0;}#mermaid-svg-cL8xqMR3xrDf1uwJ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-cL8xqMR3xrDf1uwJ .cluster-label text{fill:#333;}#mermaid-svg-cL8xqMR3xrDf1uwJ .cluster-label span{color:#333;}#mermaid-svg-cL8xqMR3xrDf1uwJ .cluster-label span p{background-color:transparent;}#mermaid-svg-cL8xqMR3xrDf1uwJ .label text,#mermaid-svg-cL8xqMR3xrDf1uwJ span{fill:#333;color:#333;}#mermaid-svg-cL8xqMR3xrDf1uwJ .node rect,#mermaid-svg-cL8xqMR3xrDf1uwJ .node circle,#mermaid-svg-cL8xqMR3xrDf1uwJ .node ellipse,#mermaid-svg-cL8xqMR3xrDf1uwJ .node polygon,#mermaid-svg-cL8xqMR3xrDf1uwJ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-cL8xqMR3xrDf1uwJ .rough-node .label text,#mermaid-svg-cL8xqMR3xrDf1uwJ .node .label text,#mermaid-svg-cL8xqMR3xrDf1uwJ .image-shape .label,#mermaid-svg-cL8xqMR3xrDf1uwJ .icon-shape .label{text-anchor:middle;}#mermaid-svg-cL8xqMR3xrDf1uwJ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-cL8xqMR3xrDf1uwJ .rough-node .label,#mermaid-svg-cL8xqMR3xrDf1uwJ .node .label,#mermaid-svg-cL8xqMR3xrDf1uwJ .image-shape .label,#mermaid-svg-cL8xqMR3xrDf1uwJ .icon-shape .label{text-align:center;}#mermaid-svg-cL8xqMR3xrDf1uwJ .node.clickable{cursor:pointer;}#mermaid-svg-cL8xqMR3xrDf1uwJ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-cL8xqMR3xrDf1uwJ .arrowheadPath{fill:#333333;}#mermaid-svg-cL8xqMR3xrDf1uwJ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-cL8xqMR3xrDf1uwJ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-cL8xqMR3xrDf1uwJ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cL8xqMR3xrDf1uwJ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-cL8xqMR3xrDf1uwJ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cL8xqMR3xrDf1uwJ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-cL8xqMR3xrDf1uwJ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-cL8xqMR3xrDf1uwJ .cluster text{fill:#333;}#mermaid-svg-cL8xqMR3xrDf1uwJ .cluster span{color:#333;}#mermaid-svg-cL8xqMR3xrDf1uwJ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-cL8xqMR3xrDf1uwJ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-cL8xqMR3xrDf1uwJ rect.text{fill:none;stroke-width:0;}#mermaid-svg-cL8xqMR3xrDf1uwJ .icon-shape,#mermaid-svg-cL8xqMR3xrDf1uwJ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cL8xqMR3xrDf1uwJ .icon-shape p,#mermaid-svg-cL8xqMR3xrDf1uwJ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-cL8xqMR3xrDf1uwJ .icon-shape .label rect,#mermaid-svg-cL8xqMR3xrDf1uwJ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cL8xqMR3xrDf1uwJ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-cL8xqMR3xrDf1uwJ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-cL8xqMR3xrDf1uwJ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 定时器时钟 f_TIM
PSC 分频
CNT 循环计数
ARR 决定周期
CCR 决定比较点
比较 CNT 与 CCR
OCxREF 参考信号
极性选择与通道使能
GPIO 输出 PWM
LED亮度 / 舵机角度 / 电机转速
一句话记住:
PSC决定 CNT 走多快,ARR决定多少拍为一个周期,CCR决定周期内何时翻转,输出比较单元把这个比较结果变成 PWM。
1.1 课堂时间线
| 录音时间 | 内容 |
|---|---|
00:02--02:06 |
LED 呼吸、舵机转角、直流电机调速演示 |
02:06--04:16 |
OC、IC、CC 缩写,输出比较的作用和通道数量 |
04:16--07:52 |
PWM 的惯性等效、频率、占空比、分辨率 |
07:52--13:39 |
输出比较通道结构、8 种比较模式、PWM 模式 1/2 |
13:39--16:58 |
PWM 基本结构及频率、占空比、分辨率公式 |
17:11--19:04 |
高级定时器的互补输出与死区(概念预览) |
19:04--22:46 |
SG90 舵机的 20 ms 周期和高电平脉宽 |
22:46--28:28 |
直流电机、H 桥、TB6612 和电源/共地 |
28:28--结束 |
在参考手册中查输出比较、PWM 模式和相关寄存器 |
2. 为什么需要输出比较
2.1 GPIO 软件翻转的问题
当然可以在循环或中断中不断改写 GPIO,但这种方式会带来:
- 高低电平宽度受代码执行时间和中断影响;
- CPU 必须反复参与;
- 频率提高、通道增多时更难稳定;
- 占空比的实时修改不易保持周期边界干净。
输出比较是定时器内部的硬件通道。CPU 只需预先写入 PSC、ARR、CCR和模式,之后每个 PWM 周期由硬件自动产生。
勘误:课堂中"PWM 频率越高,性能开销越大"适合做直观提醒,但对硬件 PWM 而言,CPU 不需逐边沿翻转 GPIO。频率提高更直接的代价是占空比分辨率下降,以及功率器件的开关损耗、EMI 增大。
2.2 OC、IC、CC 是什么
| 缩写 | 全称 | 本质 |
|---|---|---|
| OC | Output Compare | 用 CNT 与 CCR 的关系改变输出 |
| IC | Input Capture | 外部边沿到来时把 CNT 锁存进 CCR |
| CC | Capture/Compare | 捕获/比较单元的统称,CCR 被两种功能共用 |
STM32F1 的高级定时器和通用定时器通常有 4 个捕获/比较通道,基本定时器没有这些通道。一个定时器可以共享同一个 CNT/PSC/ARR,用不同 CCR1~CCR4 产生同频率、不同占空比的多路 PWM。

图 1 老师 PPT 第 63 页:输出比较通过 CNT--CCR 比较控制输出。
3. PWM 到底是什么
PWM(Pulse Width Modulation,脉冲宽度调制)是一串仍然只有高、低两种电平的数字波形。它不是 MCU 引脚真的输出了任意模拟电压,而是通过改变每个周期内高电平的持续时间,让负载的惯性或滤波电路表现出平均效果。

图 2 老师 PPT 第 64 页:PWM 周期、高电平时间和惯性等效。
3.1 三个核心参数
| 参数 | 定义 | 决定什么 |
|---|---|---|
周期 T |
一次完整高低电平循环的时间 | 波形重复速度 |
频率 f_PWM |
1/T |
每秒有多少个周期 |
占空比 D |
T_on/T |
高电平在周期中的比例 |
分辨率 ΔD |
占空比可调的最小步进 | 亮度/转速能调得多细 |
理想情况下,负载经过充分平均后:
V a v g ≈ D V H + ( 1 − D ) V L V_{avg} \approx D\,V_H+(1-D)V_L Vavg≈DVH+(1−D)VL
若低电平是 0 V,则:
V a v g ≈ D V H V_{avg} \approx D\,V_H Vavg≈DVH
例如高电平 5 V、占空比 50%,理想平均值约 2.5 V;占空比 20% 则约 1 V。录音转写中的"23%"与紧随其后的"1 V"不一致,按老师前后文应为 20%。
边界:电机转速不会必然与占空比严格线性,还受线圈电感、反电动势、摩擦、负载和驱动器压降影响。舵机则是把脉宽解码为位置指令,不是靠平均电压决定角度。
4. CNT 与 CCR 怎样生成 PWM
4.1 先看信号链路

图 3 老师 PPT 第 66 页:通用定时器一个输出比较通道的信号路径。
CNT按定时器计数时钟递增;- 数到
ARR后回到 0,开始新周期; - 比较器持续判断
CNT与当前CCRx的关系; OCxM选择的比较模式决定OCxREF变成高还是低;CCxP可以对参考信号做极性反相;CCxE允许信号输出到对应通道引脚。
OCxREF 是定时器内部的参考信号,并不一定等于引脚上的最终电平;极性和输出使能仍可改变最终结果。
4.2 PWM 模式 1,向上计数,高极性
这是本课公式的默认前提:
| CNT 范围 | OCxREF/引脚电平 |
|---|---|
0 ≤ CNT < CCR |
高电平(有效) |
CCR ≤ CNT ≤ ARR |
低电平(无效) |
每个周期共有 ARR+1 个计数拍,其中前 CCR 拍为高,所以:
D = C C R A R R + 1 D=\frac{CCR}{ARR+1} D=ARR+1CCR

图 4 老师 PPT 第 68 页:CNT 锯齿波、CCR 阈值与 REF 波形的对应关系。
4.3 极端值要单独理解
CCR |
PWM1、向上计数、高极性的结果 |
|---|---|
0 |
永远不满足 CNT < CCR,占空比 0% |
1 |
仅 CNT=0 时为高,占空比 1/(ARR+1) |
ARR |
占空比 ARR/(ARR+1),还差一拍才是 100% |
ARR+1 |
整个周期 CNT < CCR,占空比 100% |
因此不能把"CCR=ARR"机械地认为绝对 100%。
5. 输出比较的 8 种模式

图 5 老师 PPT 第 67 页:通用定时器的 8 种输出比较模式。
| 模式 | 比较时做什么 | 常见用途 |
|---|---|---|
| 冻结 | CNT=CCR 不改变 OCxREF |
只利用比较事件/标志,不动输出 |
| 匹配时置有效电平 | 匹配后强制为有效 | 到指定时刻置位 |
| 匹配时置无效电平 | 匹配后强制为无效 | 到指定时刻复位 |
| 匹配时电平翻转 | 每次匹配翻转一次 | 方波、精确翻转时刻 |
| 强制为无效电平 | 不等比较,直接强制无效 | 软件控制固定状态 |
| 强制为有效电平 | 不等比较,直接强制有效 | 软件控制固定状态 |
| PWM 模式 1 | 根据计数方向和 CNT--CCR 关系切换 | 常用 PWM |
| PWM 模式 2 | PWM1 的逻辑反相 | 需要相反参考波形时 |
在向上计数时:
- PWM1:
CNT < CCR时OCxREF有效; - PWM2:
CNT < CCR时OCxREF无效; - 若再把
CCxP设为低极性,最终引脚还会再反相一次。
所以判断最终波形必须同时看"计数方向 + PWM 模式 + 输出极性",不能只看 CCR。
6. 三个公式从哪里来
以向上计数、边沿对齐 PWM 为前提。
6.1 CNT 计数频率
PSC 寄存器存的是"分频系数减 1":
f C N T = f T I M P S C + 1 f_{CNT}=\frac{f_{TIM}}{PSC+1} fCNT=PSC+1fTIM
6.2 PWM 频率
CNT 从 0 数到 ARR,一共经历 ARR+1 个计数拍:
f P W M = f C N T A R R + 1 = f T I M ( P S C + 1 ) ( A R R + 1 ) f_{PWM}=\frac{f_{CNT}}{ARR+1} =\frac{f_{TIM}}{(PSC+1)(ARR+1)} fPWM=ARR+1fCNT=(PSC+1)(ARR+1)fTIM
6.3 占空比
PWM1 高极性时,高电平共有 CCR 个计数拍:
D = T o n T = C C R A R R + 1 D=\frac{T_{on}}{T}=\frac{CCR}{ARR+1} D=TTon=ARR+1CCR
T o n = C C R f C N T T_{on}=\frac{CCR}{f_{CNT}} Ton=fCNTCCR
6.4 占空比分辨率
CCR 每改变 1,占空比变化:
Δ D = 1 A R R + 1 \Delta D=\frac{1}{ARR+1} ΔD=ARR+11

图 6 老师 PPT 第 69 页:PWM 频率、占空比和分辨率公式。
6.5 频率和分辨率的取舍
当 f_TIM 和 PSC 固定时:
f P W M ( A R R + 1 ) = f T I M P S C + 1 f_{PWM}(ARR+1)=\frac{f_{TIM}}{PSC+1} fPWM(ARR+1)=PSC+1fTIM
想让 PWM 频率更高,往往要减小 ARR+1;但 ARR+1 越小,1/(ARR+1) 越大,占空比可调步进就越粗。这是 PWM 设计中最重要的取舍之一。
本节公式专属于向上计数的边沿对齐 PWM。中心对齐模式中 CNT 要向上再向下计数,周期不能继续直接套
ARR+1;参考手册第 270~271 页给出了中心对齐波形。
7. 计算例题
7.1 例 1:72 MHz 定时器产生 1 kHz、1% 步进的 PWM
要让占空比每次变化 1%:
1 A R R + 1 = 1 % = 0.01 \frac{1}{ARR+1}=1\%=0.01 ARR+11=1%=0.01
所以:
A R R + 1 = 100 ⇒ A R R = 99 ARR+1=100\Rightarrow ARR=99 ARR+1=100⇒ARR=99
再反推 PSC:
P S C + 1 = 72 000 000 1 000 × 100 = 720 PSC+1=\frac{72\,000\,000}{1\,000\times100}=720 PSC+1=1000×10072000000=720
因此:
text
PSC = 719
ARR = 99
CCR = 期望占空比(%)
例如要 30% 占空比:
C C R = 0.30 × 100 = 30 CCR=0.30\times100=30 CCR=0.30×100=30
此时周期 T=1 ms,高电平时间 T_on=0.3 ms。
| 目标占空比 | CCR |
|---|---|
| 0% | 0 |
| 1% | 1 |
| 30% | 30 |
| 50% | 50 |
| 100% | 100 |
7.2 例 2:20 kHz PWM,占空比 65%
设 f_TIM=72 MHz,不做预分频,即 PSC=0:
A R R + 1 = 72 000 000 20 000 = 3600 ARR+1=\frac{72\,000\,000}{20\,000}=3600 ARR+1=2000072000000=3600
所以 ARR=3599,分辨率为:
Δ D = 1 3600 ≈ 0.0278 % \Delta D=\frac{1}{3600}\approx0.0278\% ΔD=36001≈0.0278%
65% 占空比对应:
C C R = 0.65 × 3600 = 2340 CCR=0.65\times3600=2340 CCR=0.65×3600=2340
PWM 周期是 50 µs,高电平时间是 32.5 µs。
7.3 例 3:舵机 50 Hz,用 1 µs 作为脉宽计算单位
先把 72 MHz 分频到 1 MHz:
P S C + 1 = 72 ⇒ P S C = 71 PSC+1=72\Rightarrow PSC=71 PSC+1=72⇒PSC=71
此时 CNT 每走一格是 1 µs。20 ms 周期需要 20 000 格:
A R R = 20 000 − 1 = 19 999 ARR=20\,000-1=19\,999 ARR=20000−1=19999
| 高电平脉宽 | CCR | 在 20 ms 内的占空比 | 课堂示例角度 |
|---|---|---|---|
| 0.5 ms | 500 | 2.5% | -90° |
| 1.5 ms | 1500 | 7.5% | 0° |
| 2.5 ms | 2500 | 12.5% | +90° |
在课堂设定的 -90°~+90° 线性范围内,可写成:
C C R = 500 + A n g l e + 90 180 × 2000 CCR=500+\frac{Angle+90}{180}\times2000 CCR=500+180Angle+90×2000
模块限制:0.5~2.5 ms 和 ±90° 是本课演示采用的映射,不是所有舵机的统一强制规格。实际使用要查具体型号资料,逐步试探端点,否则可能顶住、抖动或损伤齿轮。
7.4 参数反推模板
渲染错误: Mermaid 渲染失败: Parse error on line 3: ...1 = f_TIM / f_PWM / (ARR+1)] C --> D -----------------------^ Expecting 'SQE', 'DOUBLECIRCLEEND', 'PE', '-)', 'STADIUMEND', 'SUBROUTINEEND', 'PIPE', 'CYLINDEREND', 'DIAMOND_STOP', 'TAGEND', 'TRAPEND', 'INVTRAPEND', 'UNICODE_TEXT', 'TEXT', 'TAGSTART', got 'PS'
实际工程中 PSC 和 ARR 都是整数,某些"频率 + 分辨率"组合不能同时精确满足。此时要根据负载优先级,在频率误差与占空比精度之间折中。
8. 三种负载对 PWM 的"理解"不同
8.1 LED:人眼感受平均亮度
PWM 高时 LED 亮,低时 LED 灭。当频率足够高,人眼因视觉暂留感觉到的是平均亮度。呼吸灯的本质是缓慢改变 CCR,而不是缓慢改变 PWM 频率。
8.2 舵机:脉宽是位置命令

图 7 老师 PPT 第 70 页:本课 SG90 演示采用 20 ms 周期和 0.5~2.5 ms 脉宽。
舵机的信号线只提供命令,不为电机供电。舵机需要合适的独立电源,并且舵机电源地必须与 STM32 共地,否则 PWM 没有共同的电平参考。
8.3 直流电机:PWM 经驱动器调功率

图 8 老师 PPT 第 72 页:GPIO 不能直接驱动电机,需要 H 桥驱动器。
STM32 GPIO 的输出电流能力远小于电机启动和堵转电流,不能直接接电机。TB6612 中的 H 桥承担功率开关:
AIN1/AIN2决定 A 路电机方向;PWMA接 PWM,决定通电比例;STBY要进入工作状态;VM是电机功率电源,VCC是逻辑电源,两者不可混淆;- STM32、TB6612 逻辑地和电机电源地需要共地。

图 9 老师 PPT 第 73 页:TB6612 模块引脚、接线和控制表。
9. 高级定时器:互补输出与死区
课堂在此只做概念介绍。TIM1 这类高级定时器的前 3 个通道可以同时输出主通道 CHx 和互补通道 CHxN。在半桥/全桥功率电路中,上、下管不能同时导通,否则电源会直通。
下管 死区时间 上管 下管 死区时间 上管 #mermaid-svg-U8QsPxFynFmdIY0c{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-U8QsPxFynFmdIY0c .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-U8QsPxFynFmdIY0c .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-U8QsPxFynFmdIY0c .error-icon{fill:#552222;}#mermaid-svg-U8QsPxFynFmdIY0c .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-U8QsPxFynFmdIY0c .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-U8QsPxFynFmdIY0c .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-U8QsPxFynFmdIY0c .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-U8QsPxFynFmdIY0c .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-U8QsPxFynFmdIY0c .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-U8QsPxFynFmdIY0c .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-U8QsPxFynFmdIY0c .marker{fill:#333333;stroke:#333333;}#mermaid-svg-U8QsPxFynFmdIY0c .marker.cross{stroke:#333333;}#mermaid-svg-U8QsPxFynFmdIY0c svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-U8QsPxFynFmdIY0c p{margin:0;}#mermaid-svg-U8QsPxFynFmdIY0c .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-U8QsPxFynFmdIY0c text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-U8QsPxFynFmdIY0c .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-U8QsPxFynFmdIY0c .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-U8QsPxFynFmdIY0c .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-U8QsPxFynFmdIY0c .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-U8QsPxFynFmdIY0c #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-U8QsPxFynFmdIY0c .sequenceNumber{fill:white;}#mermaid-svg-U8QsPxFynFmdIY0c #sequencenumber{fill:#333;}#mermaid-svg-U8QsPxFynFmdIY0c #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-U8QsPxFynFmdIY0c .messageText{fill:#333;stroke:none;}#mermaid-svg-U8QsPxFynFmdIY0c .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-U8QsPxFynFmdIY0c .labelText,#mermaid-svg-U8QsPxFynFmdIY0c .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-U8QsPxFynFmdIY0c .loopText,#mermaid-svg-U8QsPxFynFmdIY0c .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-U8QsPxFynFmdIY0c .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-U8QsPxFynFmdIY0c .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-U8QsPxFynFmdIY0c .noteText,#mermaid-svg-U8QsPxFynFmdIY0c .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-U8QsPxFynFmdIY0c .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-U8QsPxFynFmdIY0c .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-U8QsPxFynFmdIY0c .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-U8QsPxFynFmdIY0c .actorPopupMenu{position:absolute;}#mermaid-svg-U8QsPxFynFmdIY0c .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-U8QsPxFynFmdIY0c .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-U8QsPxFynFmdIY0c .actor-man circle,#mermaid-svg-U8QsPxFynFmdIY0c line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-U8QsPxFynFmdIY0c :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 两管均关断 关断 等待死区 导通
死区就是在一只管关断与另一只管导通之间故意留出的很短空白时间。本节的通用 PWM 计算不需要配置这部分。
10. 从原理到代码时的配置骨架
下一课写标准库代码时,不要背函数顺序,而要按信号链路追问"这一步打通了哪个硬件环节":
| 顺序 | 配置对象 | 解决的问题 |
|---|---|---|
| 1 | RCC 的 TIMx/GPIO/AFIO 时钟 | 定时器和引脚有没有工作时钟 |
| 2 | GPIO 复用推挽输出 | 让定时器通道,而不是 GPIO ODR,控制引脚 |
| 3 | 定时器时钟源 | CNT 的计数基准从哪里来 |
| 4 | PSC、ARR、计数方向 |
确定 CNT 速度和 PWM 周期 |
| 5 | CCxS=00、OCxM=PWM1/2 |
把 CC 通道设为输出,定义比较逻辑 |
| 6 | CCRx |
确定占空比/高电平脉宽 |
| 7 | CCxP、CCxE |
确定极性并开启通道输出 |
| 8 | OCxPE、ARPE |
在更新边界统一生效,减少中途改参数产生的异常窄脉冲 |
| 9 | CEN |
启动 CNT,让 PWM 硬件运行 |
对应的常用标准库概念是:
c
RCC_APB1PeriphClockCmd(...); // 定时器时钟
RCC_APB2PeriphClockCmd(...); // GPIO/AFIO 时钟
GPIO_Init(...); // 复用推挽输出
TIM_InternalClockConfig(...); // 选内部时钟
TIM_TimeBaseInit(...); // PSC、ARR、计数模式
TIM_OCxInit(...); // PWM模式、极性、CCR
TIM_OCxPreloadConfig(...); // CCR 预装载
TIM_ARRPreloadConfig(...); // ARR 预装载
TIM_Cmd(...); // 开始计数
注意:具体通道引脚必须查所用芯片的数据手册引脚表,并确认是否启用 AFIO 重映射。参考手册讲"外设怎样工作",数据手册才讲"这个型号的哪个脚引出了该通道"。
11. 参考手册怎样查
本节不需要从手册首页顺着读。按以下索引进入:
| 想查的问题 | 手册位置 | 关键内容 |
|---|---|---|
| 输出比较怎样配 | 第 269 页,14.3.9 前的配置步骤 | 时钟、ARR/CCRx、中断/DMA、模式、极性、输出使能、启动计数器 |
| PWM 模式 1/2 的逻辑 | 第 269~270 页,14.3.9 | 向上/向下计数时 CNT--CCR 与 OCxREF 的关系 |
| 中心对齐波形 | 第 270~271 页,图 128~129 | 边沿对齐与中心对齐比较时序 |
OC1M、OC1PE、CC1S |
第 289 页,TIMx_CCMR1 |
通道方向、比较模式、CCR 预装载 |
CC1P、CC1E |
第 292 页,TIMx_CCER |
输出极性和通道使能 |
CNT、PSC、ARR、CCRx |
第 293~294 页 | 计数值、预分频、周期和比较值 |
官方手册将"功能描述"和"寄存器定义"分开。正确的查法是先在 14.3.9 看逻辑和时序图,再到 14.4 查对应位,不要只看寄存器表猜整个功能。
12. 易错点与课堂补充
- 忘记
+1:PSC和ARR均从 0 计数,公式用的是PSC+1、ARR+1。 - 把 CCR 当周期:周期主要由 PSC、ARR 决定;CCR 在正常 PWM 范围内只改变比较点。
- 把 PWM 当 DAC:引脚仍在高低电平间切换,需负载惯性或低通滤波才有平均效果。
- 只看 PWM1/2,不看极性 :
CCxP可再反相,最终引脚电平可能与OCxREF相反。 - 认为
CCR=ARR必然 100% :在本节设定中它是ARR/(ARR+1),100% 对应CCR=ARR+1。 - 以为频率越高总是越好:还要考虑分辨率、开关损耗、噪声、EMI 和负载接受范围。
- 舵机直接吃 MCU 电源:舵机启动/堵转电流可能让 MCU 复位,应正确供电并共地。
- GPIO 直接带电机:GPIO 只提供逻辑信号,功率电流必须经电机驱动器。
- 忽略预装载:运行中修改 ARR/CCR 时,预装载能让新值在统一更新边界生效,避免本周期被中途截断。
13. 复习自测
- 为什么说 PWM 是数字波形,却又能"等效"调节亮度或功率?
PSC、ARR、CCR各自改变什么?- 为什么频率公式中有两个
+1? - PWM1、向上计数、高极性时,
CNT=CCR的那一拍是高还是低? ARR=999时,占空比最小可调步进是多少?30% 应写多少 CCR?- 已知
f_TIM=72 MHz、PSC=71、ARR=19999,PWM 频率是多少?CCR=1500时高电平多宽? - 为什么 PWM2 不一定就等于最终引脚上 PWM1 的反相?
- 同一个 TIM 的 CH1~CH4 能否产生不同频率?为什么?
- 为什么舵机的 7.5% 占空比不应理解为"只给舵机 7.5% 的电压"?
- 遇到"目标频率与目标分辨率无法同时整除"时,应怎样处理?
自测答案要点
- 引脚只有高低电平;负载惯性/滤波对脉冲做时间平均。
- PSC 管 CNT 时钟,ARR 管周期,CCR 管比较点/占空比。
- 寄存器值从 0 开始计数。
- 低电平,因为有效条件是
CNT < CCR。 1/(999+1)=0.1%;CCR=300。50 Hz;1500 µs=1.5 ms。- 最终还受
CCxP极性影响。 - 通常不能独立设频率,因为共享 PSC、ARR、CNT;但可有不同 CCR,即不同占空比。
- 舵机信号线传输脉宽命令,电机功率由舵机的供电线提供。
- 调整 ARR/PSC,并按应用的优先级接受频率误差或分辨率损失,最后回算实际值。
14. 参考资料与页码索引
| 资料 | 位置 | 本文用途 |
|---|---|---|
| 课堂录音转写 | 2026-09-01 13_20 记录 PWM输出比_原文.docx,00:02--29:13 |
讲解顺序、演示、参数公式和手册查阅思路 |
| 老师 PPT | 第 63 页 | 输出比较定义、通道数量 |
| 老师 PPT | 第 64 页 | PWM 定义、波形和三个参数 |
| 老师 PPT | 第 65~66 页 | 高级/通用定时器输出比较通道框图 |
| 老师 PPT | 第 67 页 | 8 种输出比较模式 |
| 老师 PPT | 第 68~69 页 | PWM 基本结构和计算公式 |
| 老师 PPT | 第 70~71 页 | 舵机脉宽与接线 |
| 老师 PPT | 第 72~73 页 | 直流电机、TB6612、H 桥和接线 |
| 师兄笔记 | 第 50~51 页 | OC/PWM 概念、通道框图和模式表 |
| 师兄笔记 | 第 52 页 | PWM 结构、参数计算和舵机脉宽 |
| 师兄笔记 | 第 53 页 | 舵机接线、直流电机与 TB6612 |
| STM32F10xxx 参考手册 | 第 269~272 页 | 输出比较配置、PWM 模式 1/2、边沿/中心对齐时序 |
| STM32F10xxx 参考手册 | 第 289 页 | TIMx_CCMR1:CC1S、OC1PE、OC1M |
| STM32F10xxx 参考手册 | 第 292 页 | TIMx_CCER:通道输出使能和极性 |
| STM32F10xxx 参考手册 | 第 293~294 页 | CNT、PSC、ARR、CCRx 定义 |
15. 一句话总结
STM32 PWM 的本质是:定时器让 CNT 按 PSC 规定的速度在
0~ARR之间循环,输出比较单元用 CCR 设定周期内的切换时刻,再经模式、极性和使能逻辑把数字脉冲送到 GPIO;因而 PSC/ARR 定频率,CCR 定占空比,负载决定这串脉冲最终表现为亮度、角度还是转速。