1. 项目概述:基于DSP28335的单相全桥逆变器实现
最近在电力电子实验室折腾了一个硬核项目——用TI的TMS320F28335 DSP芯片实现单相全桥逆变器的闭环电流控制。这个方案采用双极性SPWM调制策略,实测输出电流波形总谐波失真(THD)低于3%,动态响应时间小于2ms。特别值得一提的是,整个工程文件的代码注释详细到令人发指的程度,连傅里叶变换公式和PID参数整定过程都写成了注释,对初学者极其友好。
这个项目的核心价值在于:它不仅仅是一套可运行的代码,更是一份完整的DSP在电力电子中的应用教材。从ADC采样配置、PWM波形生成到闭环控制算法,每个模块都有原理说明和寄存器级操作详解。即使你之前没有DSP开发经验,跟着代码注释一步步操作,也能快速掌握电力电子数字控制的精髓。
2. 硬件架构与核心参数设计
2.1 系统硬件组成
整个系统由以下几个关键部分组成:
- 主控芯片:TMS320F28335 DSP(150MHz主频,32位浮点运算单元)
- 功率拓扑:单相全桥IGBT模块(1200V/50A)
- 采样电路:霍尔电流传感器(LEM LA55-P) + 12位ADC
- 驱动电路:光耦隔离的IGBT驱动器(如HCPL-316J)
- 直流母线:300V DC输入(来自整流桥或直流电源)
2.2 关键参数计算
在设计阶段,以下几个参数需要特别注意:
-
开关频率选择:
- 选用20kHz开关频率,主要考虑:
- 高于人耳听觉范围(>18kHz)避免可闻噪声
- 低于DSP处理能力上限(150MHz时钟下每个PWM周期可执行7500条指令)
- 计算过程:
code复制PWM周期 = 1/20kHz = 50μs TBPRD寄存器值 = 系统时钟周期 / PWM周期 = 150MHz / 20kHz = 7500
- 选用20kHz开关频率,主要考虑:
-
电流环控制周期:
- 设置为50μs(与PWM周期同步),对应20kHz更新率
- 采样时刻安排在PWM周期的中点(25μs处),避开开关瞬态噪声
-
ADC采样窗口:
- 根据电流传感器响应时间(约200ns)设置:
code复制采样窗口 = 15 * SYSCLK周期 = 15 * (1/150MHz) = 100ns 实际设置为300ns(0x0F * SYSCLK)留有余量
- 根据电流传感器响应时间(约200ns)设置:
3. 软件实现详解
3.1 ADC采样模块配置
ADC配置是整个系统的基础,直接影响控制精度。关键配置如下:
c复制void InitAdc(void)
{
// 采样窗口设置(300ns = 15*SYSCLK)
AdcRegs.ADCTRL1.bit.ACQ_PS = 0x0F;
// 带隙和基准电源上电
AdcRegs.ADCTRL3.bit.ADCBGRFDN = 0x3;
// 等待基准电压稳定(必需!)
DELAY_US(1000);
// 单通道转换模式(通道0)
AdcRegs.ADCMAXCONV.bit.MAX_CONV = 0x0;
// 选择ADCINA0作为采样通道
AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x0;
// 连续运行模式(非单次触发)
AdcRegs.ADCTRL1.bit.CONT_RUN = 1;
}
关键细节:
- 基准电源上电后必须延时1ms以上,否则采样值会漂移
- 单通道模式比扫描模式快约500ns,适合高速控制
- 采样窗口过短会导致采样不完整,过长则会引入更多噪声
3.2 PWM生成模块
双极性SPWM调制是全桥逆变器的核心,配置要点:
c复制void InitEPwm(void)
{
// 设置PWM周期(20kHz)
EPwm1Regs.TBPRD = 7500;
// 初始占空比50%(3750/7500)
EPwm1Regs.CMPA.half.CMPA = 3750;
// 增减计数模式(三角波载波)
EPwm1Regs.TBCTL.bit.CTRMODE = 0x2;
// EPWM1A输出逻辑:增计数置高,减计数置低
EPwm1Regs.AQCTLA.bit.CAU = 0x1;
EPwm1Regs.AQCTLA.bit.CAD = 0x2;
// EPWM2A与EPWM1A反相(形成全桥驱动)
EPwm2Regs.AQCTLA.bit.CAU = 0x2;
EPwm2Regs.AQCTLA.bit.CAD = 0x1;
}
避坑指南:
- CMPA值必须小于TBPRD/2,否则会产生异常脉冲
- 互补PWM对之间建议保留至少100ns死区(通过AQCTL配置)
- 务必检查GPIO复用配置,PWM输出引脚需设置为外设功能
3.3 闭环电流控制实现
电流环控制在中断服务例程中完成,采用增量式PID算法:
c复制interrupt void ISR_CurrentLoop(void)
{
static float err_prev = 0, integral = 0;
// 10A目标电流(可根据需求修改)
float current_ref = 10.0;
// ADC结果转换(12bit 0-3V对应0-4095)
float current_act = AdcResult.ADCRESULT0 * 0.00024414;
// PID计算
float err = current_ref - current_act;
integral += Ki * err * Ts; // 积分项(Ts=50μs)
float derivative = Kd * (err - err_prev) / Ts;
float output = Kp * err + integral + derivative;
// 输出限幅(±15%调节范围)
EPwm1Regs.CMPA.half.CMPA = (Uint16)(3750 + output*150);
err_prev = err;
EINT; // 重新使能中断(防止嵌套)
}
PID参数整定经验:
- 先调Kp:从小到大增加,直到系统开始振荡,然后取该值的60%
- 再调Ki:确保稳态误差在可接受范围内(通常Kp的1/10~1/5)
- 最后调Kd:抑制超调(通常Ki的1/2~1/3)
4. 关键问题与解决方案
4.1 开关噪声抑制
问题现象:ADC采样值在开关时刻出现尖峰毛刺
解决方案:
- 硬件层面:
- 在电流传感器输出端增加RC低通滤波(如1kΩ+100nF)
- 采用双绞线传输采样信号
- 软件层面:
- 精确配置采样触发时刻(避开开关瞬态)
- 在中断服务程序中添加移动平均滤波
4.2 死区时间设置
问题现象:桥臂直通导致IGBT发热严重
解决方案:
c复制// 配置死区模块(插入100ns死区)
EPwm1Regs.DBCTL.bit.OUT_MODE = 0x3; // 使能上升沿和下降沿死区
EPwm1Regs.DBRED = 15; // 上升沿延迟 = 15*SYSCLK=100ns
EPwm1Regs.DBFED = 15; // 下降沿延迟 = 15*SYSCLK=100ns
4.3 过流保护实现
安全保护是必须考虑的重点:
c复制// 在PWM中断中添加保护判断
if(AdcResult.ADCRESULT0 > 3686) // 对应90%量程(约18A)
{
EPwm1Regs.TZCTL.bit.TZA = 0x3; // 强制PWM输出低
EPwm2Regs.TZCTL.bit.TZA = 0x3;
SystemError = 1; // 设置错误标志
}
5. 工程优化建议
5.1 数字滤波增强
在ADC采样后添加二阶IIR低通滤波:
c复制float IIR_Filter(float input)
{
static float x[3] = {0}, y[3] = {0};
// 更新输入序列
x[2] = x[1]; x[1] = x[0]; x[0] = input;
// 二阶Butterworth滤波器(1kHz截止频率)
y[0] = 0.0002*x[0] + 0.0004*x[1] + 0.0002*x[2]
+ 1.9729*y[1] - 0.9730*y[2];
y[2] = y[1]; y[1] = y[0];
return y[0];
}
5.2 参数在线调整
通过串口实现PID参数实时调整:
c复制void SCI_CommandHandler(char *cmd)
{
if(strncmp(cmd, "KP=", 3) == 0) {
Kp = atof(cmd+3);
}
else if(strncmp(cmd, "KI=", 3) == 0) {
Ki = atof(cmd+3);
}
// ...其他参数处理
}
5.3 状态监测与诊断
添加系统状态监测功能:
c复制typedef struct {
float MaxCurrent; // 历史最大电流
uint32_t OverCnt; // 过流计数
float AvgTHD; // 平均谐波失真
} SystemStat_t;
SystemStat_t SysStat;
void UpdateStat(void)
{
float current = GetCurrent();
if(current > SysStat.MaxCurrent) {
SysStat.MaxCurrent = current;
}
// ...其他统计量更新
}
这套代码最让我自豪的是它的教学价值——几乎每一行都有详细注释,包括:
- 寄存器位域的具体含义
- 参数选择的计算过程
- 实际调试中踩过的坑
- 关键波形的示波器截图位置
比如在PWM初始化函数里,我特意保留了当初烧管子的教训注释:
c复制// !!!重要提醒!!!
// 曾经因为忘记配置GPIO复用寄存器(GPIO MUX),
// 导致PWM信号无法输出到引脚,IGBT长时间导通烧毁
// 正确做法:
GPIO_SetupPinMux(EPWM1A_GPIO, GPIO_MUX_CPU1, 1);
对于想深入学习DSP电力电子控制的朋友,这个项目提供了绝佳的起点。它不仅展示了SPWM闭环控制的完整实现,更重要的是传授了实际工程中的调试经验和设计思维。