DSP28335直流电机闭环控制:PID调节与多传感器集成系统

dsp28335直流电机闭环控制 直流有刷电机转速闭环控制,用普中科技的开发板做的,电机是500线的ab增量编码器,用到了蜂鸣器模块,led,lcd1602,dht11温湿度传感器,l298n电机驱动模块,矩阵键盘。 采用pid控制,进行电机正反调速,超速报警并自动降速。 实时显示温度和湿度在lcd1602上。 有详细的说明,照着接线并把程序下载进去,就可以复现视频功能。

刚拿到普中DSP28335开发板那会儿,手痒想搞点硬核的。正好手头有个500线编码器的直流电机,干脆做个带温湿度显示的PID调速系统。这玩意儿做起来比想象中带感,特别是看着电机随着键盘输入乖乖变速的时候。

先说硬件组合拳:L298N驱动板接电机AB相,编码器信号线直接怼到28335的QEP接口。LCD1602用4位模式省IO口,DHT11随便找个GPIO接,矩阵键盘接法最骚——本来8个IO能搞定的矩阵,我偏用跳线帽做了个4x3布局,毕竟要给蜂鸣器和LED留足戏份。

先看编码器处理这块硬骨头。500线的AB相每转能出2000个脉冲,定时器捕获必须得够快:

#pragma CODE_SECTION(eqep1Isr,"RAMfuncs");
interrupt void eqep1Isr(void){
    static int32 old_pos=0;
    int32 new_pos = EQep1Regs.QPOSCNT;
    motor_rpm = (new_pos - old_pos)*60/(4*500)*1000; //每转2000脉冲,采样周期1ms
    old_pos = new_pos;
    EQep1Regs.ICCLR.bit.INT=1; //清中断
}

这段中断服务程序1ms执行一次,把编码器计数转成转速。注意EQep寄存器的操作——这货对时序敏感得很,写错顺序直接摆烂。

PID控制才是重头戏。调参那几天差点把示波器看吐。核心算法长这样:

float pid_update(PID* pid, float actual){
    pid->error = pid->target - actual;
    float p_out = pid->kp * pid->error;
    
    pid->integral += pid->ki * pid->error * dt;
    if(pid->integral > pid->max_i) pid->integral = pid->max_i;
    else if(pid->integral < -pid->max_i) pid->integral = -pid->max_i;
    
    float d_out = pid->kd * (pid->error - pid->prev_error)/dt;
    pid->prev_error = pid->error;
    
    float output = p_out + pid->integral + d_out;
    return output > pid->max_out ? pid->max_out : (output < -pid->max_out ? -pid->max_out : output);
}

这里埋了个坑——dt必须准确,我直接用定时器中断里的时间戳。积分限幅很重要,不然电机启动时积分项能飙到姥姥家。

温湿度显示看着简单,DHT11的时序却是个磨人精。代码里这个延时函数是关键:

void dht11_delay_us(int us){
    volatile int i = us * 8; //实测主频150MHz时这个系数刚好
    while(i--);
}

用volatile防止编译器优化,循环次数得靠示波器抓波形硬调。读数据时遇到校验错误就重试,最多试三次,防止LCD显示抽风。

键盘处理用了状态机套路,长按加速功能贼实用:

uint16 key_scan(){
    static uint8 last_state[12] = {0};
    static uint16 hold_cnt[12] = {0};
    for(int i=0; i<12; i++){
        if(key_pressed(i)){
            if(last_state[i] == 0){ //首次按下
                last_state[i] = 1;
                return i;
            }
            if(++hold_cnt[i] > 1000){ //长按1秒
                hold_cnt[i] = 0;
                return i | 0x8000; //高位标记长按
            }
        }else{
            last_state[i] = 0;
            hold_cnt[i] = 0;
        }
    }
    return 0xFFFF;
}

这样既处理了抖动又实现了长按加速,按着不放转速蹭蹭涨,松手自动锁定目标值。

报警模块最欢乐——超速时蜂鸣器唱《野蜂飞舞》,LED玩呼吸灯:

if(abs(motor_rpm) > MAX_SPEED){
    static uint16 pwm_val = 0;
    static int dir = 1;
    pwm_val += dir*50;
    if(pwm_val >= 3000) dir = -1;
    else if(pwm_val <= 0) dir = 1;
    
    PWM_set(AUX_PWM, pwm_val); //呼吸灯效果
    BUZZER_ON();
    DELAY_MS(50);
    BUZZER_OFF();
}

其实应该用PWM驱动蜂鸣器,但手头模块只能高低电平控制,就做了个断续报警声。后来发现这样反而比持续响更抓耳。

调通那天,LCD上温度湿度跟着转速一起跳,键盘按正负切转向,超速就闪灯尖叫,有种赛博朋克配蒸汽机的魔幻感。源码里留了几个彩蛋:长按*和#键能切PID参数,不过没写在文档里——留给后来者自己折腾的惊喜。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值