TEC 高精度控温算法

主要实现TEC的指定时间的升温与指定时间的降温,指定温度的恒温,给合硬件的优化可实现高精度温度控制

void temp_tec_pid(uint8_t chn)
{   
    uint8_t i;
    float mid_fTem1;
    float mid_fTem2;
    float mid_fTem3; 		        //参数计算临时值	
    float mid_fPWM = 0;             //最终输出的PWM值
    
    temperation_control_t *temp_ctrl_ptr = &temperation_tec_control[chn];
    temp_pid_t  *temp_pid_ptr = &temp_ctrl_ptr->temp_pid;

    if(temp_ctrl_ptr->u8EnFlag == 1 ){ //如果标志位使能,则PID温控,
        temp_pid_ptr->ActTemperature = tec_temp.fTemp[chn];	     
    }
    
    temp_pid_ptr->SetTemperature  = temp_ctrl_ptr->fTargeter;
    
    switch(temp_ctrl_ptr->state)
    {
        case 0X00 ://state-0:空闲状态
        {   
            //如果有触发PID状态跳转而且使能了该通道PID温控
            if(temp_ctrl_ptr->u8PidStateFlag == 1 && temp_ctrl_ptr->u8Channel_En==1){

                temp_ctrl_ptr->state	= 0X01;//跳转至状态1		
                temp_ctrl_ptr->u8PidStateFlag = 0 ;//跳转状态标志清0
                temp_pid_ptr->integral = 0;         //通道积分清0
                temp_ctrl_ptr->u8Channel_Done = 0 ;//通道到达目标温度标志清0/小于0.1摄氏度时置位			
                temp_pid_ptr->SetTemperature  = temp_ctrl_ptr->fTargeter;//设置目标温度				
                temp_ctrl_ptr->u8PwmDir =0;	//制冷方向降温标志		
                temp_ctrl_ptr->u8PwmAdj =0;	//占空比计数
                
//                voltage_enable(chn, 1);
            }
            else if(temp_ctrl_ptr->u8PidStateFlag == 1 && temp_ctrl_ptr->u8Channel_En==0){
                
                temp_ctrl_ptr->u8PidStateFlag = 0 ;//跳转状态标志清0
                tec_drv_pwm(chn, TEC_CLOSE, 0);	//序号,关闭标志,占空比;	
                
//                voltage_enable(chn, 0);
                
                float temp = tec_temp.fTemp[chn];
                if( temp>=0 ){
                    temppid_segger_log("CHN%d %d %d %d.%d \r" ,chn+1, temp_ctrl_ptr->state , tec_driver_pwm(chn)->u8StepH_Cnt , (int)temp, (int)((temp-(int)temp)*100) );
                }
                else{
                    temp *= -1;
                    temppid_segger_log("CHN%d %d %d -%d.%d \r" ,chn+1, temp_ctrl_ptr->state ,tec_driver_pwm(chn)->u8StepH_Cnt , (int)temp, (int)((temp-(int)temp)*100) );
                }
            }									
            break;
        }
        case 0X01 ://state-1:进行比例升降温
        {   

            temp_pid_ptr->Err = temp_pid_ptr->SetTemperature - temp_pid_ptr->ActTemperature;//当前目标温度与实际温度差								

            /*---------------速度自动调节 ----------------------------------------------*/                    
            mid_fTem1 =	(  temp_pid_ptr->Err_Last - temp_pid_ptr->Err ) * PID_PRE  ;//计算变温速度/50MS计算1次/单位:℃/S		/	此值为正则实际在加热中					
            mid_fTem2 = (float)fabs(mid_fTem1);//求出速度绝对值
            
            float temp2;
            temp2 = mid_fTem2;
            temppid_segger_log("CHN%d %d.%d %d\n" ,chn+1, (int)temp2, (int)((temp2-(int)temp2)*100),temp_ctrl_ptr->u8PwmAdj );

            /*--------------如果在升温控制进行PID-----------------------*/ 
            if(temp_ctrl_ptr->u8HotCool_En == 0X01 ){
                if(mid_fTem2 > temp_ctrl_ptr->fSpeed ){//如果变温速度太快
                    
                    /*--------------如果是降温太快,则需要自加1----------------*/
                    if(mid_fTem1 < 0){
                        if(temp_ctrl_ptr->u8PwmAdj < PWM_RANG)
                            temp_ctrl_ptr->u8PwmAdj+=5;	
                    }
                    /*--------------如果是升温太快,则需要自减1----------------*/
                    if(mid_fTem1 > 0){
                        if(temp_ctrl_ptr->u8PwmAdj > 5)
                            temp_ctrl_ptr->u8PwmAdj-=5;	
                    }
                }
                else if( mid_fTem2 < temp_ctrl_ptr->fSpeed ){//如果变温速度太慢,占空比自加1
                    if(temp_ctrl_ptr->u8PwmAdj < PWM_RANG)
                        temp_ctrl_ptr->u8PwmAdj+=5;																											
                }
            }
            /*--------------如果在降温控制进行PID-----------------------*/ 
            else if(temp_ctrl_ptr->u8HotCool_En == 0X02 ){
                if(mid_fTem2 > temp_ctrl_ptr->fSpeed  ){//如果变温速度太快,占空比自+1
                    if(temp_ctrl_ptr->u8PwmAdj <= PWM_RANG)
                        temp_ctrl_ptr->u8PwmAdj+=5;																
                }
                else if( mid_fTem2 < temp_ctrl_ptr->fSpeed ){//如果变温速度太慢,占空比自-1
                    if(temp_ctrl_ptr->u8PwmAdj > 0)
                        temp_ctrl_ptr->u8PwmAdj--;
                }											
            }									
            /*--------------如果加热方向降温无法到达目标速度,则需要制冷加速降温 -------------*/   
            if(temp_ctrl_ptr->u8PwmAdj == 0){//如果PWM已经减至0
                if( temp_pid_ptr->Err < 0 ){
                    temp_ctrl_ptr->u8PwmDir ++ ;
                    if(temp_ctrl_ptr->u8PwmDir >= 20){
                        temp_ctrl_ptr->state	= 0X02;//跳转至状态2,进行制冷降温	
                        break;
                    }
                }
            }
            else 
                temp_ctrl_ptr->u8PwmDir =0;


            /*--------------如果温差小于2℃,则进入PID控制 case 0X03 -----------------------*/ 
            //mid_fTem3 = (float)fabs(temp_pid_ptr->Err[chn]);//求出温差绝对值

            /*--------------如果在升温控制中-----------------------*/ 
            if(temp_ctrl_ptr->u8HotCool_En == 0X01 ){
                /*--------------如果实际温度超过目标温度,则进入PID控制 case 0X03 -----------------------*/
                if( temp_pid_ptr->Err <= -0.5  ){
                    temp_ctrl_ptr->state	= 0X03;//跳转至状态3,进行PID控制	
//                    pwm_save = temp_ctrl_ptr->u8PwmAdj;
                    temp_pid_ptr->integral = pwm_96_save;
                    break;																									
                }										
            }
            /*--------------如果在降温控制中-----------------------*/ 
            else if(temp_ctrl_ptr->u8HotCool_En == 0X02 ){
                /*--------------如果实际温度低于目标温度,则进入PID控制 case 0X03 -----------------------*/
                if( temp_pid_ptr->Err >= 0.5  ){
                    temp_ctrl_ptr->state	= 0X03;//跳转至状态3,进行PID控制	
                    temp_pid_ptr->integral = pwm_57_save;
//                    pwm_save = temp_ctrl_ptr->u8PwmAdj;
                    break;																									
                }										
            }	

            tec_drv_pwm(chn, TEC_HEAT,temp_ctrl_ptr->u8PwmAdj);	//序号,加热标志,占空比;
            temp_pid_ptr->Err_Last =  temp_pid_ptr->Err;  //上一次的偏差值

            float temp = tec_temp.fTemp[chn];;
            if( temp>=0 ){
                temppid_segger_log("CHN%d %d %d %d.%d \r" ,chn+1, temp_ctrl_ptr->state , tec_driver_pwm(chn)->u8StepH_Cnt , (int)temp, (int)((temp-(int)temp)*100) );
            }
            else{
                temp *= -1;
                temppid_segger_log("CHN%d %d %d -%d.%d \r" ,chn+1, temp_ctrl_ptr->state ,tec_driver_pwm(chn)->u8StepH_Cnt , (int)temp, (int)((temp-(int)temp)*100) );
            }

            /*--------------如果有触发PID状态跳转 -----------------------*/ 									
//            if(temp_ctrl_ptr->u8PidStateFlag == 1){
//                temp_ctrl_ptr->state	= 0X00;//跳转至状态0	
//                tec_drv_pwm(chn, TEC_CLOSE, 0);	//序号,关闭标志,占空比;
//                temp_ctrl_ptr->u8PidStateFlag = 1 ;
//            }

            break;
        }
        case 0X02 ://state-2:制冷降温状态
        {   
            temp_pid_ptr->Err = temp_pid_ptr->SetTemperature - temp_pid_ptr->ActTemperature;//当前目标温度与实际温度差								

            /*---------------速度自动调节 ----------------------------------------------*/                    
            mid_fTem1 =	(  temp_pid_ptr->Err_Last - temp_pid_ptr->Err ) * (PID_PRE)  ;//计算变温速度/50MS计算1次/单位:℃/S									
            mid_fTem1 = (float)fabs(mid_fTem1);//求出速度绝对值

            if(mid_fTem1 > temp_ctrl_ptr->fSpeed ){//如果变温速度太快,占空比自减1
                if(temp_ctrl_ptr->u8PwmAdj > 0)
                    temp_ctrl_ptr->u8PwmAdj--;													
            }	
            else if( mid_fTem1 < temp_ctrl_ptr->fSpeed ){//如果变温速度太慢,占空比自加1
                if(temp_ctrl_ptr->u8PwmAdj <= 100)
                    temp_ctrl_ptr->u8PwmAdj++;																											
            }	

            /*--------------如果温差小于2℃,则进入PID控制 case 0X03 -----------------------*/ 
            mid_fTem2 = (float)fabs(temp_pid_ptr->Err);//求出温差绝对值
            if(mid_fTem2 < 0.1 ){
                temp_ctrl_ptr->state	= 0X03;//跳转至状态3,进行PID控制	
                temp_pid_ptr->integral = pwm_57_save;
                break;																		
            }

            tec_drv_pwm(chn, TEC_COOL, temp_ctrl_ptr->u8PwmAdj);	//序号,制冷标志,占空比;
            temp_pid_ptr->Err_Last =  temp_pid_ptr->Err;  //上一次的偏差值
            
            float temp = tec_temp.fTemp[chn];;
            if( temp>=0 ){
                temppid_segger_log("CHN%d %d %d %d.%d \r" ,chn+1, temp_ctrl_ptr->state , tec_driver_pwm(chn)->u8StepH_Cnt , (int)temp, (int)((temp-(int)temp)*100) );
            }
            else{
                temp *= -1;
                temppid_segger_log("CHN%d %d %d -%d.%d \r" ,chn+1, temp_ctrl_ptr->state ,tec_driver_pwm(chn)->u8StepH_Cnt , (int)temp, (int)((temp-(int)temp)*100) );
            }
            /*--------------如果有触发PID状态跳转 -----------------------*/ 									
//            if(temp_ctrl_ptr->u8PidStateFlag == 1){
//                temp_ctrl_ptr->state	= 0X00;//跳转至状态0	
//                tec_drv_pwm(chn, TEC_CLOSE, 0);	//序号,关闭标志,占空比;
//                temp_ctrl_ptr->u8PidStateFlag = 1 ;
//            }									
            break;																		
        }
        case 0X03 ://state-3:PID温控状态
        {   
            temp_pid_ptr->Err = temp_pid_ptr->SetTemperature - temp_pid_ptr->ActTemperature;//当前目标温度与实际温度差		

            /*--------------判断通道是否到达目标温度,偏差为0.1℃-----------------------*/ 									
            if(temp_pid_ptr->Err <= 0.1 && temp_pid_ptr->Err >= -0.1){
                temp_ctrl_ptr->u8Channel_Done = 1;															
            }

            /*--------------如果在升温控制进行PID-----------------------*/ 
            if(temp_ctrl_ptr->u8HotCool_En == 0X01 ){
                temp_pid_ptr->integral += temp_pid_ptr->Err;  //积分偏差累加,刚开始为正数	
                mid_fTem1 = temp_pid_ptr->Err - temp_pid_ptr->Err_Last;//差分变化值,当前值减上次值,刚开始为负数
                if(mid_fTem1>=0 && temp_pid_ptr->Err>=0)//出现降温且还没有达到目标温度
                    mid_fTem2=60.0;
                else if(mid_fTem1<=0)
                    mid_fTem2=0.0;

                temp_ctrl_ptr->u8PwmCoe = temp_adj_factor(temp_pid_ptr->SetTemperature );//获取调整系数	

                mid_fPWM = syscfg_ptr()->temp_pid_para.kpid_warm.kp*temp_pid_ptr->Err + \
                    syscfg_ptr()->temp_pid_para.kpid_warm.ki*temp_pid_ptr->integral + \
                    mid_fTem2* mid_fTem1 + temp_ctrl_ptr->u8PwmCoe;
                if(mid_fPWM >= PWM_RANG)
                    mid_fPWM = PWM_RANG;
                if(mid_fPWM <= 0)
                    mid_fPWM = 0;													
                temp_ctrl_ptr->u8PwmAdj = (uint16_t)mid_fPWM;//赋值PWM占空比											
//                if( mid_fPWM < pwm_save-50 ){
//                    tec_drv_pwm(chn, TEC_HEAT, pwm_save);	//序号,加热标志,占空比;							
//                }
//                else{
                    tec_drv_pwm(chn, TEC_HEAT, temp_ctrl_ptr->u8PwmAdj);	//序号,加热标志,占空比;							
//                    pwm_save = 0;
//                }
                temp_pid_ptr->Err_Last =  temp_pid_ptr->Err;  //上一次的偏差值
                
                temppid_segger_log("CHN%d %d %d\r" ,chn+1, temp_ctrl_ptr->u8PwmAdj,temp_ctrl_ptr->u8PwmCoe );

                float temp = tec_temp.fTemp[chn];;
                if( temp>=0 ){
                    temppid_segger_log("CHN%d %d %d %d.%d \r" ,chn+1, temp_ctrl_ptr->state , tec_driver_pwm(chn)->u8StepH_Cnt , (int)temp, (int)((temp-(int)temp)*100) );
                }
                else{
                    temp *= -1;
                    temppid_segger_log("CHN%d %d %d -%d.%d \r" ,chn+1, temp_ctrl_ptr->state ,tec_driver_pwm(chn)->u8StepH_Cnt , (int)temp, (int)((temp-(int)temp)*100) );
                }
            }

            /*--------------如果在降温控制进行PID-----------------------*/ 
            else if(temp_ctrl_ptr->u8HotCool_En == 0X02 ){

                /*--------------如果环境温度大于目标温度需要进行制冷-----------------------*/
                if(  TEMP_ENV >= temp_pid_ptr->SetTemperature){
                    temp_pid_ptr->integral += temp_pid_ptr->Err;  //积分偏差累加	

                    mid_fPWM = syscfg_ptr()->temp_pid_para.kpid_cool_below_env.kp*( -temp_pid_ptr->Err) + \
                        syscfg_ptr()->temp_pid_para.kpid_cool_below_env.kp * ( -temp_pid_ptr->integral) ;

                    temp_ctrl_ptr->u8PwmAdj = (uint16_t)mid_fPWM;//赋值PWM占空比		
                    tec_drv_pwm(chn, TEC_COOL, temp_ctrl_ptr->u8PwmAdj);	//序号,制冷标志,占空比;							
                    temp_pid_ptr->Err_Last =  temp_pid_ptr->Err;  //上一次的偏差值		
                    
                    float temp = tec_temp.fTemp[chn];;
                    if( temp>=0 ){
                        temppid_segger_log("CHN%d %d %d %d.%d \r" ,chn+1, temp_ctrl_ptr->state , tec_driver_pwm(chn)->u8StepH_Cnt , (int)temp, (int)((temp-(int)temp)*100) );
                    }
                    else{
                        temp *= -1;
                        temppid_segger_log("CHN%d %d %d -%d.%d \r" ,chn+1, temp_ctrl_ptr->state ,tec_driver_pwm(chn)->u8StepH_Cnt , (int)temp, (int)((temp-(int)temp)*100) );
                    }
                }

                /*--------------如果环境温度小于目标温度需要进行加热-----------------------*/
                else{
                    temp_pid_ptr->integral += temp_pid_ptr->Err;  //积分偏差累加	

                    temp_ctrl_ptr->u8PwmCoe = temp_adj_factor(temp_pid_ptr->SetTemperature );//获取调整系数		

                    mid_fPWM = syscfg_ptr()->temp_pid_para.kpid_cool_above_env.kp*(temp_pid_ptr->Err) + \
                        syscfg_ptr()->temp_pid_para.kpid_cool_above_env.ki * (temp_pid_ptr->integral) + \
                        temp_ctrl_ptr->u8PwmCoe;

                    if(mid_fPWM >=PWM_RANG)
                        mid_fPWM=PWM_RANG;
                    if(mid_fPWM <=0  )
                        mid_fPWM=0;

                    temp_ctrl_ptr->u8PwmAdj = (uint16_t)mid_fPWM;//赋值PWM占空比

                    tec_drv_pwm(chn, TEC_HEAT, temp_ctrl_ptr->u8PwmAdj);	//序号,加热标志,占空比;	

                    temp_pid_ptr->Err_Last =  temp_pid_ptr->Err;  //上一次的偏差值		
                    
                    float temp = tec_temp.fTemp[chn];;
                    if( temp>=0 ){
                        temppid_segger_log("CHN%d %d %d %d.%d \r" ,chn+1, temp_ctrl_ptr->state , tec_driver_pwm(chn)->u8StepH_Cnt , (int)temp, (int)((temp-(int)temp)*100) );
                    }
                    else{
                        temp *= -1;
                        temppid_segger_log("CHN%d %d %d -%d.%d \r" ,chn+1, temp_ctrl_ptr->state ,tec_driver_pwm(chn)->u8StepH_Cnt , (int)temp, (int)((temp-(int)temp)*100) );
                    }
                }
            }

            //如果有触发PID状态跳转
//            if(temp_ctrl_ptr->u8PidStateFlag == 1){
//                temp_ctrl_ptr->state	= 0X00;//跳转至状态0	
//                tec_drv_pwm(chn, TEC_CLOSE, 0);	//序号,关闭标志,占空比;
//                temp_ctrl_ptr->u8PidStateFlag = 0 ;
//            }
            break;
        }							
        default :
            break;	
    }
}

算法分三部分,主要实现定时匀速升温,定时匀速降温,指定温度降,升温与降温不能产生太大过冲,恒温精度高

以下为实验实测视频,目标温度不要求精准可通过校准实现偏差修正,主要实现温度稳定

95度恒温

升降温曲线实现

你可能感兴趣的:(rt-thread,STM32,单片机外围电路,算法,tec,PID)