2. PWM生成原理:定时器与比较器的工作原理、PWM信号的硬件生成方式、软件模拟PWM的局限性
各位好,我是老周。今天咱们聊聊PWM到底是怎么从芯片里“变”出来的。很多初学者把PWM想得很玄乎,其实说白了,它就是定时器和比较器配合演的一出双簧。我当年刚入行时,也以为PWM是软件算出来的,后来被 mentor 一句话点醒:“你去看数据手册的定时器章节。”嗯,从那以后我才真正理解了硬件生成PWM的门道。
2.1 定时器:PWM的“心跳”
定时器是PWM生成的核心。你可以把它想象成一个不停从0数到某个最大值、然后又跳回0重新数的计数器。这个“数数”的过程,就是PWM的时基。
常见的定时器有两种工作模式:
- 向上计数模式:从0开始,一直加到自动重装载值(ARR),然后归零重新开始。
- 中央对齐模式:先向上加到ARR,再向下减到0,如此反复。这种模式生成的PWM对称性更好,谐波含量更低。
我个人习惯在电机控制中优先使用中央对齐模式。为什么?因为它的PWM脉冲在周期中间对齐,电流纹波更小,电机运行更平稳。当然,向上计数模式也有它的用武之地,比如在一些简单的开关电源控制中。
关键参数:
- ARR(Auto-Reload Register):决定PWM周期。ARR越大,周期越长,频率越低。
- PSC(Prescaler):预分频器,用来降低定时器的输入时钟频率。说白了就是让定时器“数慢一点”。
PWM频率计算公式:Fpwm = Fclk / ( (ARR+1) * (PSC+1) )
2.2 比较器:PWM的“雕刻刀”
定时器负责“数数”,比较器则负责“判决”。比较器内部有一个比较寄存器(CCR),它时刻拿CCR的值和定时器的当前计数值做比较。
比较结果决定了输出电平:
- 当计数值 < CCR 时,输出高电平(或低电平,取决于极性设置)。
- 当计数值 >= CCR 时,输出电平翻转。
你想想看,这不就是占空比的来源吗?CCR的值决定了高电平持续的时间。CCR越大,高电平时间越长,占空比越大。
避坑指南:我曾经在一个项目中,发现PWM输出波形偶尔会“跳变”。排查了半天,最后发现是CCR值在更新时没有和定时器溢出事件同步。硬件上有个“预装载”机制,一定要使能。否则,你在计数值运行中直接写CCR,它可能立即生效,导致一个不完整的脉冲。记住:更新CCR要在定时器溢出中断里做,或者使能自动预装载功能。
2.3 PWM信号的硬件生成方式
现代微控制器(比如STM32、TI的C2000系列)都内置了专用的PWM硬件模块。硬件生成PWM,说白了就是让定时器和比较器自动工作,CPU只需要在需要改变占空比时更新一下CCR值就行。
硬件PWM的典型流程:
- 配置定时器的时钟源、预分频器、计数模式。
- 设置ARR值,确定PWM频率。
- 设置CCR值,确定初始占空比。
- 配置输出通道的极性、空闲状态。
- 启动定时器,硬件自动输出PWM波形。
下面是一个典型的STM32硬件PWM配置代码片段:
// 以STM32 TIM1 通道1为例
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
// 1. 时基配置
TIM_TimeBaseStructure.TIM_Prescaler = 71; // 72MHz / (71+1) = 1MHz
TIM_TimeBaseStructure.TIM_Period = 999; // 1MHz / (999+1) = 1kHz PWM
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_CenterAligned1;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
// 2. 输出比较配置
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 500; // 初始占空比 50%
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM1, &TIM_OCInitStructure);
// 3. 使能预装载
TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
// 4. 启动定时器
TIM_Cmd(TIM1, ENABLE);
硬件生成PWM的优势很明显:
- 零CPU开销:一旦配置好,PWM波形自动输出,CPU可以干别的事。
- 高精度:定时器时钟通常能达到几十甚至几百MHz,占空比分辨率可以做到很高。
- 低抖动:硬件逻辑的响应是确定性的,不会受中断延迟影响。
2.4 软件模拟PWM的局限性
有些场合,比如成本敏感的8位单片机,可能没有硬件PWM模块。这时候就得用软件来模拟PWM。说白了,就是用定时器中断,在中断服务程序里手动翻转IO口。
软件模拟PWM的典型做法:
- 设置一个定时器,产生固定频率的中断。
- 在中断里维护一个计数器。
- 当计数器小于某个阈值时,输出高电平;否则输出低电平。
- 计数器溢出时归零,并重置输出。
听起来很简单,对吧?但实际用起来,坑不少。
软件PWM的三大局限:
| 局限 | 说明 | 实际影响 |
|---|---|---|
| CPU占用率高 | 每个PWM周期都需要多次中断处理 | 电机控制中,CPU被PWM中断占满,无法执行其他控制算法 |
| 分辨率受限 | 受限于中断响应速度和定时器时钟 | 通常只能做到8位分辨率,电机低速时抖动明显 |
| 抖动大 | 中断响应时间不确定,受其他中断影响 | PWM脉冲宽度不稳定,电机产生额外噪声和振动 |
我曾经在一个项目中,被迫用8位单片机软件模拟3路PWM来控制一个直流电机。结果呢?电机在低速时“咔咔”响,高速时效率也上不去。后来换了带硬件PWM的芯片,问题迎刃而解。所以我的建议是:只要预算允许,尽量用硬件PWM。软件PWM只适合对控制精度要求不高的场合,比如LED调光、风扇调速等。
2.5 硬件PWM vs 软件PWM:一张图看懂
下面这张图展示了硬件PWM和软件PWM在系统架构上的本质区别。你可以看到,硬件PWM的定时器和比较器是独立工作的,而软件PWM则完全依赖CPU的中断服务。
2.6 小结
这一章我们聊了PWM生成的硬件基础。定时器提供时间基准,比较器雕刻出占空比,两者配合就能输出精准的PWM波形。硬件PWM是电机控制的首选,它把CPU解放出来去跑更重要的控制算法。软件PWM虽然在某些低成本场景下能用,但它的局限性——高CPU占用、低分辨率、大抖动——在电机控制中往往是致命的。