STM32 硬件 PWM 学习文档(以 STM32F103VB + PA1/TIM2_CH2/LED17 为例)
1. 学习目标
本文档用于梳理 STM32 硬件 PWM 的基础概念、参数计算方法、配置思路,以及本次实验中
用例:PA1 -> TIM2_CH2 -> LED17 的实际应用过程。
通过本文档,应能回答下面几个问题:
- 什么是 PWM
- STM32 的硬件 PWM 是怎么产生的
- 为什么
PSC、ARR、CCR要这样配置 PWM 频率和占空比分别由什么决定- 为什么某个 LED 能不能做硬件 PWM,要看引脚有没有
TIMx_CHx - 为什么
PA1可以做 LED17 的硬件 PWM
2. 本次实验背景
本次实验使用芯片为:
STM32F103VB
板上 LED17 对应到 MCU 的:
PA1
而 PA1 具备复用功能:
TIM2_CH2
因此可以将 PA1 配置为定时器 2 的通道 2 输出脚,使用 TIM2_CH2 输出硬件 PWM ,进而控制 LED17 的亮度变化。
3. 什么是 PWM
PWM,全称:
Pulse Width Modulation(脉冲宽度调制)
它的核心思想是:
在一个固定周期内,通过控制高电平持续时间所占的比例,来控制输出的平均效果。
例如,一个周期为 10ms:
- 高电平持续
1ms,低电平持续9ms,占空比为10% - 高电平持续
5ms,低电平持续5ms,占空比为50% - 高电平持续
9ms,低电平持续1ms,占空比为90%
对于 LED 来说,人眼看到的不是每一个瞬间的高低电平,而是一个"平均亮度":
- 占空比越大,通常越亮
- 占空比越小,通常越暗
4. 硬件 PWM 和软件 PWM 的区别
4.1 软件 PWM
软件 PWM 的典型做法是:
- 定时器周期性进入中断
- 在中断里手动控制 GPIO 输出高低电平
- 通过程序计算亮灭时间比例,模拟 PWM
特点:
- 实现直观
- 所有 GPIO 都可以尝试模拟
- 但 CPU 参与较多
- 中断负担更重
4.2 硬件 PWM
硬件 PWM 的典型做法是:
- 使用定时器内部的 PWM 模式
- 定时器自动产生 PWM 波形
- 通过
TIMx_CHx对应引脚直接输出
特点:
- 波形由硬件自动产生
- CPU 不需要反复翻转 GPIO
- 更稳定、更高效
- 但只能用具备
TIMx_CHx功能的引脚
4.3 本次实验属于
PA1 -> TIM2_CH2 -> LED17 的实验,属于:
硬件 PWM
∵ PWM 波形由 TIM2 的通道 2 直接输出到 PA1,不是通过中断手动翻转 GPIO 实现的。
5. STM32 硬件 PWM 的本质
STM32 硬件 PWM 的本质可以理解为:
- 定时器以一定速度计数
- 计数器从
0开始不断累加 - 当计数值小于某个比较值时,输出一种电平
- 当计数值大于等于该比较值时,输出另一种电平
- 当计数到周期上限后,重新回到
0,开始下一个周期
因此,硬件 PWM 的核心不是普通 GPIO,而是:
- 定时器计数
- 比较寄存器
- 输出通道
6. PWM 须掌握的几个核心概念
6.1 系统时钟
系统时钟是 MCU 运行的基础时钟来源。
本次实验中,使用简单的时钟配置:
HSI = 8MHz
也就是说,很多外设的基础时钟,都与这 8MHz 有关。
6.2 定时器时钟
定时器本身并不是凭空计数的,它的计数速度来自输入时钟。
在入门阶段,可以先简单理解成:
定时器拿到一个时钟后,经过预分频,再开始计数。
6.3 Prescaler(预分频器,PSC)
PSC 的作用是:
把输入给定时器的时钟先"减慢"
公式为:
text
定时器计数频率 = 定时器输入时钟 / (PSC + 1)
注意这里一定是:
text
PSC + 1
不是直接除以 PSC。
例如:
- 输入时钟 =
8MHz PSC = 7
那么:
text
定时器计数频率 = 8MHz / (7 + 1) = 1MHz
说明:
定时器现在每
1us计一次数每秒1M次
f= 1/T
6.4 Period(自动重装值,ARR)

