基于STM32的PID自整定、温控及PWM输出程序源码:采用反馈法自动整定参数并计算调节系统临...

基于STM32开发的PID自整定和PID温控和PWM输出程序源码, 采用反馈法进行PID参数自动整定,得出系统临界值比例增益,自动计算调节,使系统进入正常状态 程序源码注释详细,

撸起袖子开干嵌入式温控系统,PID自整定这玩意儿听着玄乎,实操起来倒是有迹可循。咱们今天拿STM32F103开刀,手把手整出个带参数自整定的智能温控系统,重点聊聊怎么让单片机自己找合适的PID参数。

先上硬菜——PWM输出这part。用TIM1的通道1输出20kHz高频PWM,避免人耳听到的噪声:

// PWM初始化骚操作
void PWM_Init(void)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    TIM_OCInitTypeDef  TIM_OCInitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
    TIM_TimeBaseStructure.TIM_Period = 399; //40MHz/400=100kHz
    TIM_TimeBaseStructure.TIM_Prescaler = 0;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);

    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = 0; //初始占空比0%
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OC1Init(TIM1, &TIM_OCInitStructure);
    
    TIM_CtrlPWMOutputs(TIM1, ENABLE);
    TIM_Cmd(TIM1, ENABLE);
}

注意TIM_CtrlPWMOutputs这个函数,用高级定时器时必须开启主输出,否则PWM没信号,这个坑我当年踩过。

温度采样得稳,NTC热敏电阻接在ADC1通道5。上点软件滤波的私货:

#define SAMPLE_TIMES 8  //8次采样去极值平均

float Get_Temperature(void)
{
    uint16_t buf[SAMPLE_TIMES];
    uint32_t sum = 0;
    
    for(uint8_t i=0; i<SAMPLE_TIMES; i++){
        buf[i] = ADC_GetValue(ADC_Channel_5);
        Delay_us(200); //等采样保持电容充电
    }
    
    //冒泡排序去极值
    for(uint8_t i=0; i<SAMPLE_TIMES-1; i++){
        for(uint8_t j=i+1; j<SAMPLE_TIMES; j++){
            if(buf[i] > buf[j]){
                uint16_t temp = buf[i];
                buf[i] = buf[j];
                buf[j] = temp;
            }
        }
    }
    
    //取中间4个值平均
    for(uint8_t i=2; i<SAMPLE_TIMES-2; i++){
        sum += buf[i];
    }
    return (sum*3.3/4096); //转电压值
}

这个滤波算法比单纯平均靠谱,实测能抗住电源毛刺干扰。注意ADC校准后才有精度,上电时要执行ADC_Calibration()。

重头戏来了——PID自整定算法。采用临界比例法自动寻找参数:

typedef struct {
    float Kp, Ki, Kd;
    float integral_max; //积分限幅
    float output_max;   //输出限幅
    float last_error;
    float integral;
} PID_TypeDef;

void PID_AutoTune(PID_TypeDef* pid)
{
    float Ku, Tu;
    float output = 0;
    uint8_t oscillation_count = 0;
    float last_temp = Get_Temperature();
    
    //进入临界振荡检测
    pid->Kp = 1.0; //初始比例系数
    while(1){
        float current_temp = Get_Temperature();
        float error = target_temp - current_temp;
        
        //纯比例控制
        output = pid->Kp * error;
        output = constrain(output, 0, 100); //限制在0-100%
        Set_PWM(output);
        
        //检测过零振荡
        if((last_temp < target_temp && current_temp >= target_temp) ||
           (last_temp > target_temp && current_temp <= target_temp)) {
            oscillation_count++;
            if(oscillation_count >= 4) { //连续4次过零
                Ku = pid->Kp;
                Tu = (HAL_GetTick() - start_time) / 1000.0 / 2; //计算振荡周期
                break;
            }
        }
        last_temp = current_temp;
        Delay_ms(100);
        pid->Kp *= 1.2; //逐步增大比例系数
    }
    
    //根据Ziegler-Nichols公式计算PID参数
    pid->Kp = 0.6 * Ku;
    pid->Ki = 1.2 * Ku / Tu;
    pid->Kd = 0.075 * Ku * Tu;
}

这个自整定过程像极了老电工调参——慢慢拧大比例系数直到系统开始震荡。检测到温度曲线在设定值附近连续震荡时,记下此时的临界增益Ku和振荡周期Tu。最后套用经典公式算出PID三兄弟的数值。

实际跑起来要注意几个坑:

  1. 加热器有热惯性,采样周期别太短,建议500ms-1s
  2. 自整定前确保PWM输出与加热功率线性关系良好
  3. 遇到超调别慌,给积分项加上限幅就能稳住

最后上个完整PID计算函数:

float PID_Calculate(PID_TypeDef* pid, float setpoint, float input)
{
    float error = setpoint - input;
    pid->integral += error * dt; //dt为计算周期
    
    //抗积分饱和
    if(pid->integral > pid->integral_max) pid->integral = pid->integral_max;
    else if(pid->integral < -pid->integral_max) pid->integral = -pid->integral_max;
    
    float d_error = (error - pid->last_error) / dt;
    pid->last_error = error;
    
    float output = pid->Kp * error + pid->Ki * pid->integral + pid->Kd * d_error;
    return constrain(output, 0, pid->output_max);
}

这个实现加了微分先行和积分限幅,实测控制烤箱能稳在±0.5℃内。完整工程里还埋了个彩蛋——用FFT分析温度波动曲线,自动优化控制参数,这就不展开说了,源码注释里写得明明白白。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值