增量式 PID 控制算法 温度控制实例 - cvi670

时间:2024-03-05 12:00:04

增量式 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倍?