FUNCTION_BLOCK "F_CONT_C1" TITLE = 'continuous PID controller' { S7_Optimized_Access := 'FALSE' } AUTHOR : MT FAMILY : ICONT NAME : CONT_C1 VERSION : 1.5 VAR_INPUT COM_RST : Bool := FALSE; // 完全重启动 MAN_ON : Bool := TRUE; // 手动值打开 PVPER_ON : Bool := FALSE; // 外设过程变量打开 P_SEL : Bool := TRUE; // 比例作用打开 I_SEL : Bool := TRUE; // 积分作用打开 INT_HOLD : Bool := FALSE; // 积分作用保持 I_ITL_ON : Bool := FALSE; // 积分作用初始化 D_SEL : Bool := FALSE; // 微分作用打开 CYCLE : Time := T#1S; // 采样时间 SP_INT : Real := 0.0; // 内部设定值 PV_IN : Real := 0.0; // 过程变量输入 PV_PER : Word := WORD#16#0000; // 外设过程变量 MAN : Real := 0.0; // 手动值 GAIN : Real := 2.0; // 比例增益 TI : Time := T#20S; // 积分复位时间 TD : Time := T#10S; // 微分时间 TM_LAG : Time := T#2S; // 微分作用时间延时 DEADB_W : Real := 0.0; // 死区带宽 LMN_HLM : Real := 100.0; // 积分值上限 LMN_LLM : Real := 0.0; // 积分值下限 PV_FAC : Real := 1.0; // 过程变量因子 PV_OFF : Real := 0.0; // 过程变量偏移量 LMN_FAC : Real := 1.0; // 调节值因子 LMN_OFF : Real := 0.0; // 调节值偏移量 I_ITLVAL : Real := 0.0; // 积分作用的初始化值 DISV : Real := 0.0; // 干扰变量 END_VAR VAR_OUTPUT LMN : Real := 0.0; // 调节值 LMN_PER : Word := WORD#16#0000; // 外设调节值 QLMN_HLM : Bool := FALSE; // 达到调节值上限 QLMN_LLM : Bool := FALSE; // 达到调节值下限 LMN_P : Real := 0.0; // 比例分量 LMN_I : Real := 0.0; // 积分分量 LMN_D : Real := 0.0; // 微分分量 PV : Real := 0.0; // 当前值输出 ER : Real := 0.0; // 误差信号 END_VAR VAR sInvAlt : Real := 0.0; // 上周期比例偏差值 sIanteilAlt : Real := 0.0; // 上周期积分值 sRestInt : Real := 0.0; // 上周期积分偏差量(浮点数计算偏差) sRestDif : Real := 0.0; // 上周期微分偏差量(浮点数计算偏差) sRueck : Real := 0.0; sLmn : Real := 0.0; // 上周期调节值 sbArwHLmOn : Bool := FALSE; // 上周期达到调节值上限 sbArwLLmOn : Bool := FALSE; // 上周期达到调节值下限 sbILimOn : Bool := TRUE; // 备用-本程序没有使用该变量 END_VAR VAR_TEMP rCycle : Real; // 采样时间浮点值 Iant : Real; // 积分增量 Diff : Real; // 积分量 Istwert : Real; // 过程变量浮点值 ErKp : Real; // 偏差比例值 rTi : Real; // 积分时间浮点值 rTd : Real; // 微分时间浮点值 rTmLag : Real; // 微分作用时间延时浮点值 Panteil : Real; // 比例值 Ianteil : Real; // 积分值 Danteil : Real; // 微分值 Verstaerk : Real; RueckDiff : Real; RueckAlt : Real; // 上周期积分量 dLmn : Real; // 调节量 gf : Real; // Hilfwert rVal : Real; // Real Hilfsvariable END_VAR BEGIN //来源网络 IF #COM_RST THEN //PID初始化 #sIanteilAlt := #I_ITLVAL; #LMN := 0.0; #QLMN_HLM := FALSE; #QLMN_LLM := FALSE; #LMN_P := 0.0; #LMN_I := 0.0; #LMN_D := 0.0; #LMN_PER := W#16#0; #PV := 0.0; #ER := 0.0; #sInvAlt := 0.0; #sRestInt := 0.0; #sRestDif := 0.0; #sRueck := 0.0; #sLmn := 0.0; #sbArwHLmOn := FALSE; #sbArwLLmOn := FALSE; ELSE #rCycle := DINT_TO_REAL(TIME_TO_DINT(#CYCLE)) / 1000.0; //采样时间转换为浮点数值 #Istwert := DINT_TO_REAL(INT_TO_DINT(WORD_TO_INT(#PV_PER))) * 0.003616898; #Istwert := #Istwert * #PV_FAC + #PV_OFF; //外设输入转换为浮点数值 IF NOT #PVPER_ON THEN //过程变量选择 #Istwert := #PV_IN; END_IF; #PV := #Istwert; #ErKp := #SP_INT - #PV; //计算偏差 IF #ErKp < - #DEADB_W THEN #ER := #ErKp + #DEADB_W; ELSIF #ErKp > #DEADB_W THEN #ER := #ErKp - #DEADB_W; ELSE #ER := 0.0; END_IF; #ErKp := #ER * #GAIN; //偏差比例增益 #rTi := DINT_TO_REAL(TIME_TO_DINT(#TI)) / 1000.0; #rTd := DINT_TO_REAL(TIME_TO_DINT(#TD)) / 1000.0; #rTmLag := DINT_TO_REAL(TIME_TO_DINT(#TM_LAG)) / 1000.0; IF #rTi < #rCycle * 0.5 THEN //积分时间必须 >= 采样时间的0.5倍 #rTi := #rCycle * 0.5; END_IF; IF #rTd < #rCycle THEN //微分时间必须 >= 采样时间 #rTd := #rCycle; END_IF; IF #rTmLag < #rCycle * 0.5 THEN //微分作用延时时间必须 >= 采样时间的0.5倍 #rTmLag := #rCycle * 0.5; END_IF; IF #P_SEL THEN //比例作用投入 #Panteil := #ErKp; ELSE #Panteil := 0.0; END_IF; IF #I_SEL THEN //积分作用投入 IF #I_ITL_ON THEN //积分初始化 #Ianteil := #I_ITLVAL; #sRestInt := 0.0; ELSIF #MAN_ON THEN //手动值输入时的积分量计算,用于用于手动切换自动无扰切换 #Ianteil := #sLmn - #Panteil - #DISV; #sRestInt := 0.0; ELSE //积分计算 #Iant := (#rCycle / #rTi) * (#ErKp + #sInvAlt) * 0.5 + #sRestInt; IF ((#Iant > 0.0 AND #sbArwHLmOn) OR #INT_HOLD) OR (#Iant < 0.0 AND #sbArwLLmOn) THEN //抗积分饱和 #Iant := 0.0; END_IF; #Ianteil := #sIanteilAlt + #Iant; //当前积分值 := 上时刻积分值 + 本次积分量 #sRestInt := #sIanteilAlt - #Ianteil + #Iant; //感觉 sRestInt一直等于0.0 ;?????不知为何,通过运行发现不为0.0,可能是浮点数计算误差 END_IF; ELSE #Ianteil := 0.0; #sRestInt := 0.0; END_IF; #Diff := #ErKp; IF NOT #MAN_ON AND #D_SEL THEN //微分作用投入 #Verstaerk := #rTd / (#rCycle * 0.5 + #rTmLag); #Danteil := (#Diff - #sRueck) * #Verstaerk; #RueckAlt := #sRueck; #RueckDiff := #rCycle / #rTd * #Danteil + #sRestDif; #sRueck := #RueckDiff + #RueckAlt; #sRestDif := #RueckAlt - #sRueck + #RueckDiff; //同积分一样计算微分误差量 ELSE // #Danteil := 0.0; #sRestDif := 0.0; #sRueck := #Diff; END_IF; #dLmn := #Panteil + #Ianteil + #Danteil + #DISV; //PID输出 IF #MAN_ON THEN //PID手动之打开 #dLmn := #MAN; ELSE IF NOT #I_ITL_ON AND #I_SEL THEN //干扰量处理 IF #Ianteil > #LMN_HLM - #DISV AND #dLmn > #LMN_HLM AND #dLmn - #LMN_D > #LMN_HLM THEN #rVal := #LMN_HLM - #DISV; #gf := #dLmn - #LMN_HLM; #rVal := #Ianteil - #rVal; IF #rVal > #gf THEN #rVal := #gf; END_IF; #Ianteil := #Ianteil - #rVal; ELSIF #Ianteil < #LMN_LLM - #DISV AND #dLmn < #LMN_LLM AND #dLmn - #LMN_D < #LMN_LLM THEN #rVal := #LMN_LLM - #DISV; #gf := #dLmn - #LMN_LLM; #rVal := #Ianteil - #rVal; IF #rVal < #gf THEN #rVal := #gf; END_IF; #Ianteil := #Ianteil - #rVal; END_IF; END_IF; END_IF; #LMN_P := #Panteil; #LMN_I := #Ianteil; #LMN_D := #Danteil; #sInvAlt := #ErKp; #sIanteilAlt := #Ianteil; #sbArwHLmOn := FALSE; #sbArwLLmOn := FALSE; IF #dLmn >= #LMN_HLM THEN //调节辆限幅(上限) #QLMN_HLM := TRUE; #QLMN_LLM := FALSE; #dLmn := #LMN_HLM; #sbArwHLmOn := TRUE; ELSE #QLMN_HLM := FALSE; IF #dLmn <= #LMN_LLM THEN //调节辆限幅(下限) #QLMN_LLM := TRUE; #dLmn := #LMN_LLM; #sbArwLLmOn := TRUE; ELSE #QLMN_LLM := FALSE; END_IF; END_IF; #sLmn := #dLmn; #dLmn := #dLmn * #LMN_FAC + #LMN_OFF; #LMN := #dLmn; #dLmn := #dLmn * 276.48; IF #dLmn >= 32512.0 THEN #dLmn := 32512.0; ELSIF #dLmn <= -32512.0 THEN #dLmn := -32512.0; END_IF; #LMN_PER := INT_TO_WORD(DINT_TO_INT(REAL_TO_DINT(#dLmn))); END_IF; END_FUNCTION_BLOCK