打印
[疑难问答]

关于PID控制气压的算法

[复制链接]
2118|57
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
uptown|  楼主 | 2023-11-25 14:58 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
#include "config.h"
#include <math.h>
#define ADC_POWER   0x80            
#define ADC_FLAG    0x10            
#define ADC_START   0x08           
#define ADC_SPEEDLL 0x00         
#define ADC_SPEEDL  0x20           
#define ADC_SPEEDH  0x40         
#define ADC_SPEEDHH 0x60

unsigned char idata RsBuf[MAC_RX_BUF];
unsigned char data guc_RsPoint=0;
//unsigned char xdata Time0L1;
//unsigned char xdata Time0H1;
unsigned char xdata led_step=0;

unsigned char xdata led_show1;
unsigned char xdata led_show2;
unsigned char xdata led_show3;
unsigned char xdata led_show4;
unsigned int xdata Time_Show=0;

unsigned int xdata TimeMotor=0;
unsigned int xdata PwmBitVat=0;
//unsigned short xdata ADC_VAL[3];
//unsigned char xdata ADC_ch=0;

bit led_dian1;
bit led_dian2;
bit led_dian3;
bit led_dian4;
bit RsOver=0;

typedef struct _pid_t
{
        float SetSpeed;//定义设定值
        float ActualSpeed;//定义实际值
        float err;//定义偏差值
        float err_last;//定义上一个偏差值
        float Kp,Ki,Kd;//定义比例、积分、微分系数
        float voltage;//定义电压值(控制执行器的变量)
        float integral;//定义积分值
        float umax;
        float umin;
} pid_t;



unsigned char code ledTab[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x27,0x7f,0x6f};


void PID_init(pid_t *npid)
{
        npid->SetSpeed=0.0;
        npid->ActualSpeed=0.0;
        npid->err=0.0;
        npid->err_last=0.0;
        npid->voltage=0.0;
        npid->integral=0.0;
        npid->Kp=0.2;
        npid->Ki=0.015;
        npid->Kd=0.2;

        npid->umax=127;
        npid->umin=-127;
}

float PID_realize(pid_t *npid ,float speed,float ActualSpeed)
{
        float index;
        npid->SetSpeed=speed;
        npid->ActualSpeed=ActualSpeed;
        npid->err=npid->SetSpeed-npid->ActualSpeed;
        if(npid->voltage>npid->umax)
        {
                if(abs(npid->err)>200)//变积分过程
                {
                        index=0.0;
                }
                else if(abs(npid->err)<180)
                {
                        index=1.0;
                        if(npid->err<0)
                        {
                                npid->integral+=npid->err;
                        }
                }
                else
                {
                        index=(200-abs(npid->err))/20;
                        if(npid->err<0)
                        {
                                npid->integral+=npid->err;
                        }
                }
        }
        else if(npid->voltage<npid->umin)
        {
                if(abs(npid->err)>200)//变积分过程
                {
                        index=0.0;
                }
                else if(abs(npid->err)<180)
                {
                        index=1.0;
                        if(npid->err>0)
                        {
                                npid->integral+=npid->err;
                        }
                }
                else
                {
                        index=(200-abs(npid->err))/20;
                        if(npid->err>0)
                        {
                                npid->integral+=npid->err;
                        }
                }
        }
        else
        {
                if(abs(npid->err)>200)//变积分过程
                {
                        index=0.0;
                }
                else if(abs(npid->err)<180)
                {
                        index=1.0;
                        npid->integral+=npid->err;
                }
                else
                {
                        index=(200-abs(npid->err))/20;
                        npid->integral+=npid->err;
                }
        }
        npid->voltage=npid->Kp*npid->err+index*npid->Ki*npid->integral+npid->Kd*(npid->err-npid->err_last);
        npid->err_last=npid->err;
        return npid->voltage;
}


void Delay_n_ms(unsigned int dly)
{
        unsigned int        j;
        do
        {
                j = MAIN_Fosc / 13000;        //延时1ms, 主程序在此节拍下运行
                while(--j)        ;
        }while(--dly);
}
void InitUart(void)
{
        SCON = 0x50;//工作在串口模式
        T2L = (65536 - (MAIN_Fosc/4/BAUD)); //设置波特率为重新装值
        T2H = (65536 - (MAIN_Fosc/4/BAUD))>>8;
        AUXR |= 0x14; //启用定时器T2为1T模式, 并启用定时器2
        AUXR |= 0x01; //选择定时器2为串口1的波特率发生器
        ES = 1; //使能串口1为中断
}
void InitTime0(void)
{
//        #if 0
//        AUXR |=  (1<<7);        // Timer0 set as 1T mode
//        TMOD = 0x01; //16位,
//        //Timer0_16bit();
//        Time0L1=(65536-(MAIN_Fosc/1000000)*(TIME0_us1))%256;
//        Time0H1=(65536-(MAIN_Fosc/1000000)*(TIME0_us1))/256;
//        TL0=Time0L1;
//        TH0=Time0H1;
//        #endif
        T0_Load_us_12T(TIME0_us1);
        ET0 = 1;                //Timer0 Interrupt Enable
        PT0 = 1;                //高优先级
        TR0 = 1;                //Timer0 Run
}
// ADC初始化函数
void ADC_Init(void)
{
//        ADC_ch=0;
//        P1ASF=0x30;//设置P1为ADC
//        //P1ASF|=(1<<4)|(1<<5);
//        ADC_RES=0; // 清除结果寄存器
//        ADC_CONTR=ADC_POWER|ADC_SPEEDLL|ADC_START|4;
//        Delay_n_ms(20);
//        EADC=1;// EADC=1 允许ADC中断

//查询方式
        P1ASF=0x30;//设置P1为ADC
        ADC_RES=0;
        ADC_RESL=0;
        ADC_CONTR=ADC_POWER|ADC_SPEEDLL;
        Delay_n_ms(20);
}

void SendTxdBuf(unsigned char ASC)                                                        //发送-个ASCII
{
        ES     =   0;  //关闭串口中断
        SBUF   =   ASC;
        while(TI ==0); //
        TI     =   0;  //
        ES     =   1;  //允许串口中断
}
void Rs_Do(void) interrupt 4 using 1                                                                 //  通讯中断接收程序
{
        unsigned char data luc_temp;
        if(RI==1)
        {
                RI=0;
                luc_temp = SBUF;
                if(guc_RsPoint>=MAC_RX_BUF)
                        guc_RsPoint=0;      
                if(luc_temp==0x0d)
                {
                        RsBuf[guc_RsPoint] = 0x0d;
                        guc_RsPoint = 0;
                        RsOver = 1;
                }
                else
                {
                        RsBuf[guc_RsPoint++]=luc_temp;
                }
        }
}


void ledTime()
{
        switch(led_step)
        {
                case 0:
                        DIG1=1;
                        DIG2=0;
                        DIG3=0;
                        DIG4=0;
                        P2=ledTab[led_show1];
                        led_di=led_dian1;
                        led_step=1;
                        break;
                case 1:
                        DIG1=0;
                        DIG2=1;
                        DIG3=0;
                        DIG4=0;
                        P2=ledTab[led_show2];
                        led_di=led_dian2;
                        led_step=2;
                        break;
                case 2:
                        DIG1=0;
                        DIG2=0;
                        DIG3=1;
                        DIG4=0;
                        P2=ledTab[led_show3];
                        led_di=led_dian3;
                        led_step=3;
                        break;
                case 3:
                        DIG1=0;
                        DIG2=0;
                        DIG3=0;
                        DIG4=1;
                        P2=ledTab[led_show4];
                        led_di=led_dian4;
                        led_step=0;
                        break;
        }
}

void Time0Interrupt(void) interrupt 1 using 3
{
        //TR0=0;
        ledTime();
        if(Time_Show>0)
                Time_Show--;

        if(PwmBitVat>TimeMotor)
        {
                MOTOR1=1;
        }
        else
        {
                MOTOR1=0;//低电平打开电机
        }
        if(PwmBitVat++>256)
        {
                PwmBitVat=0;
        }
        //TL0=Time0L1;
        //TH0=Time0H1;
        //TR0=1;
}

//void ADC_ISR() interrupt 5
//{
//        ADC_CONTR &= ~ADC_FLAG;
//        switch(ADC_ch)
//        {
//                case 0:
//                        ADC_ch=1;
//                        ADC_VAL[0]=(ADC_RES<<2)|(ADC_RESL&0x03);
//               
//                        ADC_CONTR = ADC_POWER | ADC_SPEEDLL | 5 | ADC_START;
//                break;
//                case 1:
//                        ADC_ch=0;
//                        ADC_VAL[1]=(ADC_RES<<2)|(ADC_RESL&0x03);
//               
//                        ADC_CONTR = ADC_POWER | ADC_SPEEDLL | 4 | ADC_START;
//                break;
//        }
//}

void led_showP(float fshowPa)
{
        static float tmp_showPa=-1;
        float tmp_show=fshowPa;
        float temp_dian;
        unsigned char shorteger,shordian;
        if(fshowPa==tmp_showPa)
                return;
        tmp_showPa=fshowPa;

        shorteger=(unsigned char)abs((int)fshowPa);
        temp_dian=tmp_show-(float)shorteger;

        led_show1=shorteger/10;
        led_show2=shorteger%10;
        led_dian1=0;
        led_dian2=1;

        //小数点后两位
        shordian=(unsigned char)(temp_dian*100.0);
        led_show3=shordian/10;
        led_show4=shordian%10;
        led_dian3=0;
        led_dian4=0;
}

unsigned short GetADCResult(unsigned char ch)
{
        ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ch | ADC_START;
        while(!(ADC_CONTR&ADC_FLAG));
        ADC_CONTR &= ~ADC_FLAG;

        return (ADC_RES<<2)|(ADC_RESL&0x03);
}

使用特权

评论回复
沙发
gygp| | 2023-12-7 21:20 | 只看该作者
PID控制算法需要实时地执行,因此对其计算速度有一定要求

使用特权

评论回复
板凳
mollylawrence| | 2023-12-8 08:27 | 只看该作者
PID控制方法将偏差的比例(proportional)、积分(integral)、微分(derivative)通过线性组合构成控制量,对被控对象进行控制。

使用特权

评论回复
地板
modesty3jonah| | 2023-12-8 08:48 | 只看该作者
在控制气压时,需要根据实际系统的特点来调整这些参数,以达到较好的控制效果。参数调整过程中需要考虑系统的稳定性、响应速度和超调量等因素。

使用特权

评论回复
5
lihuami| | 2023-12-8 09:02 | 只看该作者
当PID控制器的积分项累积到一定程度时,可能会导致控制器输出饱和,即使微分项也尝试调整,但已经无法在短时间内恢复到设定值。

使用特权

评论回复
6
maqianqu| | 2023-12-8 09:45 | 只看该作者
在实际应用中,PID参数需要不断进行调整,以适应控制对象的变化和环境的影响。

使用特权

评论回复
7
loutin| | 2023-12-8 20:46 | 只看该作者
传感器漂移和噪声可能会影响控制性能

使用特权

评论回复
8
uytyu| | 2023-12-9 10:11 | 只看该作者
系统可能会受到干扰和噪声的影响              

使用特权

评论回复
9
uiint| | 2023-12-9 14:42 | 只看该作者
数调整是一个迭代的过程,可能需要多次尝试才能找到最优的参数组合。

使用特权

评论回复
10
louliana| | 2023-12-9 15:10 | 只看该作者
在实现PID控制气压算法时,需要合理设计控制逻辑,包括误差计算、控制量计算和输出等环节

使用特权

评论回复
11
bestwell| | 2023-12-9 20:06 | 只看该作者
在控制器的过渡过程中,可能会出现过冲或过滞等现象,需要进行相应的处理。

使用特权

评论回复
12
iyoum| | 2023-12-9 21:22 | 只看该作者
PID控制器需要考虑系统的特性,例如延迟、滞后等。

使用特权

评论回复
13
vivilyly| | 2023-12-10 15:25 | 只看该作者
气压控制系统可能存在非线性特性,这对于PID控制算法的适用性有一定影响。

使用特权

评论回复
14
pmp| | 2023-12-10 15:47 | 只看该作者
PID控制算法的设计需要考虑控制目标和环境因素,以选取合适的控制量和反馈信号。

使用特权

评论回复
15
timfordlare| | 2023-12-10 16:30 | 只看该作者
微分控制是为了预测误差的变化趋势,提前进行控制,从而加快系统的响应速度。

使用特权

评论回复
16
uytyu| | 2023-12-10 17:58 | 只看该作者
这些参数包括比例系数、积分时间和微分时间。不同系统可能需要不同的参数配置。

使用特权

评论回复
17
lihuami| | 2023-12-10 18:17 | 只看该作者
PID控制器的参数需要进行整定,可以使用经验整定法、Ziegler-Nichols方法等

使用特权

评论回复
18
wilhelmina2| | 2023-12-10 18:35 | 只看该作者
PID控制算法根据目标气压值和实际气压值之间的差距进行工作,通过调节控制阀门的开度,使得实际气压值逐渐趋近于目标气压值。

使用特权

评论回复
19
1988020566| | 2023-12-12 09:34 | 只看该作者
PI算法适用于控制通道滞后较小、负荷变化不大、工艺参数不允许有静差的系统;而PD算法则适用于惯性较大的对象,可以加快控制速度,改善控制质量,减小偏差,缩短控制时间。

使用特权

评论回复
20
hilahope| | 2023-12-12 10:12 | 只看该作者
一般可以通过经验法、试错法或整定软件来确定合适的参数。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

41

主题

3527

帖子

2

粉丝