S7-SCL(Structured Control Language 结构化控制语言) 具有以下特点:
· 1、是一种类似于PASCAL的高级编程语言
· 2、符合国际标准IEC 61131-3
· 3、PLCopen基础级认证
· 4、适用于 S7-300 (推荐CPU314以上), S7-400,S7-1200,S7-1500, C7 and WinAC
· S7-SCL 为 PLC 做了优化处理,它不仅仅具有 PLC 典型的元素(例如 输入/输出,定时器,计数器,符号表),而且具有高级语言的特性, 例如:循环, 选择,分支,数组 ,高级函数。
以下源程序来源于网络,不保证编译后与原版一致,仅供参考。使用的是位置式PID,里面还做了手自动的无扰动切换。源码可以通过编译,内容如下:
FUNCTION_BLOCK “CONT_C”
TITLE =’continuous PID controller’
AUTHOR : MT
FAMILY : ICONT
NAME : CONT_C
VERSION : ‘1.5’
KNOW_HOW_PROTECT
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 := W#16#0; //外设过程变量
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 := W#16#0; //外设调节值
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
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
yanyan
pid块 FB41 SCL 源代码
查看日志列表 发表于01月26日 15:08
FUNCTION_BLOCK “CONT_C”
TITLE =’continuous PID controller’
AUTHOR : MT
FAMILY : ICONT
NAME : CONT_C
VERSION : ‘1.5’
KNOW_HOW_PROTECT
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 := W#16#0; //外设过程变量
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 := W#16#0; //外设调节值
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
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