| 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 運算後 輸出值 } 
 
 
 |