一个标准的PID算法

一个标准的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 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));           //全部初始化为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;
}
}


  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。
### 回答1: 标准PID控制算法的程序流程图如下: 1. 初始化PID参数:将比例系数Kp、积分系数Ki和微分系数Kd设定为合适的初始值,并将累积误差sum_error初始化为0。 2. 循环运行:进入一个循环,以固定的时间间隔执行PID控制算法。 3. 读取当前的系统状态:获取当前的反馈信号,即系统的实际输出值。 4. 计算当前误差:将目标值与当前的反馈信号相减,得到当前的误差error。 5. 累积误差计算:将当前误差error与之前的误差进行累加,得到累积误差sum_error。 6. 计算控制量:利用PID算法,将比例项、积分项和微分项分别乘以对应的系数Kp、Ki和Kd,得到控制量control。 7. 输出控制量:将计算得到的控制量control输出给执行器,如电机或阀门。 8. 更新误差:将当前误差error保存为上一个时间步的误差,以备下一次循环使用。 9. 延时等待:等待固定的时间间隔,然后回到第3步读取系统状态。 以上是标准PID控制算法的程序流程图,通过不断地计算误差、调整控制量,以实现将系统的实际输出逼近目标值。 ### 回答2: 标准PID控制算法的程序流程图如下: 1. 开始程序 2. 获取当前系统的反馈信号(一般是传感器采集到的实际值) 3. 计算误差,即目标值与实际值之间的差值 4. 根据PID控制算法计算控制量,包括比例项(Proportional)、积分项(Integral)和微分项(Derivative) 5. 设置并更新积分项的累积误差,用于补偿系统稳态误差 6. 设置并更新微分项的变化量,用于增强系统的响应速度和稳定性 7. 计算控制量,并根据指定的范围进行限制,以防止控制量超出可执行范围 8. 输出控制量,将其送给执行器或下一级控制模块 9. 等待一定的采样周期,继续执行 10. 返回步骤2,循环执行上述步骤 11. 结束程序 在这个基本的程序流程图中,比例项使系统能够对误差进行快速响应,积分项用于消除系统的稳态误差,微分项用于抑制系统的振荡。不同的PID控制算法可以根据实际需求对比例、积分和微分系数进行调整。这个流程图可以作为PID控制算法的基础,根据具体应用进行扩展和优化。 ### 回答3: 标准PID(比例-积分-微分)控制算法的程序流程图如下: 1. 初始化参数和变量: - 设定目标值(Setpoint)和反馈值(Feedback); - 设定比例系数(Kp)、积分系数(Ki)和微分系数(Kd); - 初始化误差项(error)、累计误差项(integral)和上一次误差项(previous_error)。 2. 循环执行控制算法: - 计算误差项(error = Setpoint - Feedback); - 更新累计误差项(integral = integral + error); - 计算微分项(derivative = error - previous_error); - 计算控制输出值(output = Kp * error + Ki * integral + Kd * derivative); - 将上一次误差项更新为当前误差项(previous_error = error)。 3. 输出控制信号: - 使用output作为控制信号,执行相应的控制操作; - 延时一段时间,等待系统响应。 4. 返回第2步,继续执行控制算法。 标准PID控制算法通过不断计算和调整控制输出值,使得误差逐渐减小,从而实现对系统的稳定控制。比例项用于根据当前误差项直接计算控制输出值,积分项用于消除系统永久偏差,微分项用于预测误差的未来变化趋势。这些项的权重由相应的系数(Kp、Ki和Kd)决定,根据具体应用需求进行调整。程序流程图中的循环执行部分保证了实时的控制操作,通过不断重复计算和调整的过程,使控制系统能够持续跟踪目标值并对系统进行调节。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值