资讯详情

资讯详情

六路互补PWM死区配置与波形验证:STM32高级定时器调试指南

做电机驱动、逆变器、UPS这类功率变换项目六路互补PWM这关是绕不过去的。不管你是刚接触FOC的小白还是已经在调BLDC的老手这路波形如果处理不好轻则电机抖动噪音大重则上下桥臂直通炸管子。我这篇文章就围绕“验证六路互补PWM”这个实验把完整的原理、配置、实测方法和踩坑实录都梳理出来手把手带你过一遍这套调试流程。这篇文章适合正在做三相逆变器、无刷直流电机BLDC或永磁同步电机PMSM驱动方案的工程师也适合学校实验室里刚接触STM32高级定时器的学生。通过这篇内容你会搞明白互补PWM为什么需要死区、六路信号之间的相位关系怎么验证、STM32的寄存器该怎么配以及示波器上哪些现象是正常的、哪些是危险的。1. 六路互补PWM的整体设计思路1.1 从H桥到三相全桥的进化先说清楚六路互补PWM是从哪来的。单相H桥有四个开关管一对桥臂输出一个交流电三相逆变器是把三个H桥拼在一起共用母线这就是三相全桥拓扑。三个桥臂各有一对上下管总共六个开关管。上管打开时下管必须关断下管打开时上管必须关断这就是“互补”关系的来源。而所谓“六路”PWM就是三个桥臂的上管和下管各一路控制信号总计六路。在整个PWM周期里任意时刻某个桥臂只能有一只管子导通否则就构成母线短路。真正的电机控制场景下这三对互补PWM可不是简单复制成三份。三相定子绕组需要相位差120°的正弦波电流对应到PWM上就是三对互补波形的占空比按正弦规律变化并且三对波形之间相差120°电角度。验证这个相位关系是实验的关键环节。1.2 为什么一定要加死区时间理想情况下上下管互补切换是瞬间完成的。实际功率器件不是理想开关MOS管有关断延迟时间td_off栅极驱动器也有传输延迟差异。如果上管还没完全关断下管就已经开始导通这时候母线正负极就通过两管直连了。实测中哪怕只有几百纳秒的重叠导通母线电容储存的能量也能瞬间烧毁MOS管。死区时间的本质就是在互补信号切换之间插入一段“双方都关断”的空白期让上管可靠关断后再让下管导通。这一点必须实测确认不能只看逻辑。示波器上看互补波形切换沿处有一段水平空档那就是死区。关于死区时间的计算和设定后面会专门展开讲。1.3 实验验证的目标拆解这个实验要验证的东西我总结成四个检查点互补关系每个桥臂的上下管波形在任意时刻电平相反死区期间除外。死区时间切换沿处的高电平空缺宽度与寄存器设定值一致。频率与占空比六路输出频率相同占空比跟随配置值变化。相位关系三对波形依次延迟120°这是三相控制的核心。这四个点通过示波器逐项确认后才算真正验证通过。2. 实验环境搭建与工具选型2.1 主控芯片选型的关注点并不是任意一个单片机都能输出带死区的互补PWM。普通定时器PWM输出引脚只有一个要产生互补输出必须选用带“高级定时器”的芯片典型代表是STM32的TIM1和TIM8。高级定时器内置了死区发生器、互补输出通道和刹车保护功能。这意味着死区时间、互补极性、故障关断这些逻辑全在硬件里完成不需要CPU实时干预。如果你用的MCU没有高级定时器只能软件做死区那又别论了但做工业级产品我不会用这种方案。我实验时用的板子是STM32F103C8T6最小系统板几块钱一片TIM1就是高级定时器完全够用。如果你手头有GD32、MM32这类国产替系列芯片同样有高级定时器操作逻辑大同小异。2.2 功率级与栅极驱动电路的组合方案主控输出的3.3V PWM信号根本没能力直驱大功率MOS管。标准方案是主控接栅极驱动芯片再驱动MOS管或IGBT。栅极驱动我常用IR2101S或EG2131这类半桥驱动芯片一路驱动芯片正好驱动一个桥臂的上下管。这种芯片内部的死区逻辑配合外部电阻还可以再加一道硬件死区保障。三相全桥需要三颗这样的驱动芯片。母线电压我这套实验平台用的24VMOS管选的额定电压100V的N-MOS余量留了四倍实验安全性高很多。2.3 示波器是这实验的关键工具验证PWM波形绕不开示波器。关于示波器的选择我想多说两句因为这块的经验太多人踩坑了。至少要有两个通道最好四通道。两通道意味着你一次只能看一个桥臂的上下管波形然后轮换着看另外两相四通道可以一次性把三对波形的相位关系全抓到效率一下子就上来了。带宽至少要50MHz实测20kHz PWM是绰绰有余的。但是如果你想细看死区几十纳秒的沿细节带宽越高失真越小。我用的四通道100MHz数字示波器测死区精度足够。有个容易忽略的点是探头补偿。示波器探头上有补偿电容调节孔先把探头接到示波器自带的1kHz方波校准端调成标准方波再测。不然你测出来的死区时间误差会很大甚至波形边缘出现假振铃。3. 核心参数计算与寄存器配置3.1 理解定时器时钟树的来龙去脉参数计算之前先搞明白PWM的底层来源。STM32F103的TIM1挂在APB2总线上来自主时钟的72MHz。这个时钟先经过预分频器PSC再经过计数器计数ARR最终决定PWM频率。PWM输出频率的计算公式是这样的F_PWM 主频 / ((PSC 1) × (ARR 1))主频72MHz时如果我想要20kHz的PWM频率可以取PSC0那么(ARR1)72000000/200003600即ARR3599。为什么选20kHz这里有一个理论支撑20kHz已超出人耳可听范围20Hz~20kHz。电机开关频率低于这个值运行时会发出刺耳的电磁噪音。20kHz意味着每个PWM周期是50μs死区几μs只占周期百分之几效率损失非常小。如果在实验初期调低到10kHz会明显听到电机有“咝咝”的啸叫那其实是PWM频率落在可听范围内不是电机故障。3.2 死区时间的计算与寄存器写入死区时间设置的依据是功率器件的开关特性。芯片数据手册上会给出典型开通延迟td_on和关断延迟td_off两者之差就是直通风险窗口。栅极驱动电阻也会影响这个时间。保守的做法是死区时间取器件开关延迟之和的3~5倍。比如我用的MOS管关断延迟约120ns开通延迟约80ns那么理想死区至少200ns安全起见取1μs。留足裕量之后1μs的代价是PWM周期50μs里占2%的效率损失换来的是炸管风险大幅降低。STM32 TIM1死区时间寄存器是TIMx_BDTR其中DTG位域的控制逻辑并不直接写入纳秒数而是分段映射。我的实验以72MHz主频为例逆推了一下死区值实际效果很理想Tdts对应的是定时器时钟周期72MHz下约为13.89ns。DTG位域高三位是000属于模式0直接死区时间就是DTG值乘以Tdts。需要1μs死区就要写入DTG7272×13.89ns≈1μs。我习惯在初始化代码里把死区值写明确并加注释防止换一批芯片后主频变了死区时间在不知情的情况下跟着变。3.3 寄存器级别初始化代码解析下面是我在实验里实际用过的TIM1初始化代码我贴的是简化版屏蔽了中断处理部分只保留核心配置逻辑。void TIM1_PWM_Init(uint16_t arr, uint16_t psc, uint16_t dtg) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; TIM_BDTRInitTypeDef TIM_BDTRInitStructure; TIM_TimeBaseStructure.TIM_Prescaler psc; TIM_TimeBaseStructure.TIM_CounterMode TIM_CounterMode_Up; TIM_TimeBaseStructure.TIM_Period arr; TIM_TimeBaseStructure.TIM_ClockDivision TIM_CKD_DIV1; TIM_TimeBaseInit(TIM1, TIM_TimeBaseStructure); /* 三对互补通道的模式都设置为PWM1比较值与手动配置 */ TIM_OCInitStructure.TIM_OCMode TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable; TIM_OCInitStructure.TIM_OutputNState TIM_OutputNState_Enable; TIM_OCInitStructure.TIM_Pulse 0; TIM_OCInitStructure.TIM_OCPolarity TIM_OCPolarity_High; TIM_OCInitStructure.TIM_OCNPolarity TIM_OCNPolarity_High; TIM_OCInitStructure.TIM_OCIdleState TIM_OCIdleState_Set; TIM_OCInitStructure.TIM_OCNIdleState TIM_OCNIdleState_Reset; TIM_OC1Init(TIM1, TIM_OCInitStructure); TIM_OC2Init(TIM1, TIM_OCInitStructure); TIM_OC3Init(TIM1, TIM_OCInitStructure); /* 六路主输出使能必须写否则高级定时器不输出 */ TIM_CtrlPWMOutputs(TIM1, ENABLE); /* 死区时间写入BDTR寄存器 */ TIM_BDTRInitStructure.TIM_OSSRState TIM_OSSRState_Enable; TIM_BDTRInitStructure.TIM_OSSIState TIM_OSSIState_Disable; TIM_BDTRInitStructure.TIM_LOCKLevel TIM_LOCKLevel_OFF; TIM_BDTRInitStructure.TIM_DeadTime 72; TIM_BDTRInitStructure.TIM_Break TIM_Break_Disable; TIM_BDTRInitStructure.TIM_BreakPolarity TIM_BreakPolarity_High; TIM_BDTRInitStructure.TIM_AutomaticOutput TIM_AutomaticOutput_Enable; TIM_BDTRInit(TIM1, TIM_BDTRInitStructure); TIM_ARRPreloadConfig(TIM1, ENABLE); TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable); TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable); TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable); }注意TIM_CtrlPWMOutputs这一行高级定时器区别于普通定时器的一个坑就在这里。即使前面都配好了不调用这个函数主输出就是不出来波形一直是低电平。补一句比较值怎么设置。上面代码里TIM_Pulse先置为0实际运行中通过TIM_SetCompare1(TIM1, 300)这类函数动态更新占空比。比如ARR3599时比较值300表示占空比约8.3%比较值3300表示占空比约91.7%。3.4 利用STM32CubeMX快速生成工程有些朋友喜欢用STM32CubeMX图形化配置我实验初期也用它快速搭过框架。在CubeMX里选择TIM1把Channel1、Channel2、Channel3的模式都设为PWM Generation CHx and CHxN互补输出然后在Break and Dead Time settings里设置死区时间。注意CubeMX里死区时间单位是ns界面框会让你直接输入数字底层自动帮你换算成BDTR值。输入1000代表1μs生成代码后再核对一下寄存器值确认换算逻辑没问题。我个人最终倾向于寄存器方式因为经验上调试中修改比较值以及分析波形时寄存器方式逻辑更透明出了诡异问题能少绕弯子。CubeMX适合快速起步寄存器适合深度排错两者不矛盾。4. 实操过程与六路波形验证4.1 硬件接线与上电检查我的实验用板是STM32F103C8T6选用的管脚对应TIM1通道实验具体接线如下信号MCU引脚去往备注TIM1_CH1PA8IR2101S的高边输入HIN桥臂A上管TIM1_CH1NPB13IR2101S的低边输入LIN桥臂A下管TIM1_CH2PA9IR2101S的高边输入HIN桥臂B上管TIM1_CH2NPB14IR2101S的低边输入LIN桥臂B下管TIM1_CH3PA10IR2101S的高边输入HIN桥臂C上管TIM1_CH3NPB15IR2101S的低边输入LIN桥臂C下管母线电源-桥臂MOS管直流母线24V示波器夹子-GND接地要就近接上电顺序有讲究。先给MCU烧录程序确认主控板工作正常再接通24V母线。第一次上电时我习惯把母线电源限流调小比如限流1A即使有错误也不至于炸管这个习惯帮我避免了两次事故。栅极驱动芯片的地必须和MCU共地很多初学者漏了这一步导致高低边逻辑乱跳波形完全不可控。4.2 示波器上验证互补关系示波器通道1接TIM1_CH1引脚通道2接TIM1_CH1N引脚。触发源选在通道1触发方式设置为下降沿时基先放到50μs/格。正常情况下你会看到上下两个波形接近镜像但不是完全对称。高电平宽度之差正好是死区时间。通道1从高变低后通道2还要保持一段低电平才变高通道2从高变低后通道1也要保持一段低电平。这个双双低电平的区间就是死区。给一个我更推荐的观察方式示波器打开“数学运算”功能用通道1加通道2的“与”逻辑或用“下降沿延时”测量功能直接读出死区时间数值。如果算出来的死区在0.9μs到1.1μs之间和设定的1μs一致这组波形就验证通过了。4.3 三对波形的相位差验证三相电机的核心是相位差120°。验证PWM的时候不能只看单独一个桥臂还得看三对波形之间的相位关系。示波器四通道分别接CH1、CH2、CH3同时观察三个上管波形。设置时基50μs/格你会看到三个波形形状相同但互相错开。PWM周期是50μs120°相位差对应的时间偏移是50μs除以3约16.67μs。也就是说通道1的上升沿出现后通道2的对应上升沿要晚约16.67μs通道3再晚16.67μs。如果这里测出来时间偏移不对说明比较值更新时机有误通常是对齐/边沿对齐模式选择出了问题。做FOC算法的大忌是六路PWM虽然都有输出但相位关系全是乱的。4.4 上管和下管不能简单看同一路信号有些学习板为了简化接线直接把互补输出的N通道悬空用上管信号逻辑取反来控制下管。这种做法虽然能让电机转起来但丢失了硬件死区的意义。我建议实验验证时一定要把CH1和CH1N都接上不光是看波形还要接功率级的输入实测。有些问题只在带载情况下显现空载时示波器看着教科书级完美一带电机就出毛刺。5. 调试过程实录与常见问题排查5.1 上电立即炸管典型的主输出未关断问题我调试初期最惨烈的一次经历是上电以后开始配置寄存器程序还没运行到主输出使能那段MOS管就冒烟了。原因很简单STM32刚上电时IO引脚默认是浮空输入状态对于栅极驱动芯片来说输入悬空就等于随机电平。IR2101S的LIN输入一旦悬空被拉高下管直接导通再叠加母线电源一开若上管也被意外拉导通瞬间就直通了。解决方式有两个必须同时做第一在栅极驱动输入前对地加下拉电阻10kΩ保证MCU还没初始化的时间段里栅极驱动低电平输入第二程序一启动先把刹车信号拉起来或者在主函数最开始就配置TIM1的MOE主输出使能为0全部初始化完成后再置1。炸管的问题是整个实验中最危险最花钱的问题这一条务必重视。5.2 只有三路输出被忽略的N通道使能位有次实验六路波形只出来三路CH1、CH2、CH3都有CH1N、CH2N、CH3N全是低电平。查来查去最终发现是结构体里TIM_OutputNState一直没配置默认输出状态被关掉了。对比代码就一目了然TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable; TIM_OCInitStructure.TIM_OutputNState TIM_OutputNState_Enable; // 这一行漏了就只输出三路TIM_OCInitStructure是库函数方式的老黄历写法但原理是通用的。如果你用寄存器方式初始化检查CCER寄存器里CC1NE位有没有置1低电平和这个位是强关联的。5.3 死区时间偏大的影响有段时间我把死区设成5μs电机低速转动时明显能听到“嗒嗒”的异响但波形看着没问题。效率测量对比后发现输出功率比预期低了约10%。这就是死区时间过大的副作用。死区越大每个周期里两个管子都关断的时间越长实际输出电压相对理想值的损失就越大。这个现象在低电压大电流的电机驱动上尤其明显。要做死区补偿的话原理上是在软件算法里对电压矢量做修正根据电流方向前移或者后退PWM前沿。这个属于比较进阶的内容实验初期没必要上先把死区值控制在合理范围内更重要。5.4 波形毛刺和振铃不是芯片问题示波器上看到波形上升沿有振铃很多初学者误以为是芯片时序有问题。我排查下来大部分情况来自两个物理因素探头接地线太长或者开关管快速切换时回路寄生电感与电容产生谐振。第一个因素最容易验证。把示波器探头换成弹簧地线接地端紧贴测试点附近如果振铃明显变小就是探头带来的假象。第二个因素需要改善PCB布局让母线电容尽可能靠近MOS桥臂。实验中用的面包板由于寄生电感大毛刺严重是正常的放宽心态。5.5 互补PWM常见问题速查表把调试中容易碰到的问题和排查方向整理成一个表格方便你对照定位。故障现象优先怀疑方向检查手段上电即短路或炸管IO上电默认电平、未使能MOE栅极驱动输入对地下拉主循环最先关主输出只有三路低电平输出N通道使能未配置检查CCER的CCxNE位或结构体OutputNState互补波形没有死区BDTR死区寄存器值为0读取TIMx_BDTR寄存器确认DTG非零波形振铃大探头地线过长、PCB寄生电感大换弹簧接地探针优化功率回路布局某一路占空比异常比较值更新时机问题检查是否在需要使用影子寄存器时开了预装载死区值与设定不一致主频估计错误、分频配置有误用示波器频率功能实测PWM频率反推主频6. 从实验台到产品级的几个改进方向实验波形验证通过说明你的PWM配置基础已经扎实了但距离能上产线的固件还有几个坎要过。第一增加刹车保护功能。高级定时器上的刹车输入BKIN并不是摆设。产品上得过流保护、过压保护、电机驱动故障信号直接接到刹车输入脚。一旦故障信号触发芯片硬件直接将PWM输出全部置为安全状态响应时间在硬件级纳秒级别而软件中断响应最快也要几微秒。这个时间差就能区分是管子保住了还是冒烟了。第二开启定时器中断做逐周期电流保护。母线电流通过采样电阻采集后送入比较器比较器输出接BKIN。也可以直接用ADC采样在定时器更新中断里做限流判断超出阈值就关闭PWM输出。第三考虑自适应死区时间。如果项目对效率极致追求可以根据母线电压和负载电流动态调整死区时间。小型电机上差异不明显大功率驱动上死区损耗不容忽视。实验做到这一步离实际的驱动器产品就比较接近了。剩下FOC、SVPWM那些算法层面的东西是基于这套可靠的PWM底层逐个叠加的。我个人在实际操作中的体会是六路互补PWM验证虽然步骤琐碎但一次扎实的验证能让你后续调FOC算法时少走好多弯路。PWM底层如果没有踩踏实算法跑得再花哨最终都会在各种奇怪的现象里翻车。建议你将实验记录数据保存成模板以后换主控平台直接照这个流程做验证省下的时间非常可观。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →