热度 4
PID是比例,积分,微分的缩写. 比例调节作用:是按比例反应系统的偏差,系统一旦出现了偏差,比例调节立即产生调节作用用以减少偏差。比例作用大,可以加快调节,减少误差,但是过大的比例,使系统的稳定性下降,甚至造成系统的不稳定。积分调节作用:是使系统消除稳态误差,提高无差度。因为有误差,积分调节就进行,直至无差,积分调节停止,积分调节输出一常值。积分作用的强弱取决与积分时间常数Ti,Ti越小,积分作用就越强。反之Ti大则积分作用弱,加入积分调节可使系统稳定性下降,动态响应变慢。积分作用常与另两种调节规律结合,组成PI调节器或PID调节器。微分调节作用:微分作用反映系统偏差信号的变化率,具有预见性,能预见偏差变化的趋势,因此能产生超前的控制作用,在偏差还没有形成之前,已被微分调节作用消除。因此,可以改善系统的动态性能。在微分时间选择合适情况下,可以减少超调,减少调节时间。微分作用对噪声干扰有放大作用,因此过强的加微分调节,对系统抗干扰不利。此外,微分反应的是变化率,而当输入没有变化时,微分作用输出为零。微分作用不能单独使用,需要与另外两种调节规律相结合,组成PD或PID控制器。
百度一搜最多还是理论上的说说,具体的PID控制我还不怎么明白的过来.总感觉PID用起来不难,真正和理论相结合解释的时候我很糊涂,看来多下点功夫研究PID.
下面我应一朋友的要求制作的PID温控系统,温度采用数码管显示.开机用按键设置好温度后才可以进行PID控制.
实物如下:
用到的材料有STC89C52 可泡水的DS18B20 4位共阳数码管 按键4个
原理图:
PCB图:
程序如下:
/***********************************************************************
PID温度控制程序
程序说明:
系统上电后显示 “--温度”
表示需要先设定温度才开始进行温度检测
温度设定完毕后程序才开始进行PID温控
***********************************************************************/
#include
#include
#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 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 #include #include 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 限于篇幅 程序比较长还是分模块的,如需要的朋友留下Email 我看到了会发给你的!