PID是比例,积分,微分的缩写. 比例调节作用:是按比例反应系统的偏差,系统一旦出现了偏差,比例调节立即产生调节作用用以减少偏差。比例作用大,可以加快调节,减少误差,但是过大的比例,使系统的稳定性下降,甚至造成系统的不稳定。积分调节作用:是使系统消除稳态误差,提高无差度。因为有误差,积分调节就进行,直至无差,积分调节停止,积分调节输出一常值。积分作用的强弱取决与积分时间常数Ti,Ti越小,积分作用就越强。反之Ti大则积分作用弱,加入积分调节可使系统稳定性下降,动态响应变慢。积分作用常与另两种调节规律结合,组成PI调节器或PID调节器。微分调节作用:微分作用反映系统偏差信号的变化率,具有预见性,能预见偏差变化的趋势,因此能产生超前的控制作用,在偏差还没有形成之前,已被微分调节作用消除。因此,可以改善系统的动态性能。在微分时间选择合适情况下,可以减少超调,减少调节时间。微分作用对噪声干扰有放大作用,因此过强的加微分调节,对系统抗干扰不利。此外,微分反应的是变化率,而当输入没有变化时,微分作用输出为零。微分作用不能单独使用,需要与另外两种调节规律相结合,组成PD或PID控制器。
程序如下: - /***********************************************************************
- PID温度控制程序
- 程序说明:
- 系统上电后显示 “--温度”
- 表示需要先设定温度才开始进行温度检测
- 温度设定完毕后程序才开始进行PID温控
- ***********************************************************************/
- #include <reg52.h>
- #include <absacc.h>
- #include"DS18B20.H"
- #include"PID.H"
- #define uchar unsigned char
- #define uint unsigned int
- unsigned char code tab[]=
- {
- 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xBF
- }
- ;
- /*个位0~9的数码管段码*/
- unsigned char code sao[]=
- {
- 0x7f,0xbf,0xdf,0xef
- }
- ;
- //扫描码
- uchar set=30,keyflag=1 ; //set初始化为30° keyflag为进入温度设定的标志位
- //4个按键使用说明
- sbit key_out=P1^0 ; //用于温度设定后的退出
- sbit key_up=P1^1 ; //设定温度加
- sbit key_down=P1^2 ; //设定温度减
- sbit key_in=P1^3 ; //在程序的运行中如需要重新设定温度 按下此键才能进入设置模式并且此时是停在温度控制的,按下key_out键后才表示设定完毕
- void Show_key();
- /***********************************************************/
- void delays(unsigned char k)
- {
- unsigned char i,j ;
- for(i=0;i<k;i++)
- for(j=0;j<50;j++);
- }
- /*********************************************************
- //数码管显示函数
- P0口 作为数据口
- P2口的低四位作为扫描口
- 变量 x表示扫描
- d表示是否要加小数点 为1是 为0不加
- y表示传递的数值
- *********************************************************/
- LCD_disp_char(uchar x,bit d,uchar y)
- {
- P2=0XFF ;
- P0=0xFF ;
- if(d==0)
- P0=tab[y];
- else
- P0=tab[y]&0x7f ; //与上0x7f表示是否要加小数点
- P2=sao[x]; //打开扫描端号
-
- }
- /*********************************************************
- 按键扫描
- *********************************************************/
- void keyscan(void)
- {
- if(key_in==0) //按键进入函数
- {
- delays(10); //延时消抖 (以下同)
- if(key_in==0)
- {
- while(key_in==0)
- {
- Show_key(); //如果一直按着键不放 就一直显示在当前状态 (以下同)
- }
- keyflag=1 ; //按键标志位
- }
- }
- /***********************/
- if(key_out==0) //按键退出
- {
- delays(10);
- if(key_out==0)
- {
- while(key_out==0)
- {
- Show_key();
- }
- keyflag=0 ;
- set_temper=set ;
- }
- }
- /*************************/
- if(key_up==0) //设定温度的加
- {
- delays(10);
- if(key_up==0)
- {
- while(key_up==0)
- {
- Show_key();
- }
- if(keyflag==1)
- {
- set++;
- if(set>90) //如果大于90°就不在加
- set=90 ;
- }
- }
- }
- /*************************/
- if(key_down==0) //温度设定的减
- {
- delays(10);
- if(key_down==0)
- {
- while(key_down==0)
- {
- Show_key();
- }
- if(keyflag==1)
- {
- set--;
- if(set<30) //温度减到30°时不在往下减
- set=30 ;
- }
- }
- }
- }
- /*********************************************************************
- 按键按下时的显示函数
- ***********************************************************************/
- void Show_key()
- {
- output=1 ;
- LCD_disp_char(3,0,10); //显示 -
- delays(3);
- LCD_disp_char(2,0,10); //显示- (表示温度设定 )
- delays(3);
- LCD_disp_char(1,0,set/10); //显示温度十位
- delays(3);
- LCD_disp_char(0,0,set%10); //显示温度个位
- delays(3);
- }
- /*****************************************************************/
- void main()
- {
- unsigned int tmp ;//声明温度中间变量
- unsigned char counter=0 ;
- PIDBEGIN(); //PID参数的初始化
- output=1 ; //关闭继电器输出
- while(1)
- {
- keyscan();
- if(keyflag)
- {
- Show_key(); //显示温度设定
- }
- else
- {
- if(counter--==0)
- {
- tmp=ReadTemperature();//每隔一段时间读取温度值
- counter=20 ;
- }
- LCD_disp_char(3,0,tmp/1000); //显示温度十位
- delays(3);
- LCD_disp_char(2,1,tmp/100%10); //显示温度个位
- //显示小数点
- delays(3);
- LCD_disp_char(1,0,tmp/10%10); //显示温度小数后一位
- delays(3);
- LCD_disp_char(0,0,tmp%10);//显示温度小数后二位
- delays(3);
- P2=0XFF ;
- P0=0xff ;
- compare_temper(); //比较温度
-
-
- }
- }
- }
- /**********************************************************************************************************************************************/
- //PID算法温控C语言2008-08-17 18:58
- #ifndef _PID_H__
- #define _PID_H__
- #include<intrins.h>
- #include<math.h>
- #include<string.h>
- struct PID
- {
- unsigned int SetPoint ;
- // 设定目标 Desired Value
- unsigned int Proportion ;
- // 比例常数 Proportional Const
- unsigned int Integral ;
- // 积分常数 Integral Const
- unsigned int Derivative ;
- // 微分常数 Derivative Const
- unsigned int LastError ;
- // Error[-1]
- unsigned int PrevError ;
- // Error[-2]
- unsigned int SumError ;
- // Sums of Errors
- }
- ;
- struct PID spid ;
- // PID Control Structure
- unsigned int rout ;
- // PID Response (Output)
- unsigned int rin ;
- // PID Feedback (Input)
- sbit output=P1^4;
- unsigned char high_time,low_time,count=0 ;
- //占空比调节参数
- unsigned char set_temper ;
- void PIDInit(struct PID*pp)
- {
- memset(pp,0,sizeof(struct PID)); //PID参数初始化全部设置为0
- }
- unsigned int PIDCalc(struct PID*pp,unsigned int NextPoint)
- {
- unsigned int dError,Error ;
- Error=pp->SetPoint-NextPoint ;
- // 偏差
- pp->SumError+=Error ;
- // 积分
- dError=pp->LastError-pp->PrevError ;
- // 当前微分
- pp->PrevError=pp->LastError ;
- pp->LastError=Error ;
- //比例
- //积分项
- return(pp->Proportion*Error+pp->Integral*pp->SumError+pp->Derivative*dError);
- // 微分项
- }
- /***********************************************************
- 温度比较处理子程序
- ***********************************************************/
- void compare_temper()
- {
- unsigned char i ;
- //EA=0;
- if(set_temper>temper)
- {
- if(set_temper-temper>1)
- {
- high_time=100 ; //大于1°不进行PID运算
- low_time=0 ;
- }
- else
- { //在1°范围内进行PID运算
- for(i=0;i<10;i++)
- {
- //get_temper();
- rin=s;
- // Read Input
- rout=PIDCalc(&spid,rin); //执行PID运算
- // Perform PID Interation
- }
- if(high_time<=100) //限制最大值
- high_time=(unsigned char)(rout/800);
- else
- high_time=100;
- low_time=(100-high_time);
- }
- }
- /****************************************/
- else if(set_temper<=temper) //当实际温度大于设置温度时
- {
- if(temper-set_temper>0)//如果实际温度大于设定温度
- {
- high_time=0 ;
- low_time=100 ;
- }
- else
- {
- for(i=0;i<10;i++)
- {
- //get_temper();
- rin=s ;
- // Read Input
- rout=PIDCalc(&spid,rin);
- // Perform PID Interation
- }
- if(high_time<100) //此变量是无符号字符型
- high_time=(unsigned char)(rout/10000);
- else
- high_time=0 ;//限制不输出负值
- low_time=(100-high_time);
- //EA=1;
- }
- }
- }
- /*****************************************************
- T0中断服务子程序,用于控制电平的翻转 ,40us*100=4ms周期
- ******************************************************/
- void serve_T0()interrupt 1 using 1
- {
- if(++count<=(high_time))
- output=0 ;
- else if(count<=100)
- {
- output=1 ;
- }
- else
- count=0 ;
- TH0=0x2f ;
- TL0=0xe0 ;
- }
- void PIDBEGIN()
- {
-
- TMOD=0x01 ;
- TH0=0x2f ;
- TL0=0x40 ;
-
- EA=1 ;
- ET0=1 ;
- TR0=1 ;
-
- high_time=50 ;
- low_time=50 ;
- PIDInit(&spid);
- // Initialize Structure
- spid.Proportion=10 ;
- // Set PID Coefficients
- spid.Integral=8 ;
- spid.Derivative=6 ;
- spid.SetPoint=100 ;
- // Set PID Setpoint
-
- }
- #endif
复制代码
|