ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

PWM流程架构详解:从定时器配置到负载动作

PWM流程架构详解:从定时器配置到负载动作 很多朋友第一次接触PWM上来就是打开CubeMX点两下生成一个50Hz的PWM调调占空比让舵机转个角度。能转吗能。但后面问题就来了为什么我用同一个定时器一会儿输出PWM一会儿捕获输入它就乱了为什么我配置了死区电机驱动还是烧管子为什么占空比调到100%的时候波形反而没了这些问题的根源不是某个寄存器配错了而是脑子里缺一张图——一张从“软件配置”到“引脚电平”再到“功率器件动作”的完整流程图。这篇是PWM理论模型基础系列的第一篇我打算把PWM这条链路从里到外拆开讲它到底是怎么产生的、每一层是什么角色、为什么每个环节都有讲究。标题里的“流程架构”四个字我理解成一条信号链从定时器时钟到计数器比较到输出引脚/死区/故障保护再到外部驱动电路和负载。下面就用做项目的口吻带你把这条链走一遍。1. 先把“PWM到底在干什么”说清楚1.1 从“调电压”到“调时间”PWM的本质我接触过的不少初学者对PWM有个思维惯性PWM就是在调电压。这个理解不算错但很危险因为它混淆了“平均效果”和“瞬时状态”。从物理上看PWM输出的是连续的数字方波只有高电平或低电平两种状态它没有中间档位。真正连续的东西是它在一个周期内高电平的时间占比这个占比叫占空比。占空比50%意味着高电平占一半周期平均电压是供电电压的一半理论上但瞬时电压不是一半它依然是满幅。用一个生活化类比你有一个水龙头拧一半开是连续水流PWM不是“拧一半的水龙头”而是“极快地全开、全关、再全开、再全关”。你盯着水滴时它是断续的但放在大水箱里看水位上涨速度却可以连续调节。所以PWM的本质不是“调电压”而是“调时间”——通过精确控制导通时间在一个周期内的占比来等效出一个可控的平均效果。这个区别直接决定了后面很多技术选择。比如你给LED调亮度PWM频率够高时人眼感觉不到闪烁这是“视觉暂留”在帮PWM做低通滤波你给电机调速是电机的机械惯量在帮PWM做低通滤波你给加热丝控温是热惯性在帮PWM做低通滤波。你会发现PWM的负载几乎都有“惯性”这一共同特征。无惯性负载或者对纹波极敏感的负载直接用PWM是会有问题的后面讲RC滤波和三倍压电路时会再提到。1.2 为什么PWM在嵌入式里无处不在说PWM是嵌入式工程师接触频率最高的外设功能之一不过分。它一台微控制器上从几十kHz的电机调速到几百Hz的舵机控制再到 kHz 级甚至 MHz 级的电源开关控制全都能干。上到应用处理器RK3588中到STM32、DSP28335、STC8H下到NE555搭建的纯硬件电路PWM这个“概念”是通的变的只是实现方式。我对“流程架构理解”这个标题的解读是你要建立一张PWM信号链全景图。这张图从软件寄存器配置开始经过硬件定时器逻辑最终反映到外部负载的动作上。如果你对流程中每一级的角色都清晰那么无论换哪款芯片、哪个工具你都能快速定位问题。反之你只是会用STM32的某个例程换一个芯片平台就会很痛苦。2. PWM流程架构的整体拆解一条链路走完2.1 五层链路模型从寄存器到负载动作我习惯把PWM工程链路分成五层你可以把它当成一个汉堡结构从顶部到底部一层层看配置层时钟、定时器预分频、自动重载值、比较值、极性、死区、故障保护使能。生成层计数器的计数方式向上/向下/中央对齐、比较器的输出逻辑产生原始PWM脉冲序列。调理层死区插入、电平极性反转、故障封锁、输出使能控制。驱动层外部MOSFET驱动器、光耦隔离、RC滤波、上拉下拉。负载层LED、电机、舵机、加热器、开关电源、蜂鸣器等实际被控对象。如果你用MCU内部定时器配置层到调理层都在芯片内部完成你不太看得见所以容易忽略。但你一旦用NE555搭纯硬件PWM前三层全变成了电阻电容的搭配事情就变得直观得多。而用STM32、DSP28335这类芯片前三层是由寄存器帮你实现的。我推荐大家在调试时做一个习惯像检查网络分层一样一层一层判断。波形不对先确认配置层有没有问题再看生成层寄存器值是否符合预期再查调理层是否把信号改变了最后才怀疑外部驱动电路。这五个层级对应到排查里就是一套非常高效的问题定位法。2.2 信号是怎么从定时器“流”到引脚的以STM32F103的TIM3为例它内部有一条类似这样的流时钟源 → 预分频器PSC → 计数器CNT → 比较器CCR → 输出控制CCER/CCMR → 输出引脚经过重映射配置。TIM3挂载在APB1上但你切记一个坑APB1的定时器时钟并不等于APB1总线时钟这里有个倍频器STM32F103上通常定时器时钟是72MHz别只看到APB1是36MHz就以为完了。计数器的值CNT在每个时钟周期递增或递减同时CCR寄存器里存着一个预先设置好的比较值比较器就是干一件事判断CNT和CCR的关系输出高或低。向上计数模式下CNT小于CCR输出高反之输出低就产生了一个占空比由CCR决定的PWM波形。ARR自动重载值决定计数周期也就是PWM的周期CCR决定高电平时间。一句话记住核心ARR定频率CCR定占空比。PSC预分频器在这里扮演的角色是“精细调频”和“降低计数速度”。频率计算公式是PWM频率 定时器时钟 / ((PSC1) * (ARR1))这里所有值都加1是因为很多芯片的寄存器从0计起。我见过很多人把ARR计算对了却忘了PSC也要加1结果频率差一倍调了半天找不到原因。到了输出控制层CCER里的极性位和使能位会决定信号是直接输出还是翻转输出输出引脚在哪一个GPIO口则由AFIO重映射寄存器决定。TIM3的重映射可以把输出引脚从默认的PA6/PA7映射到PB4/PB5部分重映射或PC6/PC7完全重映射这在PCB走线打架的时候非常有用。你要是忘了开启重映射时钟AFIO时钟配置了寄存器也白搭这是很多人忽略的坑。3. 三个决定系统行为的核心参数3.1 频率先想清楚你要多快很多人配置PWM的时候第一件事就是问频率到底该设多少我的习惯是倒推从负载需求倒推参数。LED呼吸灯/照明调光频率应该大于100Hz不然人眼能感觉到闪烁实际我一般起步256Hz或者更高。舵机控制航模舵机的PWM周期固定为20ms50Hz高电平时间0.5ms~2.5ms对应角度。这个频率是舵机内部电路定义的你不能随便改。直流减速电机调速常见几百Hz到几十kHz。太低了电机会发出明显的“嗡嗡”噪声太高了MOSFET开关损耗会变大。开关电源BUCK之类典型频率几十kHz到几MHz频率选择跟电感、电容体积、损耗都相关高频可以缩小磁芯但驱动的开关损耗也随之上升。频率不是越高越好但也不是越低越好它是一门折中艺术。我做直流电机驱动时最常用8kHz~20kHz这个区间既能避开人耳敏感区又不会让MOSFET开关损耗难以接受。再补充一个跟频率强相关的问题分辨率。PWM的分辨率 log2(ARR1)也就是说ARR值越大占空比能调的步进越细。比如ARR 999占空比可以1/1000的步进调对应的分辨率大约10位如果ARR 99就只有7位左右。频率和分辨率是矛盾的你想要的PWM频率越高ARR必须越小占空比分辨率就越差。做LED调光时这个矛盾尤其明显有些人非要用20kHz调光结果发现亮度变化有可见的阶梯感就是因为分辨率不够了。3.2 占空比最直观的控制量占空比的定义是高电平时间占整个周期的百分比公式为Duty CCR / (ARR1)向上计数模式不考虑死区。我一直觉得占空比是这三个参数里最好理解但最容易被忽略细节的一个。细节在哪两个地方一是极性二是死区对有效占空比的影响。先说极性。很多芯片的PWM输出极性寄存器默认是“高电平有效”也就是CCR决定的是高电平时间。但有些应用里你可能希望反转比如你外部接了一个低电平导通的驱动电路。STM32里CCER的CC1P位就是干这个的。如果你把极性搞反了LED会变成“关灯呼吸”——占空比100%时反而不亮这类现象排查起来容易让人懵其实看一眼寄存器就能定位。再说死区。死区对占空比的“吃掉”效应后面细讲这里先记住一个结论你在CCR里写的值决定的是理想占空比但最终作用到负载上的有效占空比可能小于理想值因为插入死区后一部分时间既不是上桥导通也不是下桥导通。在高频大功率场景下这个差值不能忽略。3.3 死区桥式驱动里不能省的过渡时间死区这个名词在热搜词里反复出现——28335配置的PWM里DBFED和DBRED、死区主源选择、STM32死区等等可见它确实是把很多人绕晕的地方。先说为什么需要死区。你现在有一个H桥或者半桥驱动电路上下两个MOSFET串联在电源和地之间。如果上下桥同时导通就是电源正负极直接短路这叫“直通”轻则发烫重则炸管。但MOSFET的导通和关断都需要时间不是开关一给信号立刻就完全换向的。如果你输出PWM的上下桥信号是严格互补的即一个关断的同时另一个导通那在开关瞬间会有重叠导通的风险。死区就是干这个的在一路关断和另一路导通之间插入一段两边都关断的时间确保安全。比如你期望占空比50%插入死区后实际有效占空比会略低一点。DSP28335里DBFEDDead-Band Falling Edge Delay下降沿延迟和DBREDDead-Band Rising Edge Delay上升沿延迟是死区配置的核心。上升沿延迟是对PWM信号从低到高的跳变做延迟下降沿延迟则对从高到低的跳变做延迟。配合死区主源选择、极性控制一套完整的死区逻辑就出来了。如果你在28335上配置死区时遇到“主源选择有什么要求”这类疑问我建议先回答自己三个问题你用的是哪一路PWM信号作为源你输出的极性是高有效还是低有效你的延迟是要加在上升沿还是下降沿理清这三件事死区寄存器配置就不会乱了。STM32的话刹车寄存器BDTR里的DTG位段就是设死区的单位跟定时器时钟挂钩。假设定时器时钟72MHz一个时钟周期约13.89ns如果你想要1us的死区DTG要写的值大约是72。注意DTG的高位还有几位决定死区时间的倍率关系不同区间换算方式不同别一上来就线性套用。4. 从理论到寄存器用STM32F103的TIM3做一个呼吸灯4.1 引脚重映射为什么默认引脚上没波形可以说呼吸灯是PWM入门的“Hello World”但即便这么简单的项目也能扯出重映射的问题。TIM3的PWM默认输出在PA6通道1和PA7通道2但很多人用STM32F103ZET6这种大芯片时PA6/PA7往往被别的功能占了比如ADC输入或者外部中断。这时候就需要引脚重映射。TIM3在STM32F103上有三种输出引脚选择默认映射PA6、PA7、PB0、PB1。部分重映射PB4、PB5、PB0、PB1。完全重映射PC6、PC7、PC8、PC9。我把某些应用场景里“默认无波形”的原因列出来你对照检查重映射寄存器AFIO_MAPR没有配置对应位或者配置了但没开AFIO时钟。重映射对应的GPIO时钟和引脚模式没配置复用推挽输出。定时器时钟没使能。用了错误的库函数版本把“部分重映射”的宏定义写成了别的型号的。体重映射操作的顺序也有讲究。我推荐的标准顺序是先开GPIO时钟和AFIO时钟再选重映射模式再配置GPIO复用功能再开定时器时钟最后配置定时器参数。如果你没有严格按“先时钟、后复用”的顺序可能出现一种很难查的灵异现象逻辑上查寄存器都对但引脚就是没输出。其实是GPIO复用功能在你设置完之后被后续某个操作意外覆写了。4.2 定时器配置与占空比调节呼吸效果怎么实现呼吸灯的“呼吸感”来源于占空比按正弦变化或者三角波变化。我先给一组最常用的基础配置基于STM32F103定时器时钟72MHz目标PWM频率1kHz预分频PSC 71这意味着72MHz / (711) 1MHz的计数频率。自动重载ARR 999那么PWM频率 1MHz / (9991) 1kHz。比较值CCR从0到999变化占空比就从0%到100%。代码逻辑很简单主循环里让CCR逐步增加到一个周期后逐步减少。用延时或者用定时器中断控制步进时间。实际做出来你会发现线性变化的呼吸感很机械像开关灯一样。更好看的是正弦变化就是让CCR 500 500 * sin(角度)做一个256点的正弦表按固定时间间隔查表更新呼吸感就非常自然。这里有一个细节容易被忽略你要是直接在主循环里用定时器中断更新CCR而定时器中断优先级设置不合适呼吸灯会偶发卡顿因为其他中断抢占了它的时机。我把定时器更新中断优先级设得比串口高呼吸会明显顺滑很多。4.3 100%占空比异常这条热搜问题的真相热搜词里有“stm32定时器输出pwm时100占空比异常”我猜有不少人碰到过这个问题。现象通常是CCR设成等于ARR或者大于ARR时PWM波形忽然没了或者变成了一个常高电平但毛刺非常多。原因在于PWM生成模式的具体规则。在PWM模式1下向上计数当CNT CCR时输出有效电平否则输出无效电平。如果CCR 0那么永远不会有CNT CCR输出一直是无效电平占空比0%如果CCR ARR 1或者更大那CNT就永远小于CCR输出一直是有效电平占空比100%。看起来没问题对吧问题出在边界设定。某些配置下当CCR ARR时输出不是100%占空比而是99.9%。因为计数器CNT是从0计到ARR的当CNT ARR时如果比较条件不是“严格小于”而是“小于等于”那么在一个计数周期内存在一个时钟周期CNT ARR且CCR ARR的比较成立在高电平区间会有一个极小缺口。这个缺口在示波器上看就是窄脉冲毛刺如果后级是电机驱动这个毛刺可能产生额外的开关噪声。解决方法是根据芯片参考手册确认比较器是“小于还是小于等于”生效。多数情况下你要100%占空比可以把CCR设成ARR1或者直接使用强制输出高电平的控制位。反过来要0%占空比把CCR设0就行不行就强制输出低电平。这个“强制输出”的功能在STM32里是通过CCER的CCxE和CCxP配合实现的很多资料讲得不多但它非常实用。5. 一个容易踩坑的环节故障保护与PWM刹车5.1 故障保护的触发链路热搜词里有“pwm故障保护”这个在电机驱动、电源领域极其重要但在普通LED呼吸灯工程里完全用不到所以很多入门教程根本不提。这张图必须补上PWM信号链路不是单向的从输出级反馈回来还可能有一个“刹车信号”把你的PWM一脚踩停。以STM32的TIM1/TIM8高级定时器为例它们有刹车输入BRK。当刹车输入有效比如外部电路检测到过流、过压输出引脚会被硬件强制拉低或拉到安全状态不需要软件干预。这种“硬件级保护”和“软件中断里关PWM”有本质区别软件响应中断需要若干指令周期如果是微秒级过流软件根本来不及硬件刹车是纳秒级反应靠的是逻辑电路。我见过有人在无刷电机驱动器里把过流比较器的输出直接接到STM32的刹车输入。一旦电流超限PWM立即被硬件封锁几微秒内完成保护然后产生中断让软件去做后续的状态处理和记录。没有这种机制高压大电流场景非常危险。但刹车功能也有坑刹车输入的极性、自动重新加载和复位行为配置不对可能导致系统启动时PWM一直锁死。我调试时遇到过类似情况——板子上电PWM输出就是不出来查了半天发现是刹车输入引脚悬空电平不可控芯片认为一直处于刹车状态。解决办法是把刹车输入极性配成默认安全电平或者加上下拉电阻固定电平。5.2 故障保护引发的“输出为什么没了”排查我再把故障保护跟前面的流程架构串起来。假设你有一个PWM输出一开始正常运行一段时间后消失多半要对保护链路做以下几件事查状态寄存器看是否有刹车/故障标志被置位。查故障标志对应的输入源理解外部信号是主动触发的还是干扰误触发的。是干扰误触发就要检查硬件去抖/滤波或者把刹车输入改成“只在可控条件下使能”。是主动触发就说明系统确实处于异常状态这时候不要急着清标志先找到异常根源否则一清标志就再次触发反而掩盖了故障。DSP28335的故障区Trip Zone逻辑也类似。28335的TZ模块可以通过EPWM模块的事件触发强制拉低PWM输出每个TZ输入都有极性选择和一次性/周期性的锁定模式。它的TZCLR寄存器决定故障条件清除方式。实际调试28335的PWM时我遇到比较多的问题是TZSEL配置了周期锁定故障条件消失后没有手动清标志导致输出一直被钳在安全电平。这类问题通常看TZFLG的置位情况就能定位。6. 进阶链路CCU6、RK3588、软件PWM与特殊应用6.1 不同MCU平台对PWM的描述方式不同但架构相通热搜词里出现了CCU6、RK3588我简单串一下。CCU6是英飞凌Infineon芯片里比较有代表性的定时器单元它的特色在于比较和捕获逻辑异常灵活支持多通道同步输出尤其在车规级电机控制里用得多。你在CCU6里能看到类似STM32的Timer的概念但它的寄存器名称、同步机制和故障处理单元都不一样。掌握了流程架构之后你去看CCU6手册时会自动把它“翻译”成自己熟悉的概念表T12/T13对应主定时器CC60/CC61/CC62对应比较通道死区发生器对应DB故障输入对应Trap。RK3588这种应用处理器情况更复杂它带有独立的PWM控制器可以输出PWM也可以做PWM Capture。热搜词里的“rk3588 pwm capture”值得单独说一句PWM Capture就是测外部PWM信号的频率和占空比这在测速、解码一些传感器信号时很常用。它的本质还是一个输入捕获功能但跟纯捕获模式不同在于它专门针对“周期占空比”做了硬件化处理你配置好之后去读寄存器就能直接得到频率和占空比数值不需要在中断里手动算边沿时间。使用RK3588的PWM时最大的坑在于设备树。一个PWM控制器的节点绑定了很多属性时钟源频率、pwm-cells、compatible、通道号等。你在内核里要确认使用的PWM通道有没有被别的驱动占用有没有配置正确的pinctrl。我之前在RK3588上调了一个PWM风扇调速设备树配置了但导出不成功最后发现是pinmux被某个默认功能占了pinctrl没设置对板子系统起来后引脚被复用成了别的功能。这类问题在高端SoC上比单片机更常见因为管脚复用特别复杂。6.2 软件PWM与纯硬件PWM流程架构视角下的对比不是所有场景都需要硬件PWM。有时候你的MCU所有定时器的PWM通道都被用光了或者你只需要一个慢速、精度要求不高的PWM那就可以用“软件PWM”顶一下。软件PWM的道理非常简单用一个定时器中断周期性触发在中断里翻转IO口电平根据一个软件计数器判断该高还是该低。比如你设定一个1kHz的周期中断溢出1000次为1个PWM周期每周期前N次中断输出高后1000-N次输出低N就对应占空比的千分比。优点显而易见灵活任意IO都能输出PWM不需要额外的定时器硬件。缺点也很致命当PWM频率稍微高一点MCU的算力全被中断吃掉了。STM32F103跑一个16kHz的软件PWM每周期可能需要几十微秒的中断处理时间高优先级任务会被严重打扰。所以我的经验是软件PWM仅用于低频低精度场合比如一颗状态指示灯的呼吸效果或者一个大惯性加热环节的简单调功。真要控制电机还是老老实实用硬件PWM。至于NE555做PWM我特别推荐大家搭一次。NE555工作在无稳态模式通过改变控制电压或电阻比例来调节频率和占空比。典型电路接成频率固定、占空比可调的25kHz信号发生器用来驱动一个小功率开关。NE555搭建出来的PWM有一个特点它的占空比调节范围和频率是相互影响的想做独立调节得加二极管或专用电路。热搜词“ne555做一个pwm频率固定可调25k占空比的线路”说的就是这个场景。我可以给一个参考思路用555的DIS和THR引脚配合两个电位器实现频率和占空比近似独立调节但这只能做到近似无法完全解耦。真要频率、占空比完全独立用MCU的硬件定时器更合适。我在做实验时还会额外提“单总线PWM”和“PWM控制RC电路”“PWM三倍压电路”。单总线PWM通常指用一根线同时传数据和时钟或者用PWM引脚模拟单总线协议这在LED灯带、某些传感器通信里有应用。而PWM控制RC电路是利用PWM经过RC低通滤波变成模拟电压形成简易DAC搜“pwm 三倍压电路”的朋友大概率是想用PWM驱动电荷泵实现升压。这两个场景有个共同的流程逻辑PWM在这里只是一个“高频且可调的开关信号”真正实现功能的是外部电容电感和二极管构成的滤波/倍压/整流网络。从流程架构上看负载层变成了RC网络而不是电机或LED。搞明白这事你设计电路时就会想PWM频率该选多高才能让RC滤波后的纹波足够小倍压电路的开关管是否工作在连续导通模式这些问题的答案依然要回到那五层链路模型里去找。7. 我踩过的几个坑及排查思路7.1 按“信号链”排错的几个实例很多来找我问PWM问题的人都卡在“某个输出怎么就是不对”上。我总结了几类典型场景基本上是排查流程的活教材专门拿出一个章节来分享。实例一STM32输出PWM示波器测量完全没波形。我第一步看GPIO时钟和AFIO时钟第二步看引脚模式复用推挽第三步看定时器时钟和PSC/ARR第四步看CCER使能位第五步看电平极性。很多人忽略CCER的使能位CC1E只配了CCMR里的OC1M和CCR那当然没输出。另外如果用了类似PA6但板子上这个引脚还接了别的负载电阻波形可能被拉平这时要用示波器看实测电压而不是只看寄存器。实例二28335配置了EPWM输出波形频率完全不对。我通常先检查时钟寄存器CLKSRCELSEL确认EPWM模块时钟是系统时钟的几分频然后看TBCTR寄存器里CLKDIV和HSPCLKDIV的配置。28335的时基时钟分频选项多一不小心频率算错完全是正常的。比如你想要20kHz但配置完实际得到10kHz多数情况是某个分频位多除了一个2。实例三用Keil5仿真查看PWM波形看不到或者波形异常。这里有个前提要明确Keil5的仿真Simulation模式下外设模型对PWM的支持有限。很多STM32模拟器不能完全模拟定时器PWM的物理输出。遇到这种情况我强烈建议直接用示波器或者逻辑分析仪看实际波形仿真器主要用来看寄存器值、观察中断触发时机。真要看波形STM32可以用DAC输出配合内部连接或者直接把PWM引脚引出来接逻辑分析仪几分钟就能看到真实输出。实例四单总线PWM通信波形对但设备不响应。这时问题可能出在时序上你的MCU发送PWM的占空比精度不够或者频率稳定性不够导致设备端解析失败。解决办法是尽量用硬件PWM如果用软件PWM就把中断优先级调到足够高并且不要在高频主循环里改动参数否则抖动太大。7.2 排查问题时的寄存器速查习惯养成一个习惯非常有帮助所有PWM相关寄存器配置完成后做一次“回读”。怎么写进去的读出来是不是一致。有些芯片存在“写入寄存器的值在特定条件下被硬件跳变覆盖”的情况读回来能帮你发现很多隐藏问题。STM32里我常用调试器查看CCR、ARR、CCER、BDTR的值28335里用CCS的寄存器窗口看TBPRD、CMPA、DBFED、DBRED的值RK3588里则使用devmem或debugfs查看PWM节点状态。还有一个建议写代码时不要让PWM配置逻辑散落在各种初始化函数里。最好做一个结构体把PWM周期、占空比、死区、极性、重映射引脚、故障保护选项统一抽象出来然后写一个platform_pwm_config函数填入结构体驱动硬件。这样当你需要把TIM3换成TIM4时只改结构体部分即可不用到处搬寄存器配置逻辑。这也是我后面几篇系列文章会深入展开的方向。7.3 关于“一个定时器能不能同时接收PWM数据和输出PWM波形”热搜词里有一条很有意思“一个定时器能不能同时接收pwm数据和输出pwm波形”。这是一个典型的误区我在这里明确回答一个物理定时器的输入捕获和输出比较功能在硬件上是可以同时用的但有一个大前提——它们共用同一个计数器。为什么这有讲究你想想输出PWM需要CNT在跑输入捕获也需要CNT在跑。两者确实可以同时工作一个通道配置为捕获模式另一个通道配置为输出比较模式这在STM32里是允许的。但问题在于捕获依赖CNT的连续运行而输出比较在特定时刻翻转如果你修改ARR或重新初始化定时器捕获过程也会被打断。并且输出PWM的频率与捕获的对象有本质区别输出PWM是MCU主动产生信号捕获是MCU被动测量外部信号你要留心两者是否真的应该共享同一个定时器。如果两个信号的频率范围差异大或者不能接受互相干扰那就该考虑用两个独立定时器。我曾经在一个项目里差点让TIM2既输出PWM又捕获另一个信号后来发现两个任务的更新中断频率差距太大放在同一个定时器里低优先级任务一直被高优先级任务抢占运行效果很差。最后拆成两个定时器问题立刻消失。所以我的经验是没必要省定时器资源不够就选更多通道的芯片或者用外部PWM发生器别硬挤在一起。7.4 死区与故障保护的组合逻辑一个入门实操环节把这部分单独拎出来因为它很容易被忽略。我推荐任何做电机驱动的朋友都花半天时间用STM32的高级定时器TIM1配合一个简单的RC充放电电路练习一下“互补PWM死区刹车”三件套的组合逻辑。你可以不用真的接MOSFET只要用示波器看波形就行。具体做法是TIM1输出CH1和CH1N两路互补PWM在DTG里插入1us死区然后用一个按键模拟刹车输入。按键按下PWM进入刹车状态输出被钳位为低电平松开按键PWM恢复正常。注意配置刹车时BDTR寄存器里MOE位主输出使能必须使能否则高级定时器的PWM通道是不会有输出的。很多人配置TIM1时发现启动后没波形一半以上是忘了置MOE为1。做完这个实验你对“流程架构”里“调理层”的作用会有非常直接的理解死区不是随便加的它是信号链里一个实实在在的处理环节故障封锁也不是软件断PWM那么简单它是硬件级的最终保险。理解这两个点再看CCU6、28335这些芯片的死区和故障区配置时你会觉得它们大同小异反而不容易绕晕。8. 还要想清楚的事捕获模式与PWM的关系8.1 捕获不是PWM的敌人但也不能混用PWM Capture在高端SoC里经常跟PWM输出放在同一个控制器里比如RK3588的PWM模块。捕获模式的核心逻辑很简单记录PWM信号中第一个上升沿的到来时刻再记录第二个上升沿的到来时刻两者差值就是周期记录上升沿和下降沿的差值就是高电平时间占空比 高电平时间 / 周期。但一个容易被忽略的细节是捕获模式下测量的信号频率范围不能太高也不能太低因为寄存器位宽有限。你用一个16位计数器去捕获一个1kHz的方波如果时钟分频没配好计数器可能在两个边沿之间溢出好几次你都不知道该如何重建时间。所以配置捕获时钟时我得先估算信号频率然后反推预分频系数确保计数器在一个周期内不会溢出也不至于精度差到测不出来。有一点要提前跟初学者说清楚多数MCU的定时器捕获捕获到的“时间戳”是计数器CNT的瞬时值而不是一个绝对时间。你要真正得到微秒级的频率值必须在中断里读CNT、计算两次捕获的差值再根据时钟频率换算。如果你在中断里处理不当比如中断响应时间太长导致错过了下一个边沿捕获数据就会错乱。这也就是为什么很多高端SoC把PWM Capture做成硬件自动计算省去软件在中断里重建时间戳的麻烦。8.2 捕获在舵机反馈和电机测速中的实际意义搜“舵机pwm控制”的人应该知道舵机一般只需要控制信号不需要反馈信号。但一些高端舵机或者带有位置反馈的云台电机会回传一个PWM信号给MCU这个信号就用来反馈实际位置。你如果只有一路定时器就得同时做到输出PWM角度控制信号同时捕获舵机反馈PWM。这时“一个定时器同时收发PWM”的问题就变得实际了。我的建议是果断拆成两个定时器一个只管输出一个只管捕获避免交互。而电机测速编码器的A/B相输出本质上也是PWM信号用定时器捕获模式去测它们的频率和相位关系就能计算出转速和方向。这里我给一个实用数值常见的编码器输出几千Hz到几十kHz用10kHz~100kHz的捕获时钟去测就够用。捕获时钟太低测不准太高会增加寄存器溢出概率需要再降低分频让CNT值在边沿间落在一个合适的区间我一般控制在500~3000之间精度和溢出风险都比较均衡。9. 从一篇理解到一整个体系PWM后续还能怎么延伸这部分我想说点“往后看”的内容。不是讲课就是分享一下我自己的延伸路径大家按需取用。PWM只是流程架构的基础后面很多技术都建立在它之上。比如高频PWM配合电感电容做开关电源本质是一个“PWM 滤波”的问题电机FOC控制里PWM的占空比决定了施加在电机绕组上的平均电压矢量数字电源里PWM的分辨率和抖动直接决定了输出电压的准确度。你掌握了PWM信号链路就等于掌握了很多电力电子和电机控制系统的底层语法。我个人的体会是PWM流程架构最重要的不是记住每一个寄存器的名字而是建立起一种条件反射拿到一个PWM应用先画出五层链路模型标出每一层的参数和可能的风险点。频率选型、占空比计算、死区插入、故障保护、引脚复用、驱动电路匹配这些都是这张链路图上各层之间的接口协议。只要链路通畅参数合理不管是STM32、DSP28335、CCU6还是RK3588对你而言都只是换了一套寄存器的写法而已。如果你自己跑了一遍呼吸灯、电机调速或者NE555搭PWM发生器可以从示波器波形上对比各层信号的变化感受一下“配置层改动→波形层变化”的联动效果。再往后我会在系列后续文章里分别展开“死区与故障保护的硬件细节”“PWM采样与低通滤波”“高频PWM与电源设计”这些方向。写这篇文章时我又检查了一遍自己常踩的那些坑MOE位使能、AFIO时钟、DBFED/DBRED的极性理解、PSC先加一再参与计算这些细节看上去小但每一个都能让人调一整天。最后再分享一个小技巧调试PWM时手边放一张芯片参考手册对应的定时器框图把寄存器按链路顺序标在图上比对着查问题比我用过的任何调试工具都管用。
返回列表