最近在搞基于TMS320F28335的永磁同步电机控制,发现这玩意儿真是既要玩明白算法又得跟寄存器死磕。直接上干货,聊聊代码里那些有意思的细节
·
电机马达DSP28335 永磁同步电机代码 CCS编辑,有PI控制算法、速度电流双闭环控制。 有方波有感无感算法,无感为3段反电势过零点。 有pmsm有感无感算法,有感有hall的foc,有磁编码器的,有增量编码器的。 无感为滑模观测器的。 提供原理图,源代码
双闭环的暴力美学
速度环套电流环的结构大家都不陌生,关键看怎么在28335里落地。来看这个电流环PI的裸代码:
typedef struct {
float Ref; // 电流给定
float Fbk; // 电流反馈
float Kp; // 比例系数
float Ki; // 积分系数
float Ui_prev; // 上次积分值
float Out; // 输出限幅值
} PI_Struct;
void PI_Calculate(PI_Struct *v) {
float Err = v->Ref - v->Fbk;
float Up = v->Kp * Err;
v->Ui_prev += v->Ki * Err * _IQ(0.0001); // 0.1ms控制周期
// 积分抗饱和
if (v->Ui_prev > v->Out)
v->Ui_prev = v->Out;
else if (v->Ui_prev < -v->Out)
v->Ui_prev = -v->Out;
v->Out = Up + v->Ui_prev;
}
这里的积分项处理有个骚操作——直接拿输出限幅值来钳位积分,比单独设积分限幅更暴力有效。注意_IQ()是Q格式转换宏,做定点数优化时这玩意能救命。
霍尔传感器的FOC实战
霍尔安装不准咋整?这段角度补偿代码实测有效:
#define HALL_SECTOR_ANGLE (60.0/180*PI) // 每扇区60度
float Get_Hall_Electrical_Angle() {
uint16_t hall_state = (GpioDataRegs.GPBDAT.bit.GPIO34 << 2) |
(GpioDataRegs.GPBDAT.bit.GPIO33 << 1) |
GpioDataRegs.GPBDAT.bit.GPIO32;
float base_angle = hall_state * HALL_SECTOR_ANGLE;
// 动态补偿量,上电自学习获得
return base_angle + hall_compensation_table[hall_state];
}
用GPIO直接读取霍尔状态,查表补偿比实时计算更省时钟周期。注意GPIO端口映射得查原理图确认,曾经因为引脚接反调了一整天...
滑模观测器的暗黑艺术
无感控制里最带感的部分,观测器核心代码长这样:
void SMO_Update(float Ia, float Ib, float theta) {
// 反电动势估算
float e_alpha = -Ld * (Ia - smo.Ia_prev)/T + R*Ia + V_alpha;
float e_beta = -Lq * (Ib - smo.Ib_prev)/T + R*Ib + V_beta;
// 符号函数处理
float z_alpha = e_alpha - smo.Est_Alpha;
float z_beta = e_beta - smo.Est_Beta;
smo.Est_Alpha += _sign(z_alpha) * SMO_GAIN * T;
smo.Est_Beta += _sign(z_beta) * SMO_GAIN * T;
// 角度提取
theta_elec = atan2(smo.Est_Beta, smo.Est_Alpha);
}
这里用后向差分代替微分运算,避免引入噪声。_sign()函数别手贱用标准库,自己写宏定义快10倍:
#define _sign(x) ((x)>=0 ? 1.0 : -1.0)
编码器配置的坑
增量式编码器的QEP配置要特别注意:
void Init_eQEP(void) {
EQep1Regs.QUPRD = 0xFFFF; // Unit Timer周期
EQep1Regs.QDECCTL.bit.QSRC = 0; // 正交计数模式
EQep1Regs.QEPCTL.bit.FREE_SOFT = 2; // 仿真挂起时继续运行
EQep1Regs.QEPCTL.bit.PCRM = 1; // 索引脉冲复位
EQep1Regs.QCAPCTL.bit.UPPS = 5; // 1/32分频捕获
}
遇到过SPI磁编码器数据跳变?可能是片选信号没延时:
float Read_AS5048B(void) {
SpiaRegs.SPICTL.bit.TALK = 0; // 先关闭发送
DELAY_US(1); // 必须的时序缓冲
SpiaRegs.SPICTL.bit.TALK = 1;
// ...后续数据收发
}
最后说下资源的事,原理图里PWM输出部分记得加死区互补配置,代码仓库里搜"28335 PMSM Toolkit"能找到完整工程。调参时准备好咖啡,这玩意儿可比写代码费劲多了——别问我怎么知道的。

更多推荐


所有评论(0)