PID 控制 PWM 輸出方式 加熱區及冷卻區恆溫控制

2019-07-20 23:27发布

PID 控制 PWM 輸出方式 加熱區恆溫控制 及冷卻區恆溫控制,動作及控制方式說明:

控制器: ALIENTEK 战舰STM32F103ZET6开发板
3.5’寸屏模块,橫屏顯示, 库函数方式編寫

1 組加熱器及 4個冷卻排風風扇 ,  共5組 PID+PWM 溫度控制  , 17支感溫棒 (T Type 熱電偶  + MAX31855T)

    有兩個不同溫度區域

    一個
加熱恆定溫度 控制97度的高溫區: PID 控制 PWM 輸出 到 SSR 控制 AC 加熱器 (恆溫控制加熱區)
    一個排風降溫恆定溫度 控制70度的區: PID 控制 PWM 輸出到 ULN2803A 驅動IC , 使驅動 DC 小型1W 風扇, (恆溫控制降溫區)
           降溫區有4個冷卻排風風扇也就是降溫區又分成4個小區域
 

1.    4環境冷卻風扇稍微墊高,因為環境溫度是可設定,要 匹配風扇風量, 很難有一定的標準 使排風風扇產生漏風, 降低風扇最低轉速時排風量仍過強的問題   2.  當冷卻風扇最低轉速產生的排風量小於加熱器產生的熱量時 , 多餘的熱量會使溫度緩慢上升, 所以當度到達低於設定的環境溫度兩度內時 風扇保持最低 轉速排風, 使溫度變成緩慢上升 環境溫度控制誤差不會低於2, 所以風扇不會有停止轉動機會)   3.  當溫度大於達設定環境溫度時, PID 調速控制緩慢提升風扇最低轉速, 當扇轉速增加,相對提昇排風量達到緩慢降溫的作用         當溫度底於設定環境溫度時,  PID 調速控制輸出 =0, 風扇又保持最低 轉速排風環境溫度又變成緩慢上升 使環境溫度保持+_ 1度內漂動   經過測試後可能優點   1. 風扇轉速變化較小,保持有一定的最低轉速,  風扇也不會有 轉停ON/OFF控制現象   2. 環境溫度 控制更精準,  溫度控制 大多是 +_ 1度內 最高也不會超過1.5度   ( 因為相鄰兩邊風扇會互相拉風降溫 , 及 MAX31855T 溫度解析度是0.25,如果是0.1 的解析度會更精準 )   3. 風扇和本體有空隙 即有表示風扇有漏風, 降低熱傳導及沒有完全抽爐內熱風  (製程因素風扇要用抽的不能用吹的)   ,抽爐外冷風, 降低排風溫度, 使排風扇不致過熱   4. 比較不會受到現場溫度  引響到恆溫控制 , 減少或不必再去調整 PID 參數 (如還會再遇到最低轉速時冷風過強,  再加大風扇間隙降低排風量比例, 就像是比例控制閥 )   5. 啟動後如動作正常, 風扇應該多是一直轉動, 萬一風扇如有任何一個沒有轉動, 也會比較好發現為何風扇不轉的問題
  PID 測試經驗:
比例項 P : 只是給
溫度控制達到設定目標溫度附近

積分項 I :  加熱器 主要是還是靠積分項去做恆溫控制,
                溫度過低時, 積分項值會增加
                
溫度過高時, 積分項值會減少
                當積分項穩定之後, 溫度就不太會變化
                測試時,
 加熱器溫度控制, 是可達  +_ 0.2 度內


微分
項 : 溫度有變化時,短暫增益, 對恆溫控制引響不大

PS.
大家經驗互相交流一下 (以上提供 PID  控制方式, 完全是個人想出來及測試出來的, , 提供參考,或應用)   Set.C  設定要控制的溫度   Temp.C 感溫棒量到的現在溫度   Power;  經 變形 PID 運算後 PWM 輸出值 ( PWM佔空比最大值是大1000)    

