C51单片机设计的水箱温度PID控制系统的程序,PID控制程序

发布时间:2023-02-08  

此系统是基于PID的单片机温度控制系统,我在网上搜到一段完整的程序,并按他的程序做出了相应的proteus硬件仿真,但

是并没有达到预期的效果.待提高。


程序如下:


#include<reg51.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 data1=P1^0; 

sbit clk=P1^1; 

sbit plus=P2^0; 

sbit subs=P2^1; 

sbit stop=P2^2; 

sbit output=P3^4; 

sbit DQ=P3^3; 

unsigned char flag,flag_1=0; 

unsigned char high_time,low_time,count=0;//占空比调节参数 

unsigned char set_temper=35; 

unsigned char temper; 

unsigned char i; 

unsigned char j=0; 

unsigned int s; 

/*********************************************************** 

延时子程序,延时时间以12M晶振为准,延时时间为30us×time 

***********************************************************/ 

void delay(unsigned char time) 

unsigned char m,n; 

for(n=0;n<time;n++) 

for(m=0;m<2;m++){} 

/*********************************************************** 

写一位数据子程序 

***********************************************************/ 

void write_bit(unsigned char bitval) 

EA=0; 

DQ=0; /*拉低DQ以开始一个写时序*/ 

if(bitval==1) 

  _nop_(); 

  DQ=1; /*如要写1,则将总线置高*/ 

delay(5); /*延时90us供DA18B20采样*/ 

DQ=1; /*释放DQ总线*/ 

_nop_(); 

_nop_(); 

EA=1; 

/*********************************************************** 

写一字节数据子程序 

***********************************************************/ 

void write_byte(unsigned char val) 

unsigned char i; 

unsigned char temp; 

EA=0; 

TR0=0; 

for(i=0;i<8;i++) /*写一字节数据,一次写一位*/ 

  temp=val>>i; /*移位操作,将本次要写的位移到最低位*/ 

  temp=temp&1; 

  write_bit(temp); /*向总线写该位*/ 

delay(7); /*延时120us后*/ 

// TR0=1; 

EA=1; 

/*********************************************************** 

读一位数据子程序 

***********************************************************/ 

unsigned char read_bit() 

unsigned char i,value_bit; 

EA=0; 

DQ=0; /*拉低DQ,开始读时序*/ 

_nop_(); 

_nop_(); 

DQ=1; /*释放总线*/ 

for(i=0;i<2;i++){} 

value_bit=DQ; 

EA=1; 

return(value_bit); 

/*********************************************************** 

读一字节数据子程序 

***********************************************************/ 

unsigned char read_byte() 

unsigned char i,value=0; 

EA=0; 

for(i=0;i<8;i++) 

  if(read_bit()) /*读一字节数据,一个时序中读一次,并作移位处理*/ 

  value|=0x01<<i; 

  delay(4); /*延时80us以完成此次都时序,之后再读下一数据*/ 

EA=1; 

return(value); 

/*********************************************************** 

复位子程序 

***********************************************************/ 

unsigned char reset() 

unsigned char presence; 

EA=0; 

DQ=0; /*拉低DQ总线开始复位*/ 

delay(30); /*保持低电平480us*/ 

DQ=1; /*释放总线*/ 

delay(3); 

presence=DQ; /*获取应答信号*/ 

delay(28); /*延时以完成整个时序*/ 

EA=1; 

return(presence); /*返回应答信号,有芯片应答返回0,无芯片则返回1*/ 

/*********************************************************** 

获取温度子程序 

***********************************************************/ 

void get_temper() 

unsigned char i,j; 

do 

  i=reset(); /*复位*/ 

}while(i!=0); /*1为无反馈信号*/ 

i=0xcc; /*发送设备定位命令*/ 

write_byte(i); 

i=0x44; /*发送开始转换命令*/ 

write_byte(i); 

delay(180); /*延时*/ 

do 

  i=reset(); /*复位*/ 

}while(i!=0); 

i=0xcc; /*设备定位*/ 