ARR 的作用是:
决定计数器数到多少后重新从 0 开始
例如:
ARR = 999
那么计数过程为:
text
0, 1, 2, ... , 999
总共是 1000 个计数。
因此,一个完整 PWM 周期的计数长度为:
text
ARR + 1
6.5 Compare(比较值,CCR)
CCR 的作用是:
决定一个 PWM 周期中,高电平持续多长时间
在常见的 PWM1 模式下,可以简单理解为:
- 当
CNT < CCR时,输出高电平 - 当
CNT >= CCR时,输出低电平
因此:
CCR越大,高电平持续越久- 占空比越大
6.6 计数器(CNT)
CNT 是定时器当前正在计到的值。
比如:
- 当前
CNT = 100 - 当前
CCR = 500
若采用 PWM1 模式,则因为 100 < 500,输出保持高电平。
当 CNT 继续增加,到 500 及以上后,输出会切换为低电平。
7. PWM 频率和占空比公式
7.1 PWM 频率公式
PWM 频率由下面公式决定:
text
PWM频率 = 定时器输入时钟 / ((PSC + 1) × (ARR + 1))
这说明:
PSC影响计数速度ARR影响一个周期有多少个计数- 两者共同决定 PWM 的频率
7.2 占空比公式
占空比由下面公式决定:
text
占空比 = CCR / (ARR + 1)
这说明:
ARR决定总周期长度CCR决定高电平持续时间- 两者共同决定占空比
8. 举例为什么本次实验这样配置参数
本次实验采用的参数是:
- 系统时钟:
8MHz PSC = 7ARR = 999
目标是:
- 产生一个大约
1kHz的 PWM - 同时保留较高的占空比分辨率,便于 LED 调光更平滑
9. 参数计算过程详解
9.1 第一步:先确定系统时钟
本次实验使用最简单的内部高速时钟:
text
HSI = 8MHz
9.2 第二步:先决定计数频率
为了便于理解和计算,先将定时器计数频率设置为:
text
1MHz
为什么选 1MHz?
因为:
1MHz表示每1us计一次数- 时间单位直观
- 后续算周期和占空比都方便
根据公式:
text
定时器计数频率 = 定时器输入时钟 / (PSC + 1)
代入:
text
1MHz = 8MHz / (PSC + 1)
得到:
text
PSC + 1 = 8
PSC = 7
所以设置:
text
PSC = 7
9.3 第三步:确定 PWM 周期
目标 PWM 频率设为:
text
1kHz
也就是:
text
每秒 1000 个周期
每个周期 1ms
前面已经把计数频率设成了:
text
1MHz
即:
text
每 1us 计一次数
那么一个 1ms 周期内,需要计数:
text
1ms = 1000us
也就是:
text
1000 次
由于定时器从 0 开始计数,所以:
text
ARR = 1000 - 1 = 999
因此设置:
text
ARR = 999
9.4 第四步:验证 PWM 频率
将参数代入频率公式:
text
PWM频率 = 8MHz / ((7 + 1) × (999 + 1))
= 8MHz / (8 × 1000)
= 1kHz
所以该配置是正确的。
10. 为什么不选别的参数组合
实际上,并不是只有这一组参数能得到 1kHz PWM。
例如,也可以这样:
PSC = 79ARR = 99
因为:
text
8MHz / (79 + 1) = 100kHz
100kHz / (99 + 1) = 1kHz
最终频率也是 1kHz。
但是这两种配置的差别在于:
配置一:PSC = 7, ARR = 999
优点:
- 计数频率
1MHz,时间分辨率高 ARR = 999,占空比可调范围大约有 1000 档- LED 调光更细腻
配置二:PSC = 79, ARR = 99
特点:
- 计数频率较低
ARR = 99,占空比只有大约 100 档- 调节会更粗一些
因此,在 LED 呼吸灯这类应用中,通常更偏向:
在 PWM 频率满足要求的前提下,让
ARR稍大一些,从而获得更高的占空比分辨率
11. 为什么修改 CCR 就能改变 LED 亮度
假设当前:
ARR = 999
那么一个周期总共是 1000 个计数。
情况 1:CCR = 100
text
占空比 = 100 / 1000 = 10%
这意味着:
- 一个周期中只有约
10%的时间输出高电平 - LED 平均亮度较低
情况 2:CCR = 500
text
占空比 = 500 / 1000 = 50%
这意味着:
- 一个周期中约一半时间输出高电平
- LED 亮度中等
情况 3:CCR = 900
text
占空比 = 900 / 1000 = 90%
这意味着:
- 大部分时间输出高电平
- LED 平均亮度较高
因此,修改 CCR 就是在修改占空比,而占空比决定 LED 的平均亮度。
12. 为什么 PA1 必须配置为复用推挽输出
做硬件 PWM 时,PA1 不能再当普通 GPIO 使用,而要把该引脚交给定时器通道来控制。
因此必须配置为:
c
GPIO_MODE_AF_PP
含义为:
AF:Alternate Function,复用功能PP:Push Pull,推挽输出
如果配置成普通推挽输出:
c
GPIO_MODE_OUTPUT_PP
那 PA1 只是一个普通 GPIO,无法输出 TIM2_CH2 的 PWM 波形。
所以这一步是硬件 PWM 成功输出的关键条件之一。
13. 为什么要使用 TIM2_CH2
因为本次 LED17 接到的是:
PA1
而 PA1 具备的定时器通道功能是:
TIM2_CH2
所以如果想让 LED17 走硬件 PWM,必须满足下面这个链路:
text
TIM2 -> CH2 -> PA1 -> LED17
也就是说,硬件 PWM 不是任意 GPIO 都能做 ,而是要看该引脚有没有对应的 TIMx_CHx 功能。
14. 如何判断某个 LED 能不能做硬件 PWM
判断步骤通常如下:
第一步:看原理图
确认该 LED 接到了 MCU 的哪个引脚。
第二步:看该引脚复用功能
确认该引脚是否具备:
text
TIMx_CHx
例如:
PA1 -> TIM2_CH2PA0 -> TIM2_CH1
第三步:确认工程里能否将该引脚配置为复用输出
如果具备 TIMx_CHx,则可以尝试配置为硬件 PWM。
第四步:若没有 TIMx_CHx
则通常不能直接做硬件 PWM,只能考虑:
- 软件 PWM
- 或更换到支持 PWM 的引脚
15. 为什么本次 LED17 能做 PWM
本次实验中:
LED17 -> PA1PA1具备TIM2_CH2
因此满足硬件 PWM 的基本条件。
虽然板级原理图中 LED17 还经过了反相器等外围电路,但这不影响:
PA1输出 PWM 波形- 定时器使用
TIM2_CH2
只是可能会影响最终看到的亮暗逻辑方向。
也就是说:
- 占空比变大,可能看起来越来越亮
- 也可能因为板级反相,表现为越来越暗
但这不影响硬件 PWM 已经正确输出。
16. 为什么要选 1kHz 作为 LED PWM 频率
LED 做 PWM 调光时,频率不能太低。
如果频率过低,容易出现:
- 肉眼可见闪烁
- 视觉体验差
1kHz 是一个很常见、也很适合入门实验的频率,因为它:
- 足够高,不容易明显闪烁
- 参数容易计算
- 调试方便
当然,并不是只能选 1kHz,实际应用中还可能使用:
500Hz2kHz5kHz
但对学习阶段来说,1kHz 是一个很好的起点。
17. 一次完整的 PWM 参数设计思路
以后遇到 PWM 配置问题,可以按下面这个流程思考。
第一步:确定系统时钟
例如:
text
8MHz
第二步:确定目标 PWM 频率
例如:
text
1kHz
第三步:先选一个好理解的定时器计数频率
例如:
text
1MHz
这时:
text
PSC = 8MHz / 1MHz - 1 = 7
第四步:再根据 PWM 频率算 ARR
因为:
text
1MHz / 1kHz = 1000
所以:
text
ARR = 1000 - 1 = 999
第五步:根据占空比算 CCR
例如,若想要 50% 占空比:
text
CCR = 1000 × 50% = 500
这样整组参数就完整了。
18. 与本次实验相关的关键结论
18.1 参数结论
本实验设置:
PSC = 7ARR = 999
可得到:
- 定时器计数频率:
1MHz - PWM 频率:
1kHz
18.2 占空比调节方式
通过修改:
CCR
即可改变占空比,从而改变 LED17 的平均亮度。
18.3 引脚配置要求
PA1 必须配置为:
复用推挽输出
不能配置为普通 GPIO 输出。
18.4 引脚前提
某 LED 想做硬件 PWM,必须先确认其对应引脚具有:
TIMx_CHx
而 PA1 具备:
TIM2_CH2
所以可以实现硬件 PWM。
19. 容易混淆的几个点
19.1 为什么公式里总是 +1
无论是:
PSCARR
都要注意,硬件计数通常是从 0 开始的。
所以:
PSC = 7实际表示 8 分频ARR = 999实际表示一个周期共 1000 个计数
这是初学者最容易写错的地方之一。
19.2 PWM 频率和占空比不要混淆
PWM 频率由什么决定
由:
- 输入时钟
PSCARR
决定
占空比由什么决定
由:
CCRARR
决定
因此:
- 改
PSC、ARR,主要是在改 PWM 有多快 - 改
CCR,主要是在改 LED 有多亮
19.3 并不是所有 GPIO 都能直接输出硬件 PWM
只有当引脚带有:
text
TIMx_CHx
这类复用功能时,才适合直接做硬件 PWM。
如果没有该功能,则通常只能:
- 做普通 GPIO
- 做软件 PWM
20. 本次实验的理解模型
可以把 PWM 的参数理解成三层:
第一层:PSC
决定定时器"走得有多快"
第二层:ARR
决定"走多少步算一个周期"
第三层:CCR
决定"这个周期里有多少步保持高电平"
这个模型非常适合初学者建立整体认知。
21. 小结
本次基于 STM32F103VBT6 和 PA1/TIM2_CH2/LED17 的硬件 PWM 学习,核心结论如下:
- PWM 本质上是在固定周期内控制高电平持续时间比例的技术
- STM32 的硬件 PWM 由定时器自动产生,不需要 CPU 反复翻转 GPIO
PWM频率 = 定时器时钟 / ((PSC+1) × (ARR+1))占空比 = CCR / (ARR+1)PSC用于分频,ARR用于确定周期,CCR用于确定占空比- 本实验中
8MHz -> PSC=7 -> 1MHz计数频率 -> ARR=999 -> 1kHz PWM PA1因为具备TIM2_CH2功能,所以可以用于硬件 PWM 输出PA1必须配置为复用推挽输出,不能配置为普通 GPIO 输出- 通过动态修改
CCR,即可实现 LED17 的亮度调节和呼吸灯效果
22. 适合后续继续学习的方向
在掌握本文内容后,可以继续学习下面几个方向:
PWM1和PWM2模式的区别- 边沿对齐模式与中心对齐模式
- 高级定时器与普通定时器的区别
- 多通道 PWM 同步输出
- 通过按键切换占空比档位
- 通过 DMA 自动修改 CCR 实现更平滑呼吸灯
- PWM 驱动蜂鸣器、电机、舵机的不同参数配置思路