搞电机控制这活儿,有时候真觉得像在玩俄罗斯方块——各种模块得严丝合缝地对上。最近用TMS320F28335折腾永磁同步电机的双闭环控制,倒是摸出点有意思的门道
主控芯片dsp tms320f28335,基于Matlab Simulink开发的嵌入式模型,模型可自动生成ccs工程代码,生成的代码可直接运行在主控芯片中。 该模型利用id=0的矢量控制,实现了永磁同步电机的速度电流双闭环控制。
这个DSP的硬件资源确实够硬核,12路PWM输出口对付三相逆变器绰绰有余。不过真正让我省心的还是Matlab/Simulink的自动代码生成,从仿真模型直接导出CCS工程的操作,比手动敲代码靠谱多了。记得第一次看到生成的PWM配置代码时,差点以为系统出bug了:
EPwm1Regs.TBPRD = SYSTEM_FREQUENCY / (2 * PWM_FREQ) - 1;
EPwm1Regs.CMPA.half.CMPA = (uint16_t)(DutyCycle * EPwm1Regs.TBPRD);
这货居然把死区时间和载波频率的计算打包得这么利索。TBPRD寄存器设置周期值的时候,自动考虑了系统时钟分频,CMPA直接映射占空比参数,比人工计算省了至少三杯咖啡的时间。
电流环的实现最考验细节。模型里那个id=0的矢量控制策略,生成代码后变成了实实在在的坐标变换:
void ClarkTransform(float ia, float ib, float *i_alpha, float *i_beta) {
*i_alpha = ia;
*i_beta = (ia + 2*ib) * ONE_BY_SQRT3;
}
这个看似简单的Clarke变换,在代码里藏了个小彩蛋——ONEBYSQRT3用的是Q15格式的0x6ED9,既避免了浮点运算又保证了精度。不过实测中发现,当电流采样有毛刺时,beta轴分量偶尔会抽风,后来在ADC中断里加了个移动平均滤波才稳住。
速度环的PI参数整定是个玄学活。自动生成的PID模块代码虽然规范,但实际调试时发现:
void SpeedPI_Update(float ref, float fdb) {
Err = ref - fdb;
Integrator += Ki * Err * Ts;
Output = Kp * Err + Integrator;
Output = (Output > MAX_OUTPUT) ? MAX_OUTPUT : Output;
}
这个积分抗饱和处理还是太朴素。电机急减速时会出现积分windup,后来手动加了反向积分限制才解决。看来自动生成的代码也不是万能膏药,关键时刻还得老司机上手调。
最爽的时刻莫过于看生成的GPIO配置代码自动对齐硬件设计:
GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 0; // 故障信号输入
GpioCtrlRegs.GPADIR.bit.GPIO1 = 1; // 运行状态LED
连引脚分配都和原理图一一对应,省去了查寄存器手册的麻烦。不过要注意Simulink里GPIO模块的命名必须和PCB标注完全一致,否则生成的代码会让你找bug找到怀疑人生。
烧录完代码第一次试机时,电机抖得像筛糠。用CCS的实时监测功能抓了组数据,发现电流环响应比仿真慢了0.5ms。原来是生成的ADC采样代码默认用了单次触发模式,改成连续采样后波形立马顺溜了。这也提醒我们,自动生成的代码终究是模板,具体外设配置还得结合实际情况魔改。
从仿真模型到实际转起来的电机,这种"所见即所得"的开发体验确实上瘾。不过也别被自动化工具惯坏了,该懂的寄存器操作、中断机制这些基本功,该出手时还是得出手。毕竟,代码生成器可不会帮你擦屁股——当电机突然啸叫的时候,还是得靠示波器和万用表说话。

更多推荐


所有评论(0)