ARTICLE DETAIL

资讯详情

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

STM32 PWM模式1与模式2深度解析:从原理到电机驱动应用

STM32 PWM模式1与模式2深度解析:从原理到电机驱动应用 1. 从一个反直觉的现象说起为什么我的PWM波形反了很多人在第一次用STM32的定时器输出PWM时都遇到过这样一个场景代码照着例程抄的引脚配置没问题时钟也开了示波器一接波形确实出来了但占空比和预期完全对不上——明明设的是30%出来的却是70%。更诡异的是把比较值调大高电平反而变窄了。这时候大多数人第一反应是是不是寄存器配错了然后开始翻参考手册翻到CCMR1寄存器的OC1M位看到两个选项PWM模式1和PWM模式2文档上写着模式1向上计数时CNT CCR时通道为有效电平模式2向上计数时CNT CCR时通道为无效电平。看完之后更懵了——什么叫有效电平有效电平是高还是低这个问题的答案其实藏在CCER寄存器里的CC1P位输出极性里。PWM模式1和模式2的区别本质上不是谁高谁低的区别而是谁在计数器小于比较值时输出有效电平的区别。而有效电平到底是高电平还是低电平是由极性位单独决定的。这两个概念一组合就产生了四种不同的输出行为。很多人把模式1和模式2理解成一个输出高一个输出低这是最常见的误解也是导致波形反了的根本原因。这篇文章就是要把这件事彻底讲清楚。我会从定时器计数器的底层行为出发把PWM模式1和模式2的波形生成逻辑拆开然后结合电机驱动、LED调光、逆变器方案、DAC滤波等实际场景说明什么时候该用模式1、什么时候该用模式2、极性位又该怎么配。如果你正在做STM32相关的项目不管是F103还是F4系列只要用到TIM定时器的PWM输出这里面的细节都绕不开。2. 计数器、比较值和有效电平三个概念先理清楚2.1 定时器PWM输出的硬件链路STM32的通用定时器比如TIM2、TIM3、TIM4和高级定时器TIM1、TIM8都能输出PWM。整个信号产生的链路是这样的时钟源经过预分频器PSC分频后驱动计数器CNT计数器按照设定的模式向上、向下、中心对齐循环计数同时比较寄存器CCR里存着一个值硬件每个计数周期都会拿CNT和CCR做比较比较的结果经过输出模式逻辑和极性控制最终送到GPIO引脚上。这条链路里PSC决定PWM的频率ARR自动重装载寄存器决定计数器的周期也就是PWM的周期CCR决定占空比而OCxM位输出比较模式和CCxP位极性共同决定波形的形状。很多人只关注PSC和ARR忽略了OCxM和CCxP的组合效应结果就是频率对了、占空比不对或者占空比对了、极性反了。2.2 什么叫有效电平参考手册里反复出现的有效电平active level这个词是理解PWM模式的关键。所谓有效电平不是指高电平也不是指低电平而是指这个通道被判定为导通或激活状态时输出的电平。它具体是高还是低由CCER寄存器里的CCxP位决定CCxP 0时有效电平为高电平CCxP 1时有效电平为低电平。你可以把有效电平理解成一个逻辑真值对应的物理表现。PWM模式1和模式2决定的是什么时候输出这个真值极性位决定的是这个真值在物理上表现为高还是低。两者是正交的互不干扰。这就是为什么单独看模式1和模式2的文档描述会觉得绕——因为它描述的是逻辑行为不是物理波形。2.3 向上计数时模式1和模式2的波形对比为了把这件事说透我们以最常见的向上计数模式为例设ARR 100CCR 30CCxP 0有效电平为高。PWM模式1的行为是CNT CCR时输出有效电平CNT ≥ CCR时输出无效电平。所以CNT从0数到29的这段时间输出高电平从30数到100的这段时间输出低电平。最终波形的高电平时间是30个计数周期占空比30%。PWM模式2的行为正好相反CNT CCR时输出无效电平CNT ≥ CCR时输出有效电平。所以CNT从0到29输出低电平从30到100输出高电平。高电平时间是70个计数周期占空比70%。看到这里你就明白了在极性相同的情况下模式1和模式2输出的波形是互补的。模式1的占空比等于CCR/(ARR1)模式2的占空比等于1减去CCR/(ARR1)。如果你想要30%的占空比但用了模式2出来的就是70%这就是开头那个波形反了现象的真正原因。条件PWM模式1输出PWM模式2输出CNT CCR有效电平高无效电平低CNT ≥ CCR无效电平低有效电平高占空比CCxP0CCR/(ARR1)1 - CCR/(ARR1)占空比CCxP11 - CCR/(ARR1)CCR/(ARR1)这张表建议存下来配寄存器的时候对着看一眼能省掉大量调试时间。3. 极性位掺进来之后四种组合的完整波形图景3.1 极性位到底改了什么CCxP位的作用非常直接它把经过模式逻辑判断后得到的有效/无效状态映射到物理引脚上的高/低电平。CCxP 0时有效→高无效→低CCxP 1时有效→低无效→高。它不改变模式逻辑本身的判断时机只改变最终的物理表现。这意味着模式1加极性0、模式1加极性1、模式2加极性0、模式2加极性1这四种组合会产生四种不同的波形。很多人调PWM调不出来就是因为只改了模式没改极性或者只改了极性没改模式两个变量一起动的时候没有系统地分析。3.2 四种组合的占空比对照继续用ARR 100、CCR 30的例子把四种组合的占空比列出来模式1 极性0CNT 30时输出高占空比30%模式1 极性1CNT 30时输出低占空比70%模式2 极性0CNT 30时输出低占空比70%模式2 极性1CNT 30时输出高占空比30%你会发现模式1加极性0和模式2加极性1得到的波形完全一样模式1加极性1和模式2加极性0得到的波形也完全一样。也就是说从最终波形来看改模式和改极性在效果上是等价的都能实现翻转波形。那为什么还要分两个位3.3 为什么不能只用一个位搞定原因在于互补输出和死区控制。高级定时器TIM1、TIM8支持互补输出一个通道可以同时输出CH1和CH1N两路互补的PWM用于驱动H桥的上管和下管。在这种场景下模式位和极性位是分别作用于主通道和互补通道的你不能简单地用翻转来理解。另外在中心对齐模式下模式1和模式2的行为和边沿对齐模式又不一样极性位的作用时机也会变化。还有一个实际原因在电机控制里有时候需要在不改变占空比计算逻辑的前提下快速切换输出极性来适应不同的驱动电路比如高边驱动和低边驱动的有效电平相反。这时候单独操作极性位比改模式位更清晰代码可读性更好。提示如果你只是做普通的单路PWM输出模式1加极性0是最常用的组合占空比直接等于CCR/(ARR1)计算最直观。遇到波形反了的情况优先检查是不是模式或极性配错了而不是去怀疑时钟或引脚。4. 中心对齐模式下模式1和模式2的差异4.1 中心对齐的计数行为边沿对齐模式下计数器只往上数一个周期内CNT和CCR只比较一次实际上是比较两次一次在上升段一次在下降段但边沿对齐只有上升段。中心对齐模式下计数器先往上数到ARR再往下数到0一个PWM周期内CNT会两次经过CCR的值所以输出的PWM波形是对称的谐波特性比边沿对齐好很多。中心对齐模式在电机驱动和逆变器方案里用得非常多因为它能产生对称的PWM减少电机的转矩脉动和电磁噪声。但中心对齐模式下模式1和模式2的行为需要重新理解。4.2 中心对齐时模式1的输出逻辑在中心对齐模式下PWM模式1的行为是向上计数时CNT CCR输出有效电平向下计数时CNT CCR输出有效电平。也就是说在计数器靠近0的那段区域向上时小于CCR、向下时也小于CCR输出有效电平在靠近ARR的那段区域输出无效电平。最终波形是一个以ARR/2为中心的对称脉冲脉冲宽度由CCR决定。模式2则相反向上计数时CNT CCR输出无效电平向下计数时CNT CCR输出无效电平脉冲出现在计数器靠近ARR的区域。4.3 中心对齐下模式选择对电机控制的影响做电机FOC控制的时候PWM通常配置成中心对齐模式这样ADC采样可以安排在计数器过零或过ARR的时刻避开开关噪声。这时候模式1和模式2的选择会影响PWM脉冲相对于计数器零点的位置。如果你的电流采样是在计数器过零时触发的那用模式1能让有效电平也就是驱动MOS管导通的那段覆盖采样时刻附近采样窗口更干净。用模式2的话有效电平跑到ARR附近去了采样时刻正好落在无效电平区域可能采不到真实的电流。这个细节在一般的教程里很少提但实际做电机项目的时候如果搞反了电流环会一直震荡调半天调不好。我的经验是中心对齐加模式1加合适的极性是电机控制里最稳妥的默认配置除非你的驱动电路有特殊要求。5. 实际应用场景里怎么选从LED调光到逆变器5.1 LED调光模式1直接对应亮度LED调光是最简单的PWM应用场景。假设你用TIM3的CH1驱动一个LEDLED阳极接VCC阴极接引脚低电平点亮那有效电平就是低电平应该配CCxP 1。这时候如果你用模式1CCR越大CNT CCR的时间越长有效电平低的时间越长LED越亮。占空比和亮度直接正相关代码里写CCR 亮度值就行非常直观。如果你用的是共阳极接法引脚输出高电平点亮那CCxP 0模式1下CCR越大越亮同样直观。所以LED调光场景下模式1加正确的极性能让CCR值和亮度建立最直接的正相关关系代码最好写。5.2 电机驱动模式选择要和驱动芯片匹配驱动直流电机或者步进电机的时候PWM信号通常送到驱动芯片的使能脚或者方向脚。不同的驱动芯片对有效电平的定义不一样。比如有些H桥驱动芯片PWM输入高电平有效那你就得保证在需要电机转的时候输出高电平。这时候用模式1加极性0CCR设大一点就能输出更宽的高电平电机转速更快。但有些驱动芯片是低电平有效的比如某些低边驱动PWM输入低电平的时候MOS管导通。这时候你有两个选择要么用模式1加极性1要么用模式2加极性0。两种都能得到CCR越大导通时间越长的效果。我一般倾向于用模式1加极性1因为模式逻辑不变只改极性代码里占空比的计算公式不用动移植的时候不容易出错。5.3 逆变器方案互补输出和死区才是重点做单相或三相逆变器的时候PWM输出的要求就高多了。你需要互补的两路PWM驱动H桥的上下管而且两路之间必须插入死区时间防止上下管直通烧毁。这种场景下模式1和模式2的选择要结合互补通道和死区发生器一起考虑。STM32的高级定时器里CH1和CH1N是一对互补输出。你可以把CH1配成模式1CH1N自动就是互补的波形。死区时间由BDTR寄存器里的DTG位控制硬件自动在上下管切换时插入死区。这时候模式1和模式2的区别在于模式1下CH1的有效电平出现在CNT CCR的区间模式2下有效电平出现在CNT ≥ CCR的区间。对于H桥来说你希望上下管的导通时间以计数器零点或ARR点为中心对称分布这样死区插入后波形仍然对称。所以逆变器方案里通常用中心对齐加模式1配合适当的死区时间能得到最干净的互补PWM。5.4 DAC滤波和音频输出模式2有时候更方便还有一个不太常见但很有意思的场景用PWM加RC滤波做简易DAC。这时候你希望PWM的高电平时间正比于DAC输出电压。如果用模式1加极性0CCR越大高电平越长滤波后的电压越高很直观。但如果你用的RC滤波电路是反相的比如经过一级运放反相那输出电压和占空比是反的这时候用模式2加极性0反而能让最终输出电压和CCR正相关省掉代码里的取反操作。这种根据后级电路选模式的思路在实际项目里很实用。不要死记模式1就是对的而是看整个信号链选让代码最简洁、计算最直观的那个组合。6. 配置过程中容易踩的几个坑6.1 忘了使能输出比较预装载配PWM的时候CCR寄存器有个预装载功能由CCMR1里的OC1PE位控制。如果OC1PE 0你写CCR的值会立即生效在计数器运行过程中改CCR可能导致输出一个异常宽的脉冲或者窄脉冲。如果OC1PE 1CCR的值会在下一个更新事件UEV时才生效波形切换更平滑。做LED调光或者电机调速的时候如果需要在运行中动态改占空比一定要把OC1PE置1并且使能ARPE自动重装载预装载。否则你会看到波形偶尔抖一下严重的时候会触发过流保护。这个坑我在做电机项目的时候踩过调了半天以为是电流环参数问题最后发现是CCR没开预装载。6.2 模式改了但没重新使能通道STM32的定时器通道输出使能位是CCER里的CC1E。如果你在运行中改了OC1M模式位或者CC1P极性位有些系列的单片机会要求你先关闭通道输出CC1E 0改完再重新使能否则新配置可能不生效。F1系列一般可以直接改但F4和G4系列在某些情况下需要先禁用再启用。保险的做法是改模式和极性之前先把CC1E清零改完再置1。6.3 中心对齐模式下ARR必须大于CCR中心对齐模式下计数器从0数到ARR再数回0。如果你的CCR大于ARR那CNT永远小于CCR模式1下输出一直是有效电平PWM就变成了直流。这个错误在调占空比的时候很容易犯尤其是用公式动态计算CCR的时候忘了做上限保护。建议在代码里加一句if (ccr arr) ccr arr;能省掉很多莫名其妙的调试时间。6.4 高级定时器的MOE位TIM1和TIM8有个BDTR寄存器里的MOE位主输出使能这个位不置1的话所有通道都不会输出PWM哪怕你把CC1E、CC1P、OC1M都配对了也没用。很多从通用定时器转到高级定时器的人会漏掉这一步然后纳闷为什么引脚上一点波形都没有。记住高级定时器输出PWMMOE必须置1。注意MOE位在刹车事件触发后会被硬件自动清零如果你的系统里有刹车输入比如过流保护信号接到BKIN引脚触发刹车后需要软件重新置位MOE才能恢复输出。这个机制在电机驱动里是保护功能但如果你不知道会以为是芯片坏了。7. 用代码把模式1和模式2的差异跑出来7.1 最小验证代码下面这段代码基于STM32F103的标准外设库用TIM3的CH1输出PWM你可以通过改两个宏来切换模式1和模式2用示波器或者逻辑分析仪观察波形变化。#include stm32f10x.h #define PWM_MODE 1 // 1: PWM模式1, 2: PWM模式2 #define PWM_POLARITY 0 // 0: 高电平有效, 1: 低电平有效 void TIM3_PWM_Init(u16 arr, u16 psc, u16 ccr) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE); // PA6作为TIM3_CH1输出 GPIO_InitStructure.GPIO_Pin GPIO_Pin_6; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); TIM_TimeBaseStructure.TIM_Period arr; TIM_TimeBaseStructure.TIM_Prescaler psc; TIM_TimeBaseStructure.TIM_ClockDivision TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3, TIM_TimeBaseStructure); TIM_OCInitStructure.TIM_OCMode (PWM_MODE 1) ? TIM_OCMode_PWM1 : TIM_OCMode_PWM2; TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse ccr; TIM_OCInitStructure.TIM_OCPolarity (PWM_POLARITY 0) ? TIM_OCPolarity_High : TIM_OCPolarity_Low; TIM_OC1Init(TIM3, TIM_OCInitStructure); TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); TIM_ARRPreloadConfig(TIM3, ENABLE); TIM_Cmd(TIM3, ENABLE); } int main(void) { // 72MHz / 72 1MHz计数频率, ARR999 - 1kHz PWM // CCR300 - 模式1极性0时占空比30% TIM3_PWM_Init(999, 71, 300); while(1); }这段代码里PWM_MODE和PWM_POLARITY两个宏可以自由组合你可以在示波器上看到四种不同的波形。建议实际跑一遍把四种组合的波形都截个图以后配PWM的时候对着图选比翻手册快得多。7.2 动态切换模式的注意事项如果你需要在运行中切换模式比如从模式1切到模式2来实现波形的快速翻转代码大概是这样void PWM_SwitchMode(TIM_TypeDef* TIMx, uint8_t mode) { // 先关闭通道输出 TIMx-CCER ~TIM_CCER_CC1E; if (mode 1) { TIMx-CCMR1 ~TIM_CCMR1_OC1M; TIMx-CCMR1 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2; // PWM模式1 } else { TIMx-CCMR1 ~TIM_CCMR1_OC1M; TIMx-CCMR1 | TIM_CCMR1_OC1M_2; // PWM模式2 } // 重新使能通道输出 TIMx-CCER | TIM_CCER_CC1E; }注意这里先关了CC1E再改OC1M改完再开CC1E。虽然F1系列直接改OC1M也能生效但加上这个保护步骤不会有坏处而且移植到其他系列的时候不用改。7.3 用示波器验证时的观察要点验证的时候重点看三个东西一是高电平时间和CCR的关系模式1极性0下高电平时间应该等于CCR个计数周期二是波形翻转是否干净切换模式的时候不应该出现毛刺三是占空比的分辨率ARR越大分辨率越高但PWM频率会降低需要根据实际需求权衡。我一般习惯把ARR设成1000或者1000的整数倍这样CCR的值直接对应千分比的占空比代码里写CCR 300就是30%不用做除法调试的时候心算也快。8. 几个和PWM模式相关的常见疑问8.1 模式1和模式2能同时用在一个定时器的不同通道吗可以。TIM的四个通道各自有独立的OCxM位你完全可以让CH1跑模式1、CH2跑模式2、CH3跑模式1、CH4跑模式2。这种配置在多路输出需要不同相位关系的场景下很有用比如驱动两个电机一个需要正转PWM一个需要反转PWM就可以用不同的模式来实现。8.2 改了模式之后占空比公式要不要改要改。模式1极性0下占空比 CCR/(ARR1)模式2极性0下占空比 1 - CCR/(ARR1)。如果你在代码里封装了一个设置占空比的函数切换模式的时候记得把计算公式也切过来否则设30%出来70%。我的做法是在设置函数里根据当前模式自动选择公式对外只暴露占空比百分比这一个参数内部处理模式差异。8.3 为什么有些例程用模式1有些用模式2这取决于例程作者的硬件电路和习惯。如果例程配套的LED是低电平点亮的作者可能用模式2加极性0效果和模式1加极性1一样。你移植例程的时候不能只抄代码要看清楚它的硬件连接和极性配置否则波形就是反的。8.4 中心对齐下模式1和模式2的占空比公式一样吗不一样。中心对齐模式下模式1的占空比是CCR/ARR注意不是ARR1因为中心对齐的周期是2*ARR个计数模式2的占空比是1 - CCR/ARR。具体数值建议用示波器实测确认因为不同系列的ARR定义有细微差别。9. 我在实际项目里总结的几条经验做STM32的PWM输出模式1和模式2本身不复杂复杂的是它和极性位、计数模式、预装载、互补输出这些功能的交互。我做了这么多年项目总结下来几条最实用的经验第一新建工程配PWM的时候先用模式1加极性0跑通确认波形正常之后再根据硬件需要调整。不要一上来就纠结用哪个模式先把基础链路打通。第二把模式、极性、计数模式、占空比公式这四个东西做成一张对照表贴在工位上配寄存器的时候对着看。我见过太多人因为记混了模式2的占空比公式调了半天以为定时器坏了。第三动态改占空比一定要开预装载。OCxPE和ARPE都置1能避免99%的波形抖动问题。这个习惯从F1到F4到G4都适用。第四高级定时器别忘了MOE。TIM1和TIM8的MOE位不置1配得再对也没输出。这个坑每年都有新人踩。第五中心对齐加模式1是电机控制的黄金组合。除非你的驱动电路有特殊要求否则这个配置能覆盖绝大多数电机驱动场景电流采样窗口也最干净。最后说一个调试技巧如果你不确定当前配置输出的是什么波形不要靠猜拿示波器或者逻辑分析仪接上看。PWM这种东西看一眼波形比读十遍手册都快。我习惯在调试阶段把ARR设小一点比如100这样PWM频率高示波器上波形稳定容易观察占空比的变化。等逻辑调通了再把ARR改回实际需要的值。
返回列表