电机马达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"能找到完整工程。调参时准备好咖啡,这玩意儿可比写代码费劲多了——别问我怎么知道的。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