一个标准的PID算法

来源:互联网 发布:ven .js 编辑:程序博客网 时间:2024/05/21 17:33

一个标准的PID算法

#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 Structureunsigned 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));           //全部初始化为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;}}


原创粉丝点击