DSP28335 永磁同步电机代码 CCS编辑,有PI控制算法、速度电流双闭环控制。 有方波有感无感算法,无感为3段反电势过零点。 有pmsm有感无感算法,有感有hall的foc,有磁编码器的,有增量编码器的。 无感为滑模观测器的。 提供原理图,源代码
搞电机控制的兄弟们都懂,永磁同步电机这玩意儿既要速度又要力矩,双闭环那是基本功。今天拿DSP28335的工程代码开刀,咱们直接上干货,从电流环到无感算法,边看代码边分析。
先看电流环的PI实现。代码里用了结构体封装参数,这点挺聪明:
typedef struct { float Kp; float Ki; float Limit; float Ref; float Fdb; float Err; float Output; float Integral; } PI_Controller; void PI_Update(PI_Controller *pi) { pi->Err = pi->Ref - pi->Fdb; pi->Integral += pi->Ki * pi->Err * Ts; if(pi->Integral > pi->Limit) pi->Integral = pi->Limit; else if(pi->Integral < -pi->Limit) pi->Integral = -pi->Limit; pi->Output = pi->Kp * pi->Err + pi->Integral; }注意那个Ts变量,这里藏着采样周期的门道。很多新手会漏掉时间因子,结果调参调到怀疑人生。积分限幅直接写死在算法里,实测比外部钳位更干脆,防止饱和效应够直接。
速度环有个骚操作:把PI输出直接作为电流环的给定。这就构成了经典双闭环:
void Speed_Loop() { speed_pi.Ref = target_rpm; speed_pi.Fdb = actual_rpm; PI_Update(&speed_pi); current_pi.Ref = speed_pi.Output; current_pi.Fdb = Get_ActualCurrent(); PI_Update(¤t_pi); Update_PWM(current_pi.Output); }重点在转速到电流的映射系数,这里涉及电机转矩常数,代码里用了个隐藏的缩放因子,原理图上标着R_shunt电阻值,这两处必须对得上。
----
方波驱动:有感和无感的相爱相杀
有感方案简单粗暴,Hall信号直接触发换相:
void Hall_Commutation() { switch(Hall_State & 0x07) { //取低三位 case 0b101: Set_PWM_PhaseA_High(); break; case 0b100: Set_PWM_PhaseC_Low(); break; //...其他状态 } }但无感方案才是真刺激。三段式启动时,代码里强制固定相位开环拖动:
void Blind_Start() { for(int i=0; i<100; i++){ //强制拖动 EPwm1Regs.CMPA.half.CMPA = open_loop_duty++; DELAY_US(500); } while(!Detect_Zero_Cross()); //等待反电势过零 Enable_ExtInt(); //切中断检测 }过零检测用ADC采样中性点电压,注意这里的比较器滞环设计:
#pragma INTERRUPT(zero_cross_ISR) void zero_cross_ISR(){ if(AdcResult[0] > Vbus/2 + HYST || AdcResult[0] < Vbus/2 - HYST){ Commutation_Delay(30); //补偿30度电角度 Next_Commutation(); } }这里Vbus/2是理论中性点电压,实际PCB布局不好会有毛刺,所以原理图上可见三个220pF电容滤高频噪声。
----
FOC全家桶:从Hall到磁编码
有Hall的FOC最省心,直接拿霍尔信号做粗略定位:
void Hall_InitAngle(){ uint16_t sector = Hall_State & 0x07; est_angle = sector * 60; //每60度一个区间 }但磁编码器才是真爱,SPI读取AS5048:
uint16_t Read_Encoder(){ SpiRegs.SPIBUF = 0xFFFF; //发送空数据 while(!SpiRegs.SPISTS.bit.INT_FLAG); return SpiRegs.SPIBUF & 0x3FFF; //14位数据 }重点在机械角度转电角度的倍数处理,极对数参数写死在头文件里,改完记得重新校准。
增量式编码器最折腾,Z信号处理不当就翻车:
void QEP_Init(){ EQep1Regs.QUPRD = 1000000; //1秒周期 EQep1Regs.QDECCTL |= POS_RESET; //Z脉冲复位位置 }速度计算用M法测速,注意防止计数器溢出:
float Get_Speed(){ int32_t delta = EQep1Regs.QPOSLAT - last_pos; if(delta > 0x7FFF) delta -= 0xFFFF; //处理反转 return delta * 60.0 / (PPN * Ts); //转每分钟 }----
滑模观测器:无感中的战斗机
核心算法在滑模面计算,这段代码直接操作定点数:
void SMO_Update(){ alpha = V_alpha - Rs*i_alpha + Ls*(i_alpha - prev_i_alpha)/Ts; beta = V_beta - Rs*i_beta + Ls*(i_beta - prev_i_beta)/Ts; e_alpha = alpha - est_alpha; e_beta = beta - est_beta; //滑模控制量 z_alpha = (e_alpha > 0) ? Z_SLIDE : -Z_SLIDE; z_beta = (e_beta > 0) ? Z_SLIDE : -Z_SLIDE; est_alpha += (z_alpha - Rs*i_alpha) * Ts/Ls; est_beta += (z_beta - Rs*i_beta) * Ts/Ls; est_angle = atan2(est_beta, est_alpha); }这里Z_SLIDE参数决定观测器刚度,原理图上可见运放电路给的反电动势调理电路,配合代码中的Rs电阻参数必须准确。
调参秘诀:先给大Z值确保锁定,再逐步降低减小噪声。实测波形里能看到反电势从锯齿状变平滑的过程。
----
代码仓库里附带了CCS工程文件和原理图PDF,注意PWM驱动部分与EPWM模块的对应关系,某个老哥曾经把EPWM1A接到IGBT3导致炸管,血的教训...