自己盖座楼;
今天没抽出时间捣鼓偷个懒先发一个以前写的暖通行业控制温度的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; }