ARTICLE DETAIL

资讯详情

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

STM32上SVPWM与死区补偿实战:从CubeMX配置到电流波形优化

STM32上SVPWM与死区补偿实战:从CubeMX配置到电流波形优化 1. 从定时器配置到七段式波形SVPWM在STM32上的落地路径很多人第一次接触FOC卡住的地方往往不是Clarke变换或者Park变换的数学推导而是SVPWM那一堆扇区判断和矢量作用时间计算。公式看懂了代码写出来电机就是不转或者转起来噪音大、电流波形一塌糊涂。我在早期做无刷电机驱动的时候用STM32F103RCT6搭了一套板子光是SVPWM波形这一块就折腾了将近两周后来才慢慢摸清楚CubeMX里定时器的配置逻辑和死区补偿的实际效果之间的关系。这篇文章主要面向已经了解FOC基本框架、但在SVPWM波形生成和死区补偿环节遇到瓶颈的开发者。我会从CubeMX的定时器配置讲起把中心对齐PWM、七段式SVPWM的波形特征、死区时间的计算与补偿策略这几个关键环节串起来最后给出可以直接参考的代码结构。整个过程中涉及到的芯片以STM32F103RCT6为主但思路对F4、G4系列同样适用。先明确一个基本认知SVPWM的本质是在三相逆变桥上通过六个功率管的开关组合合成出一个幅值恒定、角度连续旋转的电压矢量。和SPWM相比SVPWM的直流母线电压利用率高出约15.47%这也是它在FOC中被广泛采用的核心原因。但高利用率带来的代价是开关序列更复杂死区效应更明显尤其是在低速轻载工况下死区导致的电压畸变会直接反映到电流波形上。注意如果你用的是STM32G4系列它内部有专门的HRTIM和电机控制定时器配置逻辑和F103的通用定时器有较大差异。本文以F103的TIM1高级定时器为主线G4用户可以参考思路但不要照搬寄存器配置。2. CubeMX里TIM1的配置细节与中心对齐模式的选择2.1 为什么必须用中心对齐模式在CubeMX中配置TIM1用于SVPWM输出时第一个要做的选择就是计数模式。边沿对齐模式下PWM的载波频率和开关频率一致电流纹波较大中心对齐模式下计数器先向上计数到ARR再向下计数到0实际输出的PWM频率是定时器时钟除以(2×ARR)。中心对齐的好处在于每个PWM周期内开关管会经历两次开关动作但电流纹波频率翻倍等效提高了电流环的采样质量。具体配置上假设系统时钟72MHz我希望PWM载波频率为10kHz那么ARR的计算方式是ARR 72MHz / (2 × 10kHz) 3600在CubeMX的TIM1配置界面中Counter Mode选择Center Aligned Mode 1Period填入3600Prescaler设为0。这里有个容易忽略的点Center Aligned Mode 1/2/3的区别在于中断触发条件不同。Mode 1只在向下计数时触发更新中断Mode 2只在向上计数时触发Mode 3两者都触发。对于FOC的电流采样通常选择Mode 1在计数器下溢时触发ADC注入转换这样采样点正好落在PWM周期的中间位置避开开关噪声。2.2 互补输出与死区时间的硬件配置TIM1的CH1/CH2/CH3配置为PWM Generation CHx CHxN也就是互补输出模式。CubeMX中需要设置Pulse占空比初值、Output Compare Preload使能、Fast Mode使能、CH Polarity高电平有效、CHN Polarity低电平有效、Idle State根据你的栅极驱动芯片决定。死区时间在CubeMX中有专门的Dead Time配置项单位是定时器时钟周期数。以72MHz时钟为例一个时钟周期约13.89ns。如果使用IR2103这类栅极驱动芯片其典型开通延迟约680ns关断延迟约150ns那么死区时间至少要覆盖两者的差值加上裕量。实际计算死区时间 ≥ (开通延迟 - 关断延迟) 裕量 ≥ (680ns - 150ns) 200ns ≥ 730ns换算成时钟周期数730ns / 13.89ns ≈ 53。CubeMX中Dead Time填入53即可。但要注意CubeMX的Dead Time寄存器配置有几种不同的编码方式具体值需要查参考手册中BDTR寄存器的DTG位定义。对于F103当DTG[7:5]100时死区时间 (64 DTG[4:0]) × Tdtg其中Tdtg Tck_int。所以填入53时实际死区时间 (6453) × 13.89ns ≈ 1625ns比预期大了一倍多。这个坑我在第一次配置时踩过电机低速时电流波形明显畸变后来用示波器抓互补输出波形才发现死区时间远超预期。提示配置完死区后务必用示波器测量上下管的驱动波形确认死区时间符合预期。不要只信CubeMX的数值硬件实测才是最终依据。2.3 触发ADC注入转换的时机设置FOC电流采样的准确性直接决定控制效果。在中心对齐模式下计数器下溢时触发ADC注入转换是最常见的做法。CubeMX中在TIM1的Trigger Output配置里Trigger Event选择Update Event这样每次下溢都会产生触发信号。然后在ADC配置中External Trigger Conversion Source选择Timer 1 Trigger Out event注入通道选择对应的电流采样引脚。这里有个细节ADC采样需要一定的保持时间如果采样窗口太短采样值会不准。STM32F103的ADC在72MHz下采样时间可设为1.5、7.5、13.5、28.5、41.5、55.5、71.5、239.5个ADC时钟周期。对于电机电流采样建议至少选择13.5个周期配合ADC时钟分频到14MHz左右总转换时间约1μs完全能在PWM周期内完成。3. 七段式SVPWM的扇区判断与作用时间计算3.1 从电压矢量到扇区编号的映射逻辑SVPWM的核心思想是用相邻两个基本电压矢量和一个零矢量在一个PWM周期内合成目标电压矢量。三相逆变桥有六个有效开关状态对应六个60度扇区。给定α-β平面上的目标电压矢量(Vα, Vβ)首先需要判断它落在哪个扇区。常见的判断方法是计算三个中间变量float U1 Vbeta; float U2 (sqrt(3)*Valpha - Vbeta) / 2; float U3 (-sqrt(3)*Valpha - Vbeta) / 2; int A (U1 0) ? 1 : 0; int B (U2 0) ? 1 : 0; int C (U3 0) ? 1 : 0; int sector A 2*B 4*C;得到的sector值对应1到6分别对应六个扇区。这个方法的优点是计算量小只需要几次乘法和比较适合在中断中实时执行。但要注意当Vα和Vβ都很小低速时或者为零堵转时扇区判断会变得不稳定这时候需要做特殊处理比如保持上一次的扇区值或者强制进入零矢量状态。3.2 基本矢量作用时间的计算与过调制处理确定扇区后需要计算两个相邻基本矢量的作用时间T1和T2。以扇区1为例0°到60°基本矢量V4(100)和V6(110)的作用时间分别为T1 (sqrt(3) * Ts / Vdc) * (Vbeta * cos(30°) - Valpha * sin(30°)) T2 (sqrt(3) * Ts / Vdc) * (Valpha * cos(30°) Vbeta * sin(30°))其中Ts是PWM周期Vdc是直流母线电压。其他扇区的计算可以通过旋转坐标或者查表方式实现。实际代码中通常会先把Vα和Vβ归一化到Vdc/sqrt(3)的基准下这样T1和T2就变成无量纲的比例值再乘以Ts即可。这里有一个关键问题当目标电压矢量幅值超过内切圆半径时T1T2会大于Ts这就是过调制。如果不做处理直接按比例缩放会导致波形严重失真。常见的处理方式是if (T1 T2 Ts) { float scale Ts / (T1 T2); T1 * scale; T2 * scale; }这种等比缩放虽然简单但在深度过调制时会导致电压利用率下降。更精细的做法是采用最小相位误差过调制或者六边形限幅不过对于大多数工业应用等比缩放已经足够。3.3 七段式对称波形的生成与比较值计算七段式SVPWM的开关序列在一个PWM周期内是对称的以扇区1为例开关顺序为零矢量(000) → V4(100) → V6(110) → 零矢量(111) → V6(110) → V4(100) → 零矢量(000)。每个矢量的作用时间关于周期中心对称这样做的目的是让谐波集中在开关频率附近便于滤波。在代码实现上通常计算三个比较值Ta、Tb、Tc然后写入TIM1的CCR1、CCR2、CCR3寄存器。以扇区1为例float T0 (Ts - T1 - T2) / 2; float Ta T0 / 2; float Tb Ta T1 / 2; float Tc Tb T2 / 2; // 根据扇区映射到三相 switch(sector) { case 1: CCR1 Tb; // A相 CCR2 Ta; // B相 CCR3 Tc; // C相 break; // ... 其他扇区 }注意这里的CCR值是相对于ARR的因为中心对齐模式下计数器从0到ARR再回到0所以CCR值直接对应占空比。写入CCR时要注意TIM1的预装载寄存器是否使能如果使能了新值会在下一个更新事件生效这样可以避免PWM周期内出现毛刺。提示在中断中计算CCR值时尽量使用整数运算或者定点数浮点运算在F103上没有FPU会消耗大量CPU时间。如果必须用浮点建议把计算频率降低到PWM频率的1/2或1/4。4. 死区补偿的工程实现与电流波形改善4.1 死区效应的本质与电流畸变特征死区时间是为了防止上下管直通而设置的但它的副作用是输出电压偏离理想值。具体来说在死区期间上下管都关断输出电压由续流二极管决定取决于电流方向。如果电流从逆变桥流向电机死区期间输出电压被钳位到负母线如果电流反向则钳位到正母线。这就导致实际输出电压和理想PWM占空比之间存在一个误差电压其幅值与死区时间成正比方向与电流方向相反。这个误差电压在电流过零点附近会造成明显的波形畸变表现为电流波形出现“平顶”或者“台阶”在低速时尤为明显。我实测过在10kHz载波、1.6μs死区、24V母线电压下死区导致的电压误差约为ΔV (Tdead / Ts) × Vdc (1.6μs / 100μs) × 24V ≈ 0.384V这个误差电压看起来不大但在低速轻载时电机反电动势可能只有几伏0.384V的误差足以造成电流波形明显失真甚至引起转矩脉动和噪音。4.2 基于电流极性的死区补偿策略死区补偿的基本思路是根据电流方向在理想占空比上叠加一个补偿量。如果电流为正说明实际输出电压偏低需要增加占空比如果电流为负则减小占空比。补偿量的计算公式为float Tcomp Tdead / Ts; // 补偿比例 if (Ia 0) { Ta_comp Ta Tcomp; } else { Ta_comp Ta - Tcomp; }但这里有个问题电流在过零点附近会频繁穿越如果直接根据瞬时电流极性做补偿会在过零点附近产生抖动。常见的改进方法是设置一个电流阈值只有当电流绝对值超过阈值时才进行补偿阈值以内不做补偿或者做线性过渡。阈值的选择需要根据采样精度和电机参数确定一般取额定电流的5%到10%。另一种更精细的方法是采用平均电流极性判断即在一个PWM周期内对电流多次采样根据平均值决定补偿方向。这种方法可以避免开关噪声导致的误判但需要额外的ADC采样和计算资源。4.3 补偿效果的实测验证与参数整定死区补偿的效果需要通过实测验证。我通常的做法是让电机在低速下空载运行用示波器抓取相电流波形观察过零点附近的畸变情况。补偿前电流波形在过零点会有明显的“平台”补偿后波形应该变得平滑接近正弦波。参数整定方面补偿量Tcomp不是越大越好。如果补偿过量会在过零点附近产生过冲反而加剧波形畸变。我的经验是先从理论计算值的70%开始逐步增加直到电流波形最平滑。同时要注意补偿量应该随母线电压变化而调整因为误差电压和母线电压成正比。如果母线电压波动较大建议在补偿公式中引入实时母线电压采样值。注意死区补偿对电流采样精度要求较高。如果电流采样本身有较大噪声或偏移补偿效果会大打折扣。建议先校准电流采样电路确保零电流时采样值稳定在理论中点附近。5. 代码结构与中断优先级安排的实战建议5.1 FOC主中断的执行流程与时间预算在STM32F103上跑FOC主中断通常放在TIM1的更新中断中频率和PWM频率一致10kHz。中断服务函数需要完成的任务包括电流采样、Clarke变换、Park变换、电流PI调节、反Park变换、SVPWM计算、死区补偿、CCR写入。整个流程的时间预算非常紧张10kHz意味着每个周期只有100μs扣除ADC转换时间和中断进出开销实际可用于计算的时间可能只有60μs左右。我的做法是把整个FOC计算拆分成几个部分按优先级排列。电流采样和Clarke变换必须在中断中完成因为需要和PWM同步Park变换和PI调节可以放在中断中但要注意优化SVPWM和死区补偿的计算量较大如果时间不够可以考虑把SVPWM的扇区判断和作用时间计算放在中断中而把CCR映射和写入放在主循环中通过双缓冲机制避免冲突。5.2 中断优先级的分配与ADC触发时序STM32F103的中断优先级分为抢占优先级和响应优先级NVIC中配置。FOC系统中TIM1更新中断的抢占优先级应该设为最高ADC注入转换完成中断次之串口、CAN等通信中断设为最低。这样可以确保电流环的实时性不受通信任务影响。ADC注入转换由TIM1的更新事件触发转换完成后产生JEOC中断。在JEOC中断中读取电流采样值然后置位一个标志主中断中检测到这个标志后再进行后续计算。这种做法的好处是电流采样和FOC计算解耦避免在中断中等待ADC转换完成。但要注意JEOC中断的响应时间会影响电流采样的时效性。如果JEOC中断被其他高优先级中断打断采样值可能对应的是上一个PWM周期的电流导致相位滞后。实测中如果JEOC中断延迟超过2μs电流环的相位裕度会明显下降。所以JEOC中断的优先级要足够高同时中断服务函数要尽量短只做数据读取和标志置位。5.3 代码模块划分与可移植性设计为了让代码在不同芯片之间移植我习惯把FOC算法和硬件相关的部分分开。算法部分包括Clarke、Park、反Park、SVPWM、PI调节器这些用纯C写成不依赖任何硬件寄存器硬件相关部分包括定时器配置、ADC配置、GPIO配置这些放在单独的板级支持包中。具体文件划分如下文件名内容依赖foc_math.c/hClarke、Park、反Park、SVPWM无foc_ctrl.c/h电流环PI、速度环PIfoc_mathbsp_tim.c/hTIM1配置、CCR写入HAL库bsp_adc.c/hADC配置、电流采样HAL库main.c初始化、中断服务函数全部这样的划分方式在从F103换到F407时只需要修改bsp层算法层几乎不用动。我在实际项目中用这种方式做过三次芯片迁移每次移植时间不超过半天。6. 调试过程中最容易踩的几个坑6.1 扇区判断在低速时的抖动问题前面提到过低速时电压矢量幅值很小扇区判断容易出错。我遇到过一次典型情况电机在50rpm以下运行时电流波形出现周期性抖动频率和电角度相关。用调试器抓取sector变量发现它在两个相邻扇区之间反复跳变。原因是低速时Vα和Vβ的数值很小受采样噪声影响符号判断不稳定。解决办法有两个一是设置一个最小电压幅值阈值低于阈值时保持上一次的扇区值二是采用滞环判断即扇区切换需要满足一定的幅值条件避免在边界附近频繁切换。我最终采用的是第一种方法阈值设为额定电压的2%效果很好。6.2 死区补偿方向判断错误的排查死区补偿方向判断错误是另一个常见问题。如果电流采样存在偏移零电流时采样值不在理论中点那么电流极性的判断就会出错补偿方向相反反而加剧波形畸变。排查方法是在电机不转的情况下读取三相电流采样值确认它们都在理论中点附近偏差不超过满量程的1%。如果偏差较大需要校准采样电路或者在软件中做偏移补偿。我遇到过一块板子B相电流采样偏移了约3%导致低速时B相电流波形明显异常。后来在代码中加了偏移校准问题解决。校准方法很简单上电时电机不转采样100次取平均作为零电流偏移值后续采样值减去这个偏移。6.3 PWM输出毛刺与CCR写入时机在中断中直接写CCR寄存器如果时机不对可能会在PWM周期内产生毛刺。STM32的TIM1有预装载功能CCR写入后不会立即生效而是在下一个更新事件时生效。但如果预装载没使能写入就会立即生效可能导致当前周期内占空比突变产生毛刺。CubeMX中默认使能了预装载但如果你手动修改了寄存器配置要确认TIM1_CCMR1的OC1PE位是否为1。另外在中心对齐模式下更新事件发生在计数器下溢时所以CCR写入后要等到下一个下溢才会生效。如果你在中断中计算完CCR后立即写入而中断是在下溢时触发的那么新值会在下一个周期生效正好是一个周期的延迟。这个延迟在电流环中是可以接受的但如果你的中断触发时机不对可能会导致延迟不稳定。提示建议在调试时用示波器同时抓取PWM输出和中断触发信号确认CCR更新时机和PWM周期的对应关系。如果发现毛刺优先检查预装载配置和中断触发点。7. 从实测波形反推参数整定的经验7.1 电流环PI参数与SVPWM周期的匹配电流环PI参数整定和PWM周期密切相关。理论上电流环带宽一般取开关频率的1/10到1/5对于10kHz载波带宽约1kHz到2kHz。PI参数的计算公式为Kp L × ωc Ki R × ωc其中L和R是电机定子电感和电阻ωc是目标带宽对应的角频率。但实际整定时我发现理论值往往偏大因为SVPWM的死区效应和采样延迟会引入额外的相位滞后。我的经验是先把理论值乘以0.6到0.8然后根据电流波形逐步调整。调整时观察电流波形的超调量和响应时间。如果超调过大减小Kp如果响应太慢增大Ki。注意Kp和Ki不是独立的增大Kp通常需要相应减小Ki否则容易振荡。7.2 死区补偿量对电流THD的影响我用示波器的FFT功能测量过不同死区补偿量下的电流THD。在1.6μs死区、10kHz载波、24V母线、空载低速条件下补偿前电流THD约8%补偿量取理论值的70%时THD降到4%左右补偿量取理论值的100%时THD反而回升到5.5%。这说明补偿过量确实会引入额外谐波。进一步分析发现补偿过量导致的谐波主要集中在开关频率及其边带附近而过零点畸变导致的谐波主要集中在低频段。所以整定补偿量时要同时观察低频段和高频段的谐波变化找到总THD最低的点。7.3 不同载波频率下的死区补偿策略调整载波频率变化时死区补偿策略也需要调整。载波频率越高死区占PWM周期的比例越大补偿量也越大。但高频载波下开关损耗增加死区时间可能需要适当减小以降低损耗。这是一个权衡过程。我在从10kHz切换到20kHz时发现同样的死区时间下电流波形反而变差了。原因是20kHz时PWM周期只有50μs1.6μs死区占比从1.6%上升到3.2%补偿量需要相应增加。但增加补偿量后过零点附近的抖动也更明显。最后我把死区时间减小到1μs补偿量按新比例调整波形才恢复正常。这个经验说明死区补偿不是一劳永逸的载波频率、母线电压、电机参数变化时都需要重新整定。建议在代码中把死区补偿量做成可配置参数方便不同工况下快速调整。8. 写在最后的一点个人体会FOC的SVPWM和死区补偿理论推导看起来复杂但真正落地到STM32上核心就是几件事定时器配置对不对、扇区判断稳不稳、作用时间算得准不准、死区补偿方向对不对。我见过很多开发者卡在某个环节反复检查公式却忽略了硬件配置的细节比如死区时间实际值和预期不符、ADC采样时机偏移、CCR预装载没使能等等。调试这类问题示波器比调试器更有用。抓互补输出波形看死区抓相电流波形看过零点畸变抓中断触发信号看时序很多问题一眼就能看出来。代码层面建议把关键变量sector、T1、T2、CCR值通过DAC或者串口实时输出配合示波器观察比单步调试效率高得多。最后分享一个小技巧在验证SVPWM波形时可以先不接电机用三相星型电阻负载代替这样电流波形更干净便于观察SVPWM本身的输出特性。等波形没问题了再接电机调电流环和速度环。这个顺序可以帮你把问题隔离在算法层面避免电机参数和机械特性干扰判断。
返回列表