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

时间: 2024-10-13 17:27:40

增量式 PID 控制算法 温度控制实例的相关文章

增量式PID的stm32实现(转)

源:增量式PID的stm32实现,整定过程 首先说说增量式PID的公式,这个关系到MCU算法公式的书写,实际上两个公式的写法是同一个公式变换来得,不同的是系数的差异. 资料上比较多的是: 还有一种是: 感觉第二种的Kp Ki Kd比较清楚,更好理解,下面介绍的就以第二种来吧.(比例.积分.微分三个环节的作用这里就详细展开,百度会有很多) 硬件部分: 控制系统的控制对象是4个空心杯直流电机,电机带光电编码器,可以反馈转速大小的波形.电机驱动模块是普通的L298N模块. 芯片型号,STM32F103

Vivado增量式编译

Vivado 中的增量设计会重新利用已有的布局布线数据来缩短运行时间,并生成可预测的结果.当设计有 95% 以上的相似度时,增量布局布线的运行时间会比一般布局布线平均缩短2倍.若相似度低于80%,则使用增量布局布线只有很小的优势或者基本没有优势. 当设计进行到后期,每次运行改动很小,在开始后端实现前读入的设计网表具有较高相似度的情况下,推荐使用 Vivado 的增量布局布线功能.运行增量流程的前提是有一个已经完成布局布线的参考设计检查点(Design Checkpoint, DCP)文件,并以此

增量式编码器专题

编码器简介 编码器(encoder)把角位移或直线位移转换成电信号,前者称为码盘,后者称为码尺. 按照工作原理编码器可分为增量式和绝对式两类: ①增量式编码器: 将位移转换成周期性的电信号,再把这个电信号转变成计数脉冲,用脉冲的个数表示位移的大小.通常为A相.B相.Z相输出,A相.B相为相互延迟1/4周期的脉冲输出,根据延迟关系可以区别正反转,而且通过取A相.B相的上升和下降沿可以进行2或4倍频:Z相为单圈脉冲,即每圈发出一个脉冲. ②绝对式编码器: 每一个位置对应一个确定的数字码,因此它的示值

利用stm32自带的正交编码器检测增量式编码器流程总结

由于手术的工频升级机需要自动平层功能,于是着手开始做这方面的工作.硬件选择的是增量式编码器,100脉冲每转,后来了解到stm32的每个定时器的通道1和通道2内置了正交编码器模块,可以直接使用.之前的公司工程师都是用定时器捕捉脉冲,然后自行处理的,我看了下代码挺麻烦的,现在用了stm32自带的感觉就容易多了.找了官方的软件说明,看了下网上已有的例子,一个下午就基本在我的系统架构中添加了这个设备,然后对这个设备初始化,设置上层接口API.最后看些例子将16位计数器软件扩展到32位.就顺利的完成了基本

利用Hbase的coprocessor实现增量式Apriori算法

Apriori在数据挖掘中是经典的频繁项集挖掘算法,其主要思想就是如果某个项集不频繁,则任何包含此项集的项集一定不频繁.而今天要实现的增量式的Apriori算法,有点像分布式的Apriori,因为我们可以把已挖掘的事务集和新增的事务集看作两个互相独立的数据集,挖掘新增的事务集,获取所有新增频繁集,然后与已有的频繁集做并集,对于两边都同时频繁的项集肯定全局频繁,而只有一边频繁的项集则需要统计其在两边的频繁计数,这样完成后就能获得所有的全局频繁集,并不需要重新挖掘已有的事务集,效率必然提高. 至于H

增量式强化学习

线性逼近: 相比较于非线性逼近,线性逼近的好处是只有一个最优值,因此可以收敛到全局最优.其中为状态s处的特征函数,或者称为基函数. 常用的基函数的类型为: 增量式方法参数更新过程随机性比较大,尽管计算简单,但样本数据的利用效率并不高.而批的方法,尽管计算复杂,但计算效率高. 批处理方法: 深度强化学习: Q-learning方法是异策略时序差分方法.其伪代码为: 离策略:是指行动策略(产生数据的策略)和要评估的策略不是一个策略.在图Q-learning 伪代码中,行动策略(产生数据的策略)是第5

增量式爬虫

目录 增量式爬虫 增量式爬虫 案例: 爬取4567tv网站中所有的电影详情数据 需求:爬取糗事百科中的段子和作者数据. 增量式爬虫 当我们在浏览相关网页的时候会发现,某些网站定时会在原有网页数据的基础上更新一批数据,例如某电影网站会实时更新一批最近热门的电影.小说网站会根据作者创作的进度实时更新最新的章节数据等等.那么,类似的情景,当我们在爬虫的过程中遇到时,我们是不是需要定时更新程序以便能爬取到网站中最近更新的数据呢? 增量式爬虫 概念:通过爬虫程序监测某网站数据更新的情况,以便可以爬取到该网

增量式爬虫案列

增量式爬虫 引言: 当我们在浏览相关网页的时候会发现,某些网站定时会在原有网页数据的基础上更新一批数据,例如某电影网站会实时更新一批最近热门的电影.小说网站会根据作者创作的进度实时更新最新的章节数据等等.那么,类似的情景,当我们在爬虫的过程中遇到时,我们是不是需要定时更新程序以便能爬取到网站中最近更新的数据呢? 一.增量式爬虫 概念:通过爬虫程序监测某网站数据更新的情况,以便可以爬取到该网站更新出的新数据. 如何进行增量式的爬取工作: 在发送请求之前判断这个URL是不是之前爬取过 在解析内容后判

爬虫篇 ---增量式爬虫

What is 增量式爬虫? 用来 监测 网站数据更新的情况,只会爬取网站中更新出来的新数据 增量式爬虫的核心 去重,因为你爬取到的数据是不可以出现重复的 怎么进行增量式爬取呢? 在发送请求之前判断这个URL是不是之前爬取过 在解析内容后判断这部分内容是不是之前爬取过 写入存储到 redis 时判断内容是不是已经在介质中存在 #总结分析 对比三种方式增量爬取的核心是去重, 至于去重的操作在哪个步骤起作用,只能说各有利弊.在我看来,前两种思路需要根据实际情况取一个(也可能都用). #第一种思路适合