write_byte(i); 

i=0xbe; /*读出缓冲区内容*/ 

write_byte(i); 

j=read_byte(); 

i=read_byte(); 

i=(i<<4)&0x7f; 

s=(unsigned int)(j&0x0f); 

s=(s*100)/16; 

j=j>>4; 

temper=i|j; /*获取的温度放在temper中*/ 

/*==================================================================================================== 

Initialize PID Structure 

=====================================================================================================*/ 

void PIDInit (struct PID *pp) 

memset ( pp,0,sizeof(struct PID)); 

/*==================================================================================================== 

PID计算部分 

=====================================================================================================*/ 

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); // 微分项 

/*********************************************************** 

温度比较处理子程序 

***********************************************************/ 

compare_temper() 

unsigned char i; 

if(set_temper>temper) 

  if(set_temper-temper>1) 

  { 

   high_time=100; 

   low_time=0; 

  } 

  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/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); 

  } 

// else 

// {} 

/***************************************************** 

T0中断服务子程序,用于控制电平的翻转 ,40us*100=4ms周期 

******************************************************/ 

void serve_T0() interrupt 1 using 1 

if(++count<=(high_time)) 

output=1; 

else if(count<=100) 

  output=0; 

else 

count=0; 

TH0=0x2f; 

TL0=0xe0; 

/***************************************************** 

串行口中断服务程序,用于上位机通讯 

******************************************************/ 

void serve_sio() interrupt 4 using 2 

/* EA=0; 

RI=0; 

i=SBUF; 

if(i==2) 

while(RI==0){} 

RI=0; 

set_temper=SBUF; 

SBUF=0x02; 

while(TI==0){} 

TI=0; 

else if(i==3) 

TI=0; 

SBUF=temper; 

while(TI==0){} 

TI=0; 

EA=1; */ 

void disp_1(unsigned char disp_num1[6]) 

unsigned char n,a,m; 

for(n=0;n<6;n++) 

// k=disp_num1[n]; 

  for(a=0;a<8;a++) 

  { 

   clk=0; 

   m=(disp_num1[n]&1); 

   disp_num1[n]=disp_num1[n]>>1; 

   if(m==1) 

   data1=1; 

   else 

   data1=0; 

   _nop_(); 

   clk=1; 

   _nop_(); 

  } 

/***************************************************** 

显示子程序 

功能:将占空比温度转化为单个字符,显示占空比和测得到的温度 

******************************************************/ 

void display() 

unsigned char code number[]={0xfc,0x60,0xda,0xf2,0x66,0xb6,0xbe,0xe0,0xfe,0xf6}; 

unsigned char disp_num[6]; 

unsigned int k,k1; 

k=high_time; 

k=k%1000; 

k1=k/100; 

if(k1==0) 

disp_num[0]=0; 

else 

disp_num[0]=0x60; 

k=k%100; 

disp_num[1]=number[k/10]; 

disp_num[2]=number[k%10]; 

k=temper; 

k=k%100; 

disp_num[3]=number[k/10]; 

disp_num[4]=number[k%10]+1; 

disp_num[5]=number[s/10]; 

disp_1(disp_num); 

/*********************************************************** 

主程序 

***********************************************************/ 

main() 

unsigned char z; 

unsigned char a,b,flag_2=1,count1=0; 

unsigned char phil[]={2,0xce,0x6e,0x60,0x1c,2};; 

TMOD=0x21; 

TH0=0x2f; 

TL0=0x40; 

SCON=0x50; 

PCON=0x00; 

TH1=0xfd; 

TL1=0xfd; 

PS=1; 

EA=1; 

EX1=0; 

ET0=1; 

ES=1; 

TR0=1; 

TR1=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 

while(1) 

  if(plus==0) 

  { 

   EA=0; 

   for(a=0;a<5;a++) 

    for(b=0;b<102;b++){} 

   if(plus==0) 

   { 

    set_temper++; 

    flag=0; 

   } 

  } 

  else if(subs==0) 

  { 

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>