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 運算後 輸出值
}
备注是:本次积分输出 = 积分系数 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 公式 應只是作個參考吧 ,
應是實際控制需求做小修改會比較適合
楼主 做电子行业 好多年了吧
是自動控制 屬於電機方面
一周热门 更多>