增量式 PID 控制算法 溫度控制實例


  1 #include<reg51.h> 
  2 #include<intrins.h> 
  3 #include<math.h> 
  4 #include<string.h> 
  5 struct PID { 
  6           unsigned int SetPoint; // 設定目標 Desired Value 
  7           unsigned int Proportion; // 比例常數 Proportional Const 
  8           unsigned int Integral; // 積分常數 Integral Const 
  9           unsigned int Derivative; // 微分常數 Derivative Const 
 10           unsigned int LastError; // Error[-1] 
 11           unsigned int PrevError; // Error[-2] 
 12           unsigned int SumError; // Sums of Errors 
 13           }; 
 14 struct PID spid; // PID Control Structure 
 15 unsigned int rout; // PID Response (Output) 
 16 unsigned int rin; // PID Feedback (Input) 
 17 sbit data1=P1^0; 
 18 sbit clk=P1^1; 
 19 sbit plus=P2^0; 
 20 sbit subs=P2^1; 
 21 sbit stop=P2^2; 
 22 sbit output=P3^4; 
 23 sbit DQ=P3^3; 
 24 unsigned char flag,flag_1=0; 
 25 unsigned char high_time,low_time,count=0;//占空比調節參數 
 26 unsigned char set_temper=35; 
 27 unsigned char temper; 
 28 unsigned char i; 
 29 unsigned char j=0; 
 30 unsigned int s; 
 31 /*********************************************************** 
 32         延時子程序,延時時間以12M晶振為准,延時時間為30us×time 
 33 ***********************************************************/ 
 34 void delay(unsigned char time) 
 35  { 
 36             unsigned char m,n; 
 37             for(n=0;n<time;n++) 
 38             for(m=0;m<2;m++){} 
 39  } 
 40 /*********************************************************** 
 41         寫一位數據子程序 
 42 ***********************************************************/ 
 43 void write_bit(unsigned char bitval) 
 44 { 
 45           EA=0; 
 46           DQ=0; /*拉低DQ以開始一個寫時序*/ 
 47         if(bitval==1) 
 48         { 
 49           _nop_(); 
 50           DQ=1; /*如要寫1,則將總線置高*/ 
 51         } 
 52          delay(5); /*延時90us供DA18B20采樣*/ 
 53          DQ=1; /*釋放DQ總線*/ 
 54         _nop_(); 
 55         _nop_(); 
 56         EA=1; 
 57 } 
 58  /*********************************************************** 
 59         寫一字節數據子程序 
 60  ***********************************************************/ 
 61 void write_byte(unsigned char val) 
 62 { 
 63             unsigned char i; 
 64             unsigned char temp; 
 65             EA=0; 
 66             TR0=0; 
 67         for(i=0;i<8;i++) /*寫一字節數據,一次寫一位*/ 
 68         { 
 69           temp=val>>i; /*移位操作,將本次要寫的位移到最低位*/ 
 70           temp=temp&1; 
 71           write_bit(temp); /*向總線寫該位*/ 
 72         } 
 73           delay(7); /*延時120us后*/ 
 74         // TR0=1; 
 75           EA=1; 
 76 } 
 77/*********************************************************** 
 78         讀一位數據子程序 
 79 ***********************************************************/ 
 80 unsigned char read_bit() 
 81 { 
 82         unsigned char i,value_bit; 
 83         EA=0; 
 84         DQ=0; /*拉低DQ,開始讀時序*/ 
 85         _nop_(); 
 86         _nop_(); 
 87         DQ=1; /*釋放總線*/ 
 88         for(i=0;i<2;i++){} 
 89         value_bit=DQ; 
 90         EA=1; 
 91         return(value_bit); 
 92 } 
 93 /*********************************************************** 
 94         讀一字節數據子程序 
 95  ***********************************************************/ 
 96 unsigned char read_byte() 
 97 { 
 98         unsigned char i,value=0; 
 99         EA=0; 
100         for(i=0;i<8;i++) 
101         { 
102           if(read_bit()) /*讀一字節數據,一個時序中讀一次,並作移位處理*/ 
103           value|=0x01<<i; 
104           delay(4); /*延時80us以完成此次都時序,之后再讀下一數據*/ 
105         } 
106         EA=1; 
107         return(value); 
108 } 
109  /*********************************************************** 
110         復位子程序 
111  ***********************************************************/ 
112 unsigned char reset() 
113 { 
114         unsigned char presence; 
115         EA=0; 
116         DQ=0; /*拉低DQ總線開始復位*/ 
117         delay(30); /*保持低電平480us*/ 
118         DQ=1; /*釋放總線*/ 
119         delay(3); 
120         presence=DQ; /*獲取應答信號*/ 
121         delay(28); /*延時以完成整個時序*/ 
122         EA=1; 
123         return(presence); /*返回應答信號,有芯片應答返回0,無芯片則返回1*/ 
124 } 
125 /*********************************************************** 
126         獲取溫度子程序 
127 ***********************************************************/ 
128 void get_temper() 
129 { 
130           unsigned char i,j; 
131           do 
132           { 
133              i=reset(); /*復位*/ 
134           }  while(i!=0); /*1為無反饋信號*/ 
135             i=0xcc; /*發送設備定位命令*/ 
136            write_byte(i); 
137            i=0x44; /*發送開始轉換命令*/ 
138            write_byte(i); 
139            delay(180); /*延時*/ 
140           do 
141           { 
142              i=reset(); /*復位*/ 
143           }  while(i!=0); 
144            i=0xcc; /*設備定位*/ 
145            write_byte(i); 
146            i=0xbe; /*讀出緩沖區內容*/ 
147            write_byte(i); 
148            j=read_byte();   
149            i=read_byte(); 
150            i=(i<<4)&0x7f; 
151            s=(unsigned int)(j&0x0f);            //得到小數部分
152            s=(s*100)/16; 
153            j=j>>4; 
154            temper=i|j; /*獲取的溫度放在temper中*/ 
155         } 
156 /*==================================================================================================== 
157         Initialize PID Structure 
158 =====================================================================================================*/ 
159 void PIDInit (struct PID *pp) 
160 { 
161         memset ( pp,0,sizeof(struct PID));           //全部初始化為0
162 } 
163 /*==================================================================================================== 
164         PID計算部分 
165 =====================================================================================================*/ 
166 unsigned int PIDCalc( struct PID *pp, unsigned int NextPoint ) 
167 { 
168         unsigned int dError,Error; 
169         Error = pp->SetPoint - NextPoint;          // 偏差           
170         pp->SumError += Error;                     // 積分                                   
171         dError = pp->LastError - pp->PrevError;    // 當前微分  
172         pp->PrevError = pp->LastError;                           
173         pp->LastError = Error;                                         
174         return (pp->Proportion * Error             // 比例項           
175         + pp->Integral * pp->SumError              // 積分項 
176         + pp->Derivative * dError);                // 微分項 
177 } 
178/*********************************************************** 
179         溫度比較處理子程序 
180***********************************************************/ 
181 void compare_temper() 
182 { 
183         unsigned char i; 
184         if(set_temper>temper)      //是否設置的溫度大於實際溫度
185         { 
186            if(set_temper-temper>1)         //設置的溫度比實際的溫度是否是大於1度
187           { 
188              high_time=100;                     //如果是,則全速加熱
189              low_time=0; 
190           } 
191          else                                         //如果是在1度范圍內,則運行PID計算
192           { 
193              for(i=0;i<10;i++) 
194             { 
195               get_temper();                          //獲取溫度
196               rin = s; // Read Input 
197               rout = PIDCalc ( &spid,rin ); // Perform PID Interation 
198             } 
199             if (high_time<=100) 
200               high_time=(unsigned char)(rout/800); 
201             else 
202             high_time=100; 
203               low_time= (100-high_time); 
204           } 
205         } 
206         else if(set_temper<=temper) 
207         { 
208            if(temper-set_temper>0) 
209           { 
210             high_time=0; 
211             low_time=100; 
212           } 
213            else 
214           { 
215              for(i=0;i<10;i++) 
216             {
217              get_temper(); 
218              rin = s; // Read Input 
219                rout = PIDCalc ( &spid,rin ); // Perform PID Interation 
220             } 
221              if (high_time<100) 
222                 high_time=(unsigned char)(rout/10000); 
223              else 
224                 high_time=0; 
225                 low_time= (100-high_time); 
226           } 
227         } 
228         // else 
229         // {} 
230 } 
231 /***************************************************** 
232         T0中斷服務子程序,用於控制電平的翻轉 ,40us*100=4ms周期 
233 ******************************************************/ 
234 void serve_T0() interrupt 1 using 1 
235 { 
236         if(++count<=(high_time)) 
237           output=1; 
238         else if(count<=100) 
239         { 
240           output=0; 
241         } 
242         else 
243         count=0; 
244         TH0=0x2f; 
245         TL0=0xe0; 
246 } 
247 /***************************************************** 
248         串行口中斷服務程序,用於上位機通訊 
249 ******************************************************/ 
250 void serve_sio() interrupt 4 using 2 
251 { 
252         /* EA=0; 
253         RI=0; 
254         i=SBUF; 
255         if(i==2) 
256         { 
257           while(RI==0){} 
258           RI=0; 
259           set_temper=SBUF; 
260           SBUF=0x02; 
261           while(TI==0){} 
262           TI=0; 
263         } 
264         else if(i==3) 
265         { 
266           TI=0; 
267           SBUF=temper; 
268           while(TI==0){} 
269           TI=0; 
270         } 
271         EA=1; */ 
272 } 
273 void disp_1(unsigned char disp_num1[6]) 
274 { 
275         unsigned char n,a,m; 
276         for(n=0;n<6;n++) 
277         { 
278         // k=disp_num1[n]; 
279          for(a=0;a<8;a++) 
280          { 
281             clk=0; 
282             m=(disp_num1[n]&1); 
283             disp_num1[n]=disp_num1[n]>>1; 
284             if(m==1) 
285              data1=1; 
286             else 
287              data1=0; 
288             _nop_(); 
289             clk=1; 
290             _nop_(); 
291          }   
292         } 
293 } 
294/***************************************************** 
295         顯示子程序 
296         功能:將占空比溫度轉化為單個字符,顯示占空比和測得到的溫度 
297 ******************************************************/ 
298 void display() 
299 { 
300         unsigned char code number[]={0xfc,0x60,0xda,0xf2,0x66,0xb6,0xbe,0xe0,0xfe,0xf6}; 
301         unsigned char disp_num[6]; 
302         unsigned int k,k1; 
303         k=high_time; 
304         k=k%1000; 
305         k1=k/100; 
306         if(k1==0) 
307         disp_num[0]=0; 
308         else 
309         disp_num[0]=0x60; 
310         k=k%100; 
311         disp_num[1]=number[k/10]; 
312         disp_num[2]=number[k%10]; 
313         k=temper; 
314         k=k%100; 
315         disp_num[3]=number[k/10]; 
316         disp_num[4]=number[k%10]+1; 
317         disp_num[5]=number[s/10]; 
318         disp_1(disp_num); 
319 } 
320 /*********************************************************** 
321         主程序 
322 ***********************************************************/ 
323 void main() 
324 { 
325         unsigned char z;
326         unsigned char a,b,flag_2=1,count1=0; 
327         unsigned char phil[]={2,0xce,0x6e,0x60,0x1c,2};
328         TMOD=0x21; 
329         TH0=0x2f; 
330         TL0=0x40; 
331         SCON=0x50; 
332         PCON=0x00; 
333         TH1=0xfd; 
334         TL1=0xfd; 
335         PS=1; 
336         EA=1; 
337         EX1=0; 
338         ET0=1; 
339         ES=1; 
340         TR0=1; 
341         TR1=1; 
342         high_time=50; 
343         low_time=50; 
344         PIDInit ( &spid );    // Initialize Structure 
345         spid.Proportion = 10; // Set PID Coefficients  比例常數 Proportional Const 
346         spid.Integral = 8;    //積分常數 Integral Const 
347         spid.Derivative =6;   //微分常數 Derivative Const 
348         spid.SetPoint = 100; // Set PID Setpoint 設定目標 Desired Value 
349         while(1) 
350     { 
351           if(plus==0) 
352       {
353             EA=0; 
354             for(a=0;a<5;a++) 
355             for(b=0;b<102;b++){} 
356             if(plus==0) 
357           {
358               set_temper++; 
359               flag=0; 
360           }
361       } 
362           else if(subs==0) 
363        { 
364             for(a=0;a<5;a++) 
365             for(b=0;a<102;b++){} 
366             if(subs==0) 
367             { 
368                set_temper--; 
369                flag=0; 
370             } 
371        } 
372           else if(stop==0) 
373          { 
374               for(a=0;a<5;a++) 
375               for(b=0;b<102;b++){} 
376               if(stop==0) 
377              { 
378                flag=0; 
379                break; 
380              } 
381              EA=1; 
382         } 
383        get_temper(); 
384            b=temper; 
385         if(flag_2==1) 
386           a=b; 
387         if((abs(a-b))>5) 
388           temper=a; 
389         else 
390           temper=b; 
391           a=temper; 
392           flag_2=0; 
393         if(++count1>30) 
394         { 
395           display(); 
396           count1=0; 
397         } 
398           compare_temper(); 
399         } 
400            TR0=0; 
401            z=1; 
402         while(1) 
403         { 
404             EA=0; 
405         if(stop==0) 
406         { 
407             for(a=0;a<5;a++) 
408             for(b=0;b<102;b++){} 
409             if(stop==0) 
410             disp_1(phil); 
411         // break; 
412         } 
413         EA=1; 
414 } 
415 }

這個程序spid.SetPoint = 100;

 Set PID Setpoint 設定目標 Desired Value是什么意思,

上面的eet_temper=35;

難道這個spid.SetPoint = 100是指35-34=1度的溫差擴大100倍?


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM