×
单片机 > 单片机程序设计 > 详情

51 温度PID经典算法

发布时间:2020-05-26 发布时间:
|
#include  
#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 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      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< 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));    //全部初始化为0 
}  
/*====================================================================================================  
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);                // 微分项  
}  
/***********************************************************  
温度比较处理子程序  
***********************************************************/  
void compare_temper()  
{  
unsigned char i;  
if(set_temper>temper)      //是否设置的温度大于实际温度 
{  
   if(set_temper-temper>1)  //设置的温度比实际的温度是否是大于1度 
  {  
   high_time=100;      //如果是,则全速加热 
   low_time=0;  
  }  
       else  //如果是在1度范围内,则运行PID计算 
  {  
    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);  
}  
/***********************************************************  
主程序  
***********************************************************/  
void 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  比例常数 Proportional Const  
spid.Integral = 8;    //积分常数 Integral Const  
spid.Derivative =6;   //微分常数 Derivative Const  
spid.SetPoint = 100; // Set PID Setpoint 设定目标 Desired Value  
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)  
  {  
for(a=0;a<5;a++)  
for(b=0;a<102;b++){}  
if(subs==0)  
{  
 set_temper--;  
 flag=0;  
}  
  }  
else if(stop==0)  
{  
     for(a=0;a<5;a++)  
    for(b=0;b<102;b++){}  
    if(stop==0)  
{  
   flag=0;  
   break;  
}  
   EA=1;  
}  
       get_temper();  
   b=temper;  
if(flag_2==1)  
  a=b;  
if((abs(a-b))>5)  
  temper=a;  
else  
  temper=b;  
  a=temper;  
  flag_2=0;  
if(++count1>30)  
{  
  display();  
  count1=0;  
}  
  compare_temper();  
}  
   TR0=0;  
   z=1;  
while(1)  
{  
    EA=0;  
if(stop==0)  
{  
     for(a=0;a<5;a++)  
    for(b=0;b<102;b++){}  
    if(stop==0)  
    disp_1(phil);  
// break;  
}  
EA=1;  
}  


『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
如何升级STM32单片机的代码