/*====================================================================================================/  ID1 程式 =====================================================================================================*/ void PID1_Init(void) { //PID=100000 PWM=1000 =1/100 PID1.TargetTemp =PID_Parameter[0]; //9700 設定目標溫度值 PID1.Kp=PID_Parameter[1]; //100 比例常数Proportional Const  //[100x100=10000 /100=100  (0.15)] PID1.Ki=PID_Parameter[2]; // 3积分常数Integral Const //[2000*5=10000/100=100 (0.1)]  (0.5 20=10s ) PID1.Kd=PID_Parameter[3]; //50 微分常数Derivative Const  //[25*200=5000 /100=50  (+_0.05)]  Max=0.1 PID1.Keep=PID_Parameter[4]; //設定保持最低輸出值 //[100/1000 (0.1)] PID1.Error0=0.0; //目前誤差值 PID1.Error1=0.0;   // Error[-1] 上次误差 PID1.SumError = 0; // HeaterSumErr; //累積溫度誤差總和值 PID1.OutputValue=0 ; //实际输出量 PID1.TargetValue =PID1.TargetTemp ; // 设定目标值Desired value Target }
void PID1_Control(void) //Temp.13~17 Heater { //加熱器 控制方式:1 取加熱器溫度感溫棒13, 加熱器中心感溫棒溫度,4次平均值,
        //MAX31855 解析度是 0.25, 4次平均值是希望有更小的解析度, 加熱週期1秒  MAX31855_13_Read(); //加熱器中心溫度顯示 HeaterTemp4 = HeaterTemp3; //加熱器 上次4量測到溫度 Temperature HeaterTemp3 = HeaterTemp2; //加熱器 上次3量測到溫度 Temperature HeaterTemp2 = HeaterTemp1; //加熱器 上次2量測到溫度 Temperature HeaterTemp1 = HeaterTemp0 ; //加熱器 上次1量測到溫度 Temperature HeaterTemp0 = MAX31855_13.Thermocouple; //加熱器 上次0量測到溫度 Temperature PID1.NowTemp=(HeaterTemp0 + HeaterTemp1+ HeaterTemp2+ HeaterTemp3)/4; //控制現在溫度值 ; //加熱器現在量測到溫度 Temperature   // 溫度上升或是下降 檢測 TempUpDwCount++; //溫度上升或是下降 檢測時間 計數器 1秒檢測一次 if (TempUpDwCount>3) { if (( PID1.NowTemp > HeaterAverage1 - 30 ) && ( PID1.NowTemp < HeaterAverage1+ 30 ) &&  ( PID1.NowTemp> HeaterAverage2 - 30 ) && ( PID1.NowTemp < HeaterAverage2 + 30 )) TempUpDw=0; //溫度沒變化 if (( PID1.NowTemp < HeaterAverage1 ) && ( PID1.NowTemp < HeaterAverage2 - 25 )) TempUpDw=1 ; //溫度下降中 if (( PID1.NowTemp > HeaterAverage2 ) && ( PID1.NowTemp > HeaterAverage2 + 25 )) TempUpDw=2 ;  //溫度上升 HeaterAverage4 = HeaterAverage3; //加熱器量測到溫度 平均值 4 HeaterAverage3 = HeaterAverage2; //加熱器量測到溫度 平均值 3 HeaterAverage2 = HeaterAverage1; //加熱器量測到溫度 平均值 2 HeaterAverage1 = PID1.NowValue; //加熱器量測到溫度 平均值 1 TempUpDwCount=0; //加熱器 溫度上升或是下降 檢測時間 計數器 1秒檢測一次 }
if((PCR_Status==2||Man_HeaterFg==1)&&(MAX31855_14.Thermocouple<ID1.TargetTemp+1000)&&(MAX31855_16.Thermocouple<ID1.TargetTemp+1000)) //加熱器 溫度控制運轉條件檢查 { // 加熱器 溫度控制運轉條件檢查OK PID1.NowValue=PID1.NowTemp; //控制現在溫度值 PID1.TargetValue=PID1.TargetTemp; //控制目標溫度值 if (PID1.NowTemp < PID1.TargetTemp - 1000) PID1.PWMResult=1000; //(0~10000) 溫度過低 PID運算範圍外 , PWM 輸出量 暫存值   //加熱器開始溫度輸出量 else if (PID1.NowTemp<ID1.TargetTemp - 500) PID1.PWMResult= HeaterRate2*10; //(0~10000) 溫度過低 PID運算範圍外 , PWM 輸出量 暫存值   //加熱器開始溫度輸出量 else if (PID1.NowTemp>ID1.TargetTemp + 300) PID1.PWMResult=0; //溫度過高 PID運算範圍外 , PWM 輸出量 暫存值 else  { PID1_Calculate();     //位置PID计算 PID1.PWMResult=(PID1.OutputValue*HeaterRate2)/100/100; //溫度上升中; PID 運算 (0~100000/0~1000)=100 //PID 運算範圍內 輸出值 // PID運算範圍內 } PID1.PWMOut=(PID1.PWMResult*HeaterRate)/100; //加熱器 溫度控制運轉條件檢查OK; PWM 輸出量 實際輸出值 // } else PID1.PWMOut=0; //加熱器 溫度控制運轉條件不合;關閉加熱器溫度 PWM=0  , TIM4_CH1 PB6 PWM1  WM1.OutValue Rate = 0~10000 TIM_SetCompare1(TIM4,PID1.PWMOut); //輸出到 PWM1占空比 /TIM4_CH1 PB6 PWM1  WM1.OutValue Rate = 0~10000 }


/*====================================================================================================/  ID1计算部分 =====================================================================================================*/ /* 位置型PID算法: E(K)=R(K)-M(K)         ;本次誤差值=本次設定值-本次量測值 Pp(K)=Kp*E(K)          ;本次比例輸出值 =比例增益係數×本次誤差值 Pi(K)=Ki*E(K)+Pi(K-1)  ;本次積分輸出值=積分增益係數 ×本次誤差值+上次積分輸出值 (累積溫度誤差總和值, SumErro) Pd(K)=Kd[E(K)-E(K-1)]  ;本次微分輸出值=微分增益係數×(本次誤差值-上次誤差值) P(K)=Pp(K)+Pi(K)+Pd(K) ID輸出值 = 本次比例輸出值+本次積分輸出值+本次微分輸出 */
void PID1_Calculate(void) //位置PID计算 { HeaterI_Count++; //加熱器 積分時間 計數器 HeaterD_Count++; //加熱器 微分時間 計數器
/*===PID1誤差總和值預設值===*/ if (( HeaterSumErrFg==0 ) && ( PID1.NowTemp > PID1.TargetTemp -400 ) && ( PID1.NowTemp < PID1.TargetTemp+100 ) &&  ( TempUpDw !=2 )) { PID1.SumError = HeaterSumErr; //加熱器 PID 控制參數 : 累積溫度誤差總和值預設值 HeaterSumErrFg=1; // 累積溫度誤差總和值預設值旗標  } /*===PID1比例項 計算式===*/ PID1.Error0 = PID1.TargetValue-PID1.NowValue ; //目前誤差值 = 目前溫度控制設定值 - 現在溫度感測值 ;目前誤差值 本次误差=本次设定值-本次测量值 PID1.KpValue = PID1.Kp*PID1.Error0; //比例項  本次比例输出=比例系数×本次误差值  pError=Error-pp->LastError;
/*===PID1 積分項 計算式===*/ if (HeaterI_Count>HeaterI_Set) //檢查積分時間是否到達 {   if ( PID1.NowTemp < PID1.TargetTemp - 25 ) //溫度過低時,少量增加 { if ( TempUpDw == 0 ) PID1.SumError=PID1.SumError+20; //累積誤差總合值   if ( TempUpDw == 1 ) PID1.SumError+= PID1.Error0; //累積誤差總合值   本次积分输出=积分系数×本次误差值+上次积分输出值   } if ( PID1.NowTemp > PID1.TargetTemp +25 ) // 溫度過高 { if ( TempUpDw == 0 ) PID1.SumError=PID1.SumError-20; // 溫度過高時,少量減少 if ( TempUpDw == 2 ) PID1.SumError+= PID1.Error0; //累積誤差總合值   本次积分输出=积分系数×本次误差值+上次积分输出值   } if (PID1.SumError>5000) PID1.SumError=5000; //累積誤差總和 最大值 HeaterSumMax ; SumError=10000/100=100次  if (PID1.SumError<-1000) PID1.SumError=-1000; //累積誤差總合最小值 PID1.KiValue = PID1.Ki*PID1.SumError;  //積分項  本次积分输出=积分系数×本次误差值+上次积分输出值 E(t)  //pp->SumError += Error HeaterI_Count=0; //積分時間 }
/*===PID1 微分項 計算式===*/  if(HeaterD_Count>HeaterD_Set) //檢查微分時間是否到達  { PID1.KdValue = PID1.Kd*(PID1.Error0-PID1.Error1); //微分項  本次微分输出=微分系数×(本次误差值-上次误差值)dError = pp->LastError - pp->revError PID1.Error1 = PID1.Error0;//保存上1次誤差; PID1 誤差值儲存 HeaterD_Count=0; //微分時間 }
/*===PID1 輸出值 ===*/  PID1.ResultValue = PID1.KpValue + PID1.KiValue + PID1.KdValue ; //Kp+Ki+Kd 運算結果暫存值 if ( TempUpDw == 1 ) PID1.OutputValue=PID1.ResultValue + PID1.Keep*1000;    //如果溫度下降時, 立即給予基本加熱溫控 else PID1.OutputValue=PID1.ResultValue; if (PID1.OutputValue >100000) PID1.OutputValue = 100000; //PWM 實際輸出最大值限幅 if ( PID1.OutputValue < 0 ) PID1.OutputValue = 0; //PWM 實際輸出最最小值限幅 if (( PID1.NowTemp > PID1.TargetTemp + 75 ) &&  ( TempUpDw == 2 )) PID1.OutputValue=0; //溫度過高 0.75 度 ; 且溫度還在上升中, 停止加熱器 PID 運算後 輸出值 if ( PID1.NowTemp > PID1.TargetTemp + 200 )  PID1.OutputValue=0; //溫度過高 2 度 ;停止加熱器 PID 運算後 輸出值 }


友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
48条回答
hmhuang98
2019-07-23 00:44
问题一
备注是:本次积分输出 = 积分系数 x 本次误差值 + 上次积分输出值
而程序却是:PID5.SumError += PID5.Error0;           if(PID5.SumError>2000) PID5.SumError=2000;           if(PID5.SumError<-200) PID5.SumError=-200;           PID5.KiValue = PID5.Ki*PID5.SumError;(直接用累计误差值乘以积分系数,跟备注的公式不同问题二
在程序中,只见PID5.SumError 加上PID5.Error0,没有减法或者清零,那么该数值不是一直往上累加,直到最后超过2000(被程序限制为2000),那该数值不就一直为2000? 

以上两点是小弟读了您的程序产生的疑问,希望楼主解答,谢谢!!!!!



问题一
PID5.Error0 = PID5.NowValue-PID5.TargetValue ; //冷卻風扇 現在溫度- 設定溫度 = 目前誤差值(溫度過高才須要降溫,和加熱器剛好相反)
PID1.Error0 = PID1.TargetValue-PID1.NowValue ; // 加熱器 目前誤差值 本次误差=本次设定值-本次测量值 PID5.SumError += PID5.Error0; //上次累積誤差總合值  + 本次误差
那 PID5.SumError 還不是累積誤差總合值  
本次积分输出 = 积分系数 x 本次误差值 + 上次积分输出值 (別人打的註解直接貼)
白話一點 : 本次积分输出 =积分系数 x SumError (誤差總合) 誤差總合的積分

PID1  是控制加熱器  ID 參數設定 要求比較顏嚴謹 
PID2~PID5 是控制冷卻風扇 , 只用到   比例控制就很足夠  , I 和 D 是有點多餘


问题二
一直为2000? 不會 如果溫度到達後 誤差值會轉為負誤差值, +2000 會被加上負誤差值減回去

PID 公式 應只是作個參考吧 ,

應是實際控制需求做小修改會比較適合

楼主  做电子行业  好多年了吧 
是自動控制 屬於電機方面




一周热门 更多>