自己盖座楼;
今天没抽出时间捣鼓偷个懒先发一个以前写的暖通行业控制温度的PID算法,下面是贴的代码:
/*********************************
PID = Uk + KP*[E(k)-E(k-1)]+KI*E(k)+KD*[E(k)-2E(k-1)+E(k-2)];(增量型PID算式)
函数入口: RK(设定值),CK(实际值),KP,KI,KD;KP_Flag,kaidu_s,kaidu_x
函数出口: U(K)
//PID运算函数
*********************************/
s32 PIDOperation (PIDValueStr PID)
{
s32 Temp_s32[3],temp;
if(PID.KP_Flag == 0) //P参数为正
{
if((PID.RK_U16 - PID.CK_U16) > JINGDU) //设定值大于实际值(0.5℃精度)以上
{
if( PID.RK_U16 - PID.CK_U16 > FAZHI ) //偏差大于20度否?
{
PIDset1.Uk_s32 = (s32)(PID.Kaidu_s*0x0FFF); //偏差大于20度为控制阀上限开度阀值输出
}
else
{
PIDset1.Ek_s32[0] = PID.RK_U16 - PID.CK_U16; //偏差<=20度,计算E(k)
PIDset1.Ek_s32[2] = PIDset1.Ek_s32[1];
Temp_s32[0] = (PID.KP_s8)*((PIDset1.Ek_s32[0])-(PIDset1.Ek_s32[1]));
Temp_s32[1] = (PID.KI_U8)*(PIDset1.Ek_s32[0]);
Temp_s32[2] = (PID.KD_U8)*((PIDset1.Ek_s32[0])-2*(PIDset1.Ek_s32[1])+(PIDset1.Ek_s32[2]));
if((Temp_s32[0]+Temp_s32[1]) > 0)
temp = (s32)((Temp_s32[0]+Temp_s32[1]+Temp_s32[2])*1);
else
temp = 0;
PIDset1.Ek_s32[1] = PIDset1.Ek_s32[0];
if(temp > 0) // 是否控制量为正数
{
PIDset1.Uk_s32 += temp; //PID计算值输出
if(PIDset1.Uk_s32 >= (s32)(PID.Kaidu_s*0x0FFF))
{
PIDset1.Uk_s32 = (s32)(PID.Kaidu_s*0x0FFF); //否则为上限幅值输出
}
else if(PIDset1.Uk_s32 <= (s32)(PID.Kaidu_x*0x0FFF))
{
PIDset1.Uk_s32 = (s32)(PID.Kaidu_x*0x0FFF); //否则为下限幅值输出
}
}
else
{
PIDset1.Uk_s32 += 0; //控制量输出为负数,则输出不变
}
}
}
else if((PID.CK_U16 - PID.RK_U16) > JINGDU) //实际值大于设定值(0.1℃精度)以上 //设定值小于实际值?
{
PIDset1.Ek_s32[0] = PID.RK_U16 - PID.CK_U16; //计算偏差E(k)
PIDset1.Ek_s32[2] = PIDset1.Ek_s32[1];
Temp_s32[0] = (PID.KP_s8)*((PIDset1.Ek_s32[0])-(PIDset1.Ek_s32[1]));
if(Temp_s32[0] > 0)
Temp_s32[0] = -Temp_s32[0];
Temp_s32[1] = (PID.KI_U8)*(PIDset1.Ek_s32[0]);
Temp_s32[2] = (PID.KD_U8)*((PIDset1.Ek_s32[0])-2*(PIDset1.Ek_s32[1])+(PIDset1.Ek_s32[2]));
temp = (s32)((Temp_s32[0]+Temp_s32[1]+Temp_s32[2])*1);
PIDset1.Ek_s32[1] = PIDset1.Ek_s32[0];
if(temp < 0) //是否控制量为负数
{
PIDset1.Uk_s32 += temp; //PID计算值输出
if(PIDset1.Uk_s32 >= (s32)(PID.Kaidu_s*0x0FFF))
{
PIDset1.Uk_s32 = (s32)(PID.Kaidu_s*0x0FFF); //否则为上限幅值输出
}
else if(PIDset1.Uk_s32 <= (s32)(PID.Kaidu_x*0x0FFF))
{
PIDset1.Uk_s32 = (s32)(PID.Kaidu_x*0x0FFF); //否则为下限幅值输出
}
}
else
{
PIDset1.Uk_s32 += 0; //控制量输出为正数,则输出不变
}
}
}
else if(PID.KP_Flag == 1) //P参数为负
{
if((PID.RK_U16 - PID.CK_U16) > JINGDU) //设定值大于实际值(0.5℃精度)以上
{
if( PID.RK_U16 - PID.CK_U16 > FAZHI ) //偏差大于20度否?
{
PIDset1.Uk_s32 = (s32)(PID.Kaidu_s*0x0FFF); //偏差大于20度为控制阀上限开度阀值输出
}
else
{
PIDset1.Ek_s32[0] = PID.RK_U16 - PID.CK_U16; //偏差<=20度,计算E(k)
PIDset1.Ek_s32[2] = PIDset1.Ek_s32[1];
Temp_s32[0] = (PID.KP_s8)*((PIDset1.Ek_s32[0])-(PIDset1.Ek_s32[1]));
Temp_s32[1] = (PID.KI_U8)*(PIDset1.Ek_s32[0]);
Temp_s32[2] = (PID.KD_U8)*((PIDset1.Ek_s32[0])-2*(PIDset1.Ek_s32[1])+(PIDset1.Ek_s32[2]));
if((Temp_s32[0]+Temp_s32[1]) > 0)
temp = (s32)((Temp_s32[0]+Temp_s32[1]+Temp_s32[2])*1);
else
temp = 0;
PIDset1.Ek_s32[1] = PIDset1.Ek_s32[0];
if(temp > 0) // 是否控制量为正数
{
PIDset1.Uk_s32 -= temp; //PID计算值输出
if(PIDset1.Uk_s32 >= (s32)(PID.Kaidu_s*0x0FFF))
{
PIDset1.Uk_s32 = (s32)(PID.Kaidu_s*0x0FFF); //否则为上限幅值输出
}
else if(PIDset1.Uk_s32 <= (s32)(PID.Kaidu_x*0x0FFF))
{
PIDset1.Uk_s32 = (s32)(PID.Kaidu_x*0x0FFF); //否则为下限幅值输出
}
}
else
{
PIDset1.Uk_s32 += 0; //控制量输出为负数,则输出不变
}
}
}
else if((PID.CK_U16 - PID.RK_U16) > JINGDU) //实际值大于设定值(0.1℃精度)以上 //设定值小于实际值?
{
PIDset1.Ek_s32[0] = PID.RK_U16 - PID.CK_U16; //计算偏差E(k)
PIDset1.Ek_s32[2] = PIDset1.Ek_s32[1];
Temp_s32[0] = (PID.KP_s8)*((PIDset1.Ek_s32[0])-(PIDset1.Ek_s32[1]));
if(Temp_s32[0] > 0)
Temp_s32[0] = -Temp_s32[0];
Temp_s32[1] = (PID.KI_U8)*(PIDset1.Ek_s32[0]);
Temp_s32[2] = (PID.KD_U8)*((PIDset1.Ek_s32[0])-2*(PIDset1.Ek_s32[1])+(PIDset1.Ek_s32[2]));
temp = (s32)((Temp_s32[0]+Temp_s32[1]+Temp_s32[2])*1);
PIDset1.Ek_s32[1] = PIDset1.Ek_s32[0];
if(temp < 0) //是否控制量为负数
{
PIDset1.Uk_s32 -= temp; //PID计算值输出
if(PIDset1.Uk_s32 >= (s32)(PID.Kaidu_s*0x0FFF))
{
PIDset1.Uk_s32 = (s32)(PID.Kaidu_s*0x0FFF); //否则为上限幅值输出
}
else if(PIDset1.Uk_s32 <= (s32)(PID.Kaidu_x*0x0FFF))
{
PIDset1.Uk_s32 = (s32)(PID.Kaidu_x*0x0FFF); //否则为下限幅值输出
}
}
else
{
PIDset1.Uk_s32 += 0; //控制量输出为正数,则输出不变
}
}
}
return PIDset1.Uk_s32;
}