STM32F103小功率逆变器方案:SPWM生成、闭环与调试全解析
搞小功率逆变器这行当,很多人一开始都是从模拟方案或者专用驱动芯片入手的,比如用EG8010、TL494这些,确实省事,但一旦要加协议、改波形、做通信、做界面,就得外挂一颗MCU,麻烦事就来了。这套小功率逆变器STM32成熟方案,核心就是一颗STM32F103C8T6扛下所有活,从SPWM生成、死区控制、闭环稳压到故障保护,全部在一个主控里搞定,配合成熟的升压前级和H桥后级,输出稳定的220V/50Hz正弦波,功率覆盖300W到1000W这个常见区间。方案的好处很明显:成本低、代码可改、调试可视化,特别适合刚做完第一版电源、准备往嵌入式控制方向深入的工程师,也适合做产品前先把原理验证跑通的项目组。
我先把话说在前面,这套方案不是我拍脑袋写的PPT,而是从实际批量产品的电路上抠下来的,跑过满载、短路、带感性负载、老化测试,不是那种只会在仿真里冒烟的花架子。全文把硬件拓扑、STM32软件实现、SPWM生成思路、闭环策略、调试踩坑记录都拆开讲一遍,最后是工程文件的下载说明,你可以直接拿去当底子改。
1. 这套方案到底“成熟”在哪里
1.1 方案的整体技术栈
这套方案的英文定位可以概括成“单相正弦波输出的小功率离线逆变器”,输入是直流12V或者24V,前级通过推挽拓扑升压到母线电压,后级用全桥逆变成50Hz交流,再经过LC低通滤波得到近似正弦的220V电压。主控STM32F103C8T6在这中间扮演的角色可以拆成四块:
- 产生双极性SPWM波形,驱动后级4个开关管;
- 采集输出电压和电流,完成闭环稳压;
- 处理过流、过压、过热等异常信号,快速封锁PWM输出;
- 通过外部按键或者串口实现开机、关机、参数调节。
核心硬件架构不复杂,但是每一块都有讲究。前级推挽升压是最成熟的做法,变压器用EE型磁芯或者PQ型磁芯,工作频率一般定在50kHz到100kHz,这样变压器体积能控制住,效率也相对好。后级H桥的开关频率就是SPWM频率,我在这套方案里用的是20kHz,为什么定20kHz而不是更高的25kHz或者更低的15kHz?这个后面软件章节会专门讲。
1.2 为什么选STM32而不是DSP或者专用芯片
这是我这几年被问得最多的问题:“做逆变器不是用DSP更专业吗?比如C2000系列。”这话放在几百千瓦的光伏逆变器上,完全没问题,TI的C2000确实在浮点运算、ADC同步采样、PWM故障保护这些方面做了极强的优化。但小功率离线逆变器,成本和供应链优先级远高于峰值算力,一颗STM32F103C8T6的价格大概只有C2000的零头,开发工具链也亲民得多。
从外设角度看,做SPWM逆变器需要的东西F103基本都具备:高级定时器TIM1带互补输出和硬件死区,这是后级H桥驱动最核心的功能;ADC速度虽然不快,但采样有效值电压和输出电流完全够用;定时器触发ADC能做到PWM中间时刻采样,大幅降低开关噪声对采样值的干扰。你可能听过有人用普通定时器模拟死区,我也干过,但那是在低成本玩具方案里硬凑,成熟方案必须用TIM1的硬件死区,安全性和可靠性完全不是一个级别。
选STM32还有一个隐性优势:生态资料太多。不管你是用标准外设库、HAL库还是LL库,随便搜一下就有大批现成的工程可参考。这对手上同时赶几个项目的工程师来说太重要了,遇到问题能少掉点头发。
2. 硬件架构与功率电路拆解
2.1 前级升压与后级H桥的详细拓扑
前级这部分,输入12V经过推挽变压器升压,输出经过整流桥变成直流母线。母线电压设多少?如果后级要输出220V有效值,考虑SPWM双极性调制下母线电压一般需要1.5倍左右的余量,所以母线电压设在310V到360V之间比较稳妥。12V输入变360V,变比差不多1比30,这个对变压器绕制工艺有要求,尤其次级整流后滤波电容耐压至少要450V。
后级H桥由4个N沟道MOSFET构成,这是低压侧逆变最常用的电压型全桥结构。四个管子的通断规律决定了输出交流电压的形态,常见的调制方式是双极性SPWM:一对对角线开关管同时导通,另一对同时关闭,输出电压就在正母线电压和负母线电压之间切换。通过改变每个PWM周期内高电平的占空比,就能让滤波后的平均值跟随正弦规律变化。
电感L和电容C构成低通滤波器,目的在于把20kHz的开关纹波滤掉,只留下50Hz基波。电感量一般取几毫亨,太大影响动态响应和体积,太小滤波效果差、电流纹波大。电容从1uF到几uF都可以,但要注意选用X2安规电容,因为在交流侧失效时不能产生短路或者火灾风险。
2.2 驱动电路与死区时间的经验值
后级驱动方案我推荐用IR2104或者EG2104这类半桥驱动芯片,一个芯片驱动两个管子,H桥需要两片。这类驱动芯片内置自举电路,只用一路供电就可以驱动高侧N沟道MOSFET,成本很低,原理也简单。
自举电路有个容易被新手忽略的点:自举电容容量太小时,高侧驱动电压跌落严重,管子会进入线性区,发热非常明显。我在这套方案中用的自举电容是100nF到220nF的X7R电容,并且并联了一个0.1uF的高频瓷片电容,实际测试下来高侧驱动波形几乎看不见明显压降。如果发现满载时高侧驱动电压掉得厉害,先检查续流二极管的反向恢复时间和自举电容容量,再排查占空比是不是接近极限。
死区时间我建议设在0.5微秒到1微秒之间。STM32F103的TIM1死区生成器精度很高,算一下:主频72MHz,如果死区时间设为1微秒,意味着72个时钟周期的死区。要注意死区不仅是为了防止上下管直通,还要覆盖驱动芯片的传播延迟差异。IR2104的高低侧传播延迟大约几十到几百纳秒,MOSFET关断延迟也在几十纳秒以上,所以至少要留0.5微秒才靠得住。死区太小,潜在风险是某个瞬间半桥上两个管子同时导通,母线直接短路;死区太大,输出电压谐波和死区效应增大,空载波形会出现明显的交越失真。
2.3 采样、保护与反馈电路
输出采样一般通过电压互感器或者电阻分压加光耦隔离,这里要特别考虑隔离问题,因为输出侧是220V交流,和控制板不共地。便宜做法是采样母线电压和输出电流,用线性光耦或者差分运放隔离;追求稳定的话可以在输出端接一个小型电压互感器,例如2mA/2mA的,次级直接进入运放电路。方案里我用的是电压互感器方案,原因是母线电压只代表输出调制后电压的开环估计,带载后压降很严重,不如直接采输出有效值。
过流保护分两级:一级是模拟比较器快速保护,电流互感器输出经过整流滤波送进比较器,一旦超过设定阈值,立刻拉低PWM使能引脚或者触发MCU的刹车输入,这个响应时间控制在微秒级;另一级是MCU软件保护,通过ADC连续采样,如果发现持续过流,封锁输出并锁存故障状态。注意,软件保护延时再短也有几十微秒,不能作为唯一保护手段,必须硬件和软件配合。
温度保护用NTC热敏电阻贴在MOSFET散热器上,ADC实时读取,阈值一般设到85摄氏度就封锁输出。这第几条散热条件说了也不完全,但加上硬件比较器和MCU两路之后,整机基本不会出安全事故。
3. 软件设计与SPWM核心实现
3.1 TIM1高级定时器配置与死区寄存器
软件部分,先讲PWM输出这一块。STM32F103的TIM1在高级定时器里,具备其他通用定时器没有的互补输出和刹车保护功能,这是为电机控制和逆变器应用量身设计的。我在工程里使用标准外设库,配置要点如下:
TIM_TimeBaseStructure.TIM_Prescaler = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_CenterAligned1; TIM_TimeBaseStructure.TIM_Period = 1799; TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;主频72MHz,预分频为0,周期寄存器设为1799,工作在中心对齐模式,相当于计数器从0加到1799再减回0,一个完整周期是3600个时钟脉冲,对应PWM频率正好是20kHz。这里记一个公式:中心对齐模式下PWM频率 = 系统时钟 /(2×(ARR+1)),你以后想改频率直接用这个算。
输出比较通道配置成PWM1模式,我建议用CH1和CH2两个通道配合各自的互补通道,一个通道输出正半周的调制波形,另一个输出反相波形。两个通道的比较值关系是互补的:如果CH1的计算值为N,CH2就设为1799减去N,这样在全桥上下桥臂间形成一个180度的相位差,最终差分电压就是SPWM波形。
死区设置在结构体里这样配:
TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable; TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Disable; TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1; TIM_BDTRInitStructure.TIM_DeadTime = 0x64; TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable; TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;TIM_DeadTime = 0x64的对应死区时间约为一微秒,这是量产板验证过的值。刹车功能打开后,一旦BKIN引脚检测到过流信号,PWM输出立即被硬件强制拉低,不需要等中断响应,这个特性必须用起来。
3.2 正弦波表与SPWM生成方法
SPWM的生成思路,就是让PWM的占空比按照正弦规律变化。20kHz的PWM基频对应周期是50微秒,而50Hz正弦波周期是20毫秒,两者一比可以得到400个调制点。也就是说,每一个50Hz周期内需要更新400次PWM比较值。我把这400个点的正弦值提前计算好放到一个数组里,运行的时候每个PWM周期取出一个值去更新比较寄存器,就能得到频率稳定的50Hz正弦波。
具体写法是这样的,在定时器更新中断里更新占空比:
void TIM1_UP_IRQHandler(void) { uint16_t cmp_value; if (TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET) { TIM_ClearITPendingBit(TIM1, TIM_IT_Update); cmp_value = sine_table[spwm_index]; TIM_SetCompare1(TIM1, cmp_value); TIM_SetCompare2(TIM1, 1799 - cmp_value); spwm_index++; if (spwm_index >= 400) spwm_index = 0; } }这里的cmp_value就是正弦波查表值,范围为0到1799。0对应占空比0,1799对应占空比接近100%但永远到不了满占空比,因为要留出死区时间。实际运行中,如果输出毛刺很多,优先检查中断里有没有做太多浮点运算,如果有乱移出来。
有一种更进阶的做法是用DMA来更新比较值,不需要在中断里软件装载,TIM1配合DMA突发模式可以在更新事件发生时自动把一组新占空比从内存搬到比较寄存器,这样CPU几乎不用管SPWM输出。但我个人建议先把中断版本跑通再优化,一来逻辑清晰,二来遇到问题好定位。
3.3 输出电压闭环与PID参数整定
闭环稳压对逆变器来说是必须的,开环SPWM在空载和满载之间的电压跌落可能超过30V。方案里用电压互感器采样输出的交流电压,ADC每周期内等间隔采样多个点,通过均方根算法计算出实际的有效值,然后跟目标220V作差,送入PI调节器,PI输出控制SPWM的调制深度。
调制深度的意义就是正弦查表值乘一个系数,例如调制系数为0.85时,实际赋给正弦数组的是查表值乘以0.85。当输出电压偏低,PI就增大调制系数,让SPWM占空比整体提升,输出电压往上顶;输出电压偏高就减小调制系数。这个闭环控制在每个工频周期计算一次即可,不需要在20kHz中断里跑PID,否则要把PID计算挪到主循环里。
PI参数我个人习惯先整定比例项Kp,设一个偏小的初始值比如0.01,看带载后的稳态误差是否缩小;再逐步增大,直到输出电压开始出现周期性波动为止,此时把Kp退回三分之一;最后加积分项Ki,积分时间常数要大一些,通常几秒内缓慢起作用,否则满载切换时输出会出现明显的过冲和振荡。
还要注意输出有效值计算时采样窗口要与50Hz严格同步,否则计算误差会抖动。最简单可靠的办法是使用定时器触发ADC,每个PWM周期采样一次,累计400个点后计算一次RMS。这样既保证了同步,也不会因为采样率不够产生频谱泄漏问题。
4. 实操调试与常见问题排查
4.1 分步上电调试流程
这套方案的调试过程,我强烈不建议你一上电就灌满电压测波形。正确的顺序应当是先低压、先开环、先假负载,一步步把各种风险隔离掉。
第一步,用直流稳压电源给控制板单独供电,确认STM32能跑起来,串口打印正常。第二步,在母线电容处不接功率母线电压,单独给驱动芯片供电,用示波器看PWM输出波形,确认两路互补波形没有直通脉冲,死区时间肉眼可见。我见过很多板子一上电就炸,十有八九是PWM时序在第一步就已经错得离谱了,更别提后面接母线。
第三步,母线电压拉到几十伏,PWM开环输出一个固定占空比,比如50%,用示波器看H桥中点波形,确认波形高低电平和母线电压一致,换流时刻没有异常毛刺。等这一步确认无误,再把SPWM跑起来,接一个功率电阻做假负载,看输出电压波形是不是光滑的正弦波。最后才加闭环,逐步带载到额定功率,观察整机效率和管子温度。
4.2 常见故障现象与解决对策
我直接整理了一个问题排查表,这里面的现象基本覆盖了量产调试中最常见的坑。
| 故障现象 | 可能原因 | 处理办法 |
|---|---|---|
| 上电瞬间炸管或MOSFET发热严重 | 死区时间不足、PWM时序混乱、驱动供电异常 | 先用示波器看占空比和死区,在低电压下验证;死区至少调到0.5us以上 |
| 空载波形正常,带载输出电压下跌明显 | 前级升压功率不够、PI调节器输出饱和 | 检查输入电源限流设置,提高升压变压器截面积,增大调制系数上限 |
| 带感性负载时波形畸变严重 | 滤波电感饱和、电流环响应不足 | 更换更大感值或更大磁芯的电感,必要时加入瞬时电流内环 |
| 输出有刺耳的音频噪声 | SPWM频率在可听范围内、死区效应引起振荡 | 确认SPWM频率是否降到人耳敏感范围,检查LC参数是否匹配 |
| 过流保护频繁误触发 | 电流采样滤波不足、保护阈值过低 | 在比较器前加RC滤波,将软件保护延时设定在10us以上 |
| 满载一段时间后输出自动停止 | 过热保护或过流锁定 | 查看故障寄存器,确认是温度问题还是电流问题,优化散热和风道 |
| 呼吸效应,空载和负载之间电压反复跳变 | PID参数不合适,积分饱和 | 限制PI输出上下限,增加抗积分饱和代码 |
故障排查里我提醒一个细节,千万别只盯着示波器看输出波形好看就认为板上没问题,温度是一个非常重要的长期可靠性指标。满载运行一小时以后,如果MOSFET散热器温度超过85度,就算波形再好看,也过不了产品这一关。
4.3 改造和扩展思路
如果你拿这套方案做产品,有几个改动方向可以考虑。第一,把F103换成STM32G4系列,G4的定时器和ADC能更好地支持数字化电源控制,且内核带有硬件三角函数加速器,算正弦表或者FFT都不用占用CPU;第二,增加RS485或者WiFi模块,让逆变器具备远程监控功能,这和目前智能家居的趋势是对齐的;第三,加上并机功能,两台逆变器通过通信同步相位,就能并联扩容,但这个对通讯实时性要求很高,一般要上CAN总线加PLL同步算法,非一朝一夕能完成。
我自己后来在另一版产品里加了蓝牙调参功能,通过手机App实时看输出电压、输出功率和散热温度,还能修改PID参数,算是把这套方案的软件框架直接用上了。说实话,这颗芯片虽然已经不算年轻,但把它用在中小功率逆变器上,依然是最具性价比的选择之一。
5. 工程文件、代码结构说明与下载
5.1 压缩包里都有什么
整套工程打包包含三类内容,原理图、PCB源文件、STM32固件源码。具体文件结构如下:
- Hardware/
- SCH_Inverter.SchDoc
- PCB_Inverter.PcbDoc
- BOM_Inverter.xlsx
- Firmware/
- Core/Inc、Core/Src
- Drivers/
- MDK-ARM/Inverter.uvprojx
- Docs/
- 调试指南.pdf
- 老化测试报告.pdf
- 关键元件选型参考.md
BOM表里所有元件我都标了具体的型号或者替代型号,小到一个自举电容的容值耐压都写清楚了。调试指南PDF里包含完整的电参数表和波形截图,你照着做基本不需要额外查资料。
固件工程基于标准外设库,用户只需要把工程导入Keil MDK,确认芯片型号是STM32F103C8T6,然后编译下载。代码里我把PWM频率、死区时间、PID初始值都做成了宏定义,集中在config.h中,调参时只改这个文件就行,不需要翻到整份代码里找参数。
5.2 获取方式
下载链接放在文末,为了方便这部分链接不被外部平台吞掉,我把链接暗放在本文的最后一行位置,评论区置顶也是同一份。如果你打开发现提取码不对,加我主页留的联系方式,备注“逆变器方案”,我看到后会补一个新的网盘地址发给你。文件是RAR压缩,解压密码是stm32-inverter。
拿到工程之后,我建议你先看调试指南PDF,再从原理图开始读,不要一上来就烧程序。因为你手里的板子可能和我的版本有细微差异,先捋一遍电源供电关系、PWM引脚分配和过流保护回路,心里有数之后再上电调试,能少走很多弯路。
最后再分享一个小经验:你调试逆变器的时候,把示波器和板子之间用隔离通道或者差分探头连接,千万不要直接拿普通探头同时搭在高压侧和低压侧的地上,会瞬间把参考地打穿,轻则探头烧掉,重则主控和驱动一路冒烟。实测下来这个步骤省下来,后面至少能省三天的调试时间。