主要实现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度恒温
升降温曲线实现