SCL(Structured Control Language,结构化控制语言)是一种基于 PASCAL 的高级编程语言。这种语言基于标准 DIN EN 61131-3(国际标准为 IEC 1131-3)。
根据该标准,可对用于可编程逻辑控制器的编程语言进行标准化。SCL 编程语言实现了该标准中定义的 ST 语言 (结构化文本) 的 PLCopen 初级水平。
S7-1200从V2.2版本开始支持SCL语言。
语言元素
SCL 除了包含 PLC 的典型元素(例如,输入、输出、定时器或存储器位)外,还包含高级编程语言。
程序控制语句
SCL 提供了简便的指令进行程序控制。例如,创建程序分支、循环或跳转。
应用
因此,SCL 尤其适用于下列应用领域:
说明:表达式将在程序运行期间进行运算,然后返回一个值。一个表达式由操作数(如常数、变量或函数调用)和与之搭配的操作符(如 *、/、+ 或 -)组成。通过运算符可以将表达式连接在一起或相互嵌套。
运算顺序
表达式将按照下面因素定义的特定顺序进行运算:
表达式类型
不同的运算符,分别可使用以下不同类型的表达式:
说明:算术表达式既可以是一个数字值,也可以是由带有算术运算符的两个值或表达式组合而成。
算术运算符可以处理当前 CPU 所支持的各种数据类型。如果在该运算中有 2 个操作数,那么可根据以下条件来确定结果的数据类型:
算术表达式的数据类型
表1列出了在算术表达式中可使用的数据类型:
运算 | 运算符 | 优先级 | 第一个操作数 | 第二个操作数 | 结果 |
---|---|---|---|---|---|
乘方 | ** | 2 | 整数/浮点数 | 整数/浮点数 | 浮点数 |
正号 | + | 3 | 整数/浮点数 | - | 整数/浮点数 |
Time | Time | ||||
负号 | - | 整数/浮点数 | - | 整数/浮点数 | |
Time | Time | ||||
乘法 | * | 4 | 整数/浮点数 | 整数/浮点数 | 整数/浮点数 |
Time | 整数 | Time | |||
除法 | / | 整数/浮点数 | 整数/浮点数(≠0) | 整数/浮点数 | |
Time | 整数 | Time | |||
取模 | MOD | 整数 | 整数 | 整数 | |
加法 | + | 5 | 整数/浮点数 | 整数/浮点数 | 整数/浮点数 |
Time | Time | Time | |||
Time | DInt | Time | |||
TOD | Time | TOD | |||
TOD | DInt | TOD | |||
Date | TOD | DTL | |||
DTL | Time | DTL | |||
减法 | - | 整数/浮点数 | 整数/浮点数 | 整数/浮点数 | |
Time | Time | Time | |||
Time | DInt | Time | |||
TOD | Time | TOD | |||
TOD | DInt | TOD | |||
TOD | TOD | Time | |||
Date | Date | Time | |||
DTL | Time | DTL | |||
DTL | DTL | Time |
示例
以下为一些算术表达式的示例:
"MyTag1":= "MyTag2" * "MyTag3";
说明:关系表达式将两个操作数的值或数据类型进行比较,然后得到一个布尔值。如果比较结果为真,则结果为 TRUE,否则为 FALSE。
关系运算符可以处理当前 CPU 所支持的各种数据类型。结果的数据类型始终为 Bool。
编写关系表达式时,请注意以下规则:
关系表达式的数据类型
表2列出了在关系表达式中可使用的数据类型/数据类型组:
运算 | 运算符 | 优先级 | 第一个操作数 | 第二个操作数 | 结果 |
---|---|---|---|---|---|
小于、小于等于、大于、大于等于 | <、<=、>、>= | 6 | 整数/浮点数 | 整数/浮点数 | Bool |
位序列 | 位序列 | Bool | |||
字符串 | 字符串 | Bool | |||
Time | Time | Bool | |||
日期和时间 | 日期和时间 | Bool | |||
等于、不等于 | ==、<> | 7 | 整数/浮点数 | 整数/浮点数 | Bool |
位序列 | 位序列 | Bool | |||
字符串 | 字符串 | Bool | |||
Time | Time | Bool | |||
日期和时间 | 日期和时间 | Bool | |||
Variant | 任意数据类型 | Bool | |||
UDT | UDT | Bool | |||
Array | Array | Bool | |||
Struct | Struct | Bool |
示例
以下举例说明了一个关系表达式:
IF a > b THEN c:= a; IF A > 20 AND B < 20 THEN C:= TRUE; IF A<>(B AND C) THEN C:= FALSE;
说明:逻辑表达式由两个操作数和逻辑运算符(AND、OR 或 XOR)或取反操作数 (NOT) 组成。
逻辑运算符可以处理当前 CPU 所支持的各种数据类型。如果两个操作数都是 Bool 数据类型,则逻辑表达式的结果也为 Bool数据类型。如果两个操作数中至少有一个是位序列,则结果也为位序列而且结果是由最高操作数的类型决定。例如,当逻辑表达式的两个操作数分别是 Byte 类型和 Word 类型时,结果为 Word类型。
逻辑表达式中一个操作数为 Bool类型而另一个为位序列时,必须先将 Bool类型的操作数显式转换为位序列类型。
逻辑表达式的数据类型
下表列出了逻辑表达式中可使用的数据类型:
运算 | 运算符 | 优先级 | 第一个操作数 | 第二个操作数 | 结果 |
---|---|---|---|---|---|
取反 | NOT | 3 | Bool | - | Bool |
求反码 | 位序列 | - | 位序列 | ||
与 | AND、& | 8 | Bool | Bool | Bool |
位序列 | 位序列 | 位序列 | |||
异或 | XOR | 9 | Bool | Bool | Bool |
位序列 | 位序列 | 位序列 | |||
或 | OR | 10 | Bool | Bool | Bool |
位序列 | 位序列 | 位序列 |
示例
以下为一个逻辑表达式的示例:
IF "MyTag1" AND NOT "MyTag2" THEN c := a; MyTag := A OR B;
定义:通过赋值运算,可以将一个表达式的值分配给一个变量。赋值表达式的左侧为变量,右侧为表达式的值。
函数名称也可以作为表达式。赋值运算将调用该函数,并返回其函数值,赋给左侧的变量。
赋值运算的数据类型取决于左边变量的数据类型。右边表达式的数据类型必须与该数据类型一致。
赋值运算的计算按照从右到左的顺序进行。
可通过以下方式编程赋值运算:
示例
下表举例说明了单赋值运算的操作:
"MyTag1" := "MyTag2"; | (* 变量赋值 *) |
---|---|
"MyTag1" := "MyTag2" * "MyTag3"; | (* 表达式赋值 *) |
"MyTag" := "MyFC"(); | (* 调用一个函数,并将函数值赋给 "MyTag" 变量 *) |
#MyStruct.MyStructElement := "MyTag"; | (* 将一个变量赋值给一个结构元素 *) |
#MyArray[2] := "MyTag"; | (* 将一个变量赋值给一个 ARRAY 元素 *) |
"MyTag" := #MyArray[1,4]; | (* 将一个 ARRAY 元素赋值给一个变量 *) |
#MyString[2] := #MyOtherString[5]; | (* 将一个 STRING 元素赋给另一个 STRING 元素 *) |
下表举例说明了多赋值运算的操作:
"MyTag1" := "MyTag2" := "MyTag3"; | (* 变量赋值 *) |
---|---|
"MyTag1" := "MyTag2" := "MyTag3" * "MyTag4"; | (* 表达式赋值 *) |
"MyTag1" := "MyTag2" := "MyTag3 := "MyFC"(); | (* 调用一个函数,并将函数值赋值给变量 "MyTag1"、"MyTag1" 和 "MyTag1" *) |
#MyStruct.MyStructElement1 := #MyStruct.MyStructElement2 := "MyTag"; | (* 将一个变量赋值给两个结构元素 *) |
#MyArray[2] := #MyArray[32] := "MyTag"; | (* 将一个变量赋值给两个数组元素 *) |
"MyTag1" := "MyTag2" := #MyArray[1,4]; | (* 将一个数组元素赋值给两个变量 *) |
#MyString[2] := #MyString[3]:= #MyOtherString[5]; | (* 将一个 STRING 元素赋值给两个 STRING 元素 *) |
下表举例说明了组合赋值运算的操作:
"MyTag1" += "MyTag2"; | (* "MyTag1" 和 "MyTag2" 相加,并将相加的结果赋值给 "MyTag1"。*) |
---|---|
"MyTag1" -= "MyTag2" += "MyTag3"; | (* "MyTag2" 和 "MyTag3" 相加。将相加的结果赋值给操作数"MyTag2",再从 "MyTag1" 中减去"MyTag2",计算结果将赋值给 "MyTag1"。*) |
#MyArray[2] += #MyArray[32] += "MyTag"; | (* 数组元素 "MyArray[32]" 加上 "MyTag"。计算结果将赋值给 "MyArray[32]"。之后这个数组元素 "MyArray[32]" 与数组中另一个元素"MyArray[2]"相加,然后将结果分配给数组元素 "MyArray[2]"。在该运算中,相应的数据类型必需兼容。*) |
#MyStruct.MyStructElement1 /= #MyStruct.MyStructElement2 *= "MyTag"; | (* 结构化元素 "MyStructElement2" 乘以 "MyTag"。计算结果将赋值给 "MyStructElement2"。之后,将结构化元素 "MyStructElement1" 除以 "MyStructElement2",并将计算结果赋值给 "MyStructElement1"。在该运算中,相应的数据类型必需兼容。*) |
SCL寻址分为符号寻址与地址寻址。
举例:
符号名 | 说明 | ||
---|---|---|---|
符号寻址 | DB块变量 | "MyDB".Variable.Static_1 | |
"MyDB".Array[0] | 访问数组元素 | ||
"MyDB" | DB块名作为参数 | ||
PLC变量 | "Start" | ||
局部变量 | #Input_1 | ||
#Temp_1.x0 | 变量名片段访问 | ||
地址寻址 | DB块变量 | %DB2.DBB1 | |
%DB2 | DB块名作为参数,会立刻转换为DB块名 | ||
PLC变量 | %M100.0 | 会立刻转换为"符号名" | |
%Q1.0:P | 会立刻转换为"符号名":P |
程序调用分为以下几类:
调用可以从指令列表或者项目树程序块中拖拽入程序编辑区域,也可以直接输入。
FC调用
FC调用的格式是
FC调用需要确保所有形参都有对应实参。如果没有参数的FC也需要有括号。
如图所示的例子;
图1 FC调用
FB调用
FB调用的格式是
"背景数据块名称"(输入形参:=实参,输出形参=>实参,输入输出形参:=实参...)
一般情况下,FB的简单数据类型形参可以没有对应实参,复杂数据类型的输入、输出也可以没有对应实参,所以FB可以隐藏或不隐藏不出现的形参。如果没有参数的FB也需要有括号。
如图2所示,显示了一些FB调用的例子。
图2 FB调用
如图3所示,当FB的参数全部显示,在背景数据块右键可以激活"仅显示分配的参数";当FB的参数只显示了分配的参数时,在背景数据块右键可以激活"显示所有参数"。
图3 显示分配/所有参数
FB多重背景调用
FB多重背景调用的格式是
一般情况下,FB的简单数据类型形参可以没有对应实参,复杂数据类型的输入、输出也可以没有对应实参,所以FB可以隐藏或不隐藏不出现的形参。如果只有Static的FB也需要有括号。
如图4所示,显示了一些FB多重背景调用的例子。
图4 FB多重背景调用
注意:
对于定时器和计数器的SCL调用,有特殊的格式,请参考链接:定时器、计数器。
有两种方式新建SCL:
第一种是在新建块,选择OB/FC/FB后,设置语言为SCL,如图5所示。
第二种是在LAD、FBD中直接插入SCL语言段,这需要TIA PORTAL V14及其以上的版本,如图6所示。
图5 新建SCL块
①在项目树中,找到PLC,然后展开程序块,点击"添加新块"
②在弹出对话框中,选择块类型,可以是OB/FB/FC,
③选择语言为SCL
图6 在LAD中插入SCL段
和LAD/FBD不同,LAD/FBD在程序编辑器是一段一段的,编辑器可以插入新的网络段,每一个网络段可以有各自的注释。而SCL是文本语言,不分网络段(LAD/FBD语言内增加SCL除外),需要用其他的方法来解决。
从TIA PORTAL V14以后,增加区间功能,使用指令:
REGION 区间名称
程序文本
END_REGION
可以在指令中间增加需要编写的程序还不影响程序逻辑,并且支持嵌套。此外还可以像网络段一样收折叠来,如图7所示。
图7 区域
其中左边为区间总览,可以看出整体的结构
①使得程序或总览全部展开
②使得程序或总览全部折叠
③全部展开/折叠是针对总览与程序还是只针对总览,图中为针对总览与程序
④独立展开/折叠程序
编辑器的空行,或者调用块的右侧均可以增加注释,如图8所示有两种方式注释:
第一种是://注释内容
第二种是:(/*注释内容*/)
可以在工具栏中利用按钮整段注释或取消注释。此外从TIA PORTAL V16开始支持多语言注释,使用指令(*多语言注释内容*),具体参考多语言文档。
图8 注释
①注释掉选中段落
②对注释掉的段落取消注释
SCL作为一种编程语言,可以实现LAD/FBD所有的功能,大多数的指令与LAD/FBD都是相同的,只是在编辑器中的外形不同。只有一些指令使用是不太一样的甚至LAD/FBD没有的,这里只介绍这些不同的。
SCL特殊的指令有以下几种,如图1-3红框中的指令:
图1 读写存储器
图2 转换操作
图3 程序控制指令
在这三部分中,读写存储器的PEEK POKE指令可以参考链接,转换操作可以参考链接,这里只介绍图3的程序控制指令。
程序控制指令见以下表格。
程序控制语句 | 说明 | |
---|---|---|
选择 | IF-THEN语句 | 用将程序执行转移到两个备选分支之一(取决于条件为 True 还是 False) |
CASE语句 | 用于选择执行 n 个备选分支之一(取决于变量值) | |
循环 | FOR语句 | 只要控制变量在指定值范围内,就重复执行某一语句序列 |
WHILE-DO语句 | 只要仍满足执行条件,就重复执行某一语句序列 | |
REPEAT-UNTIL语句 | 重复执行某一语句序列,直到满足终止条件为止 | |
程序跳转 | CONTINUE语句 | 停止执行当前循环迭代 |
EXIT语句 | 无论是否满足终止条件,都会随时退出循环 | |
GOTO语句 | 使程序立即跳转到指定标签 | |
RETURN语句 | 使程序立刻退出正在执行的块,返回到调用块 |
程序控制指令是SCL编程的基础,接近高级语言的指令,虽然这些功能通过LAD/FBD也可以实现,但使用SCL编写会更加方便,逻辑条理也更加清晰。
说明:使用"条件执行"指令,可以根据条件控制程序流的分支。该条件是结果为布尔值(True 或 False)的表达式。可以将Bool变量、逻辑表达式或比较表达式作为条件。
执行该条件执行指令时,将对指定的表达式进行运算。如果表达式的值为 True,则表示满足该条件;如果其值为 False,则表示不满足该条件。
参数
根据分支的类型,可以对以下形式的指令进行编程:
图4 IF...THEN... 分支
如果满足该条件,则将执行 THEN 后编写的指令。如果不满足该条件,则程序将从 END_IF 后的下一条指令开始继续执行。
图5 IF...THEN... ELSE...分支
如果满足该条件,则将执行 THEN 后编写的语句。如果不满足该条件,则将执行 ELSE 后编写的语句。不论执行哪一个语句,之后都将从 END_IF 后的下一条指令开始继续执行。
图6 IF...THEN... ELSIF...分支
如果满足条件1,则将执行 THEN 后的语句1,执行这些语句后,程序将从 END_IF 后继续执行。
如果不满足条件1,则将检查条件2。如果满足条件2,则将执行 THEN 后的语句2。执行这些语句后,程序将从 END_IF 后继续执行。
如果不满足任何条件,则直接执行 END_IF 后的程序部分。
在 IF 指令内可以嵌套任意多个 ELSIF 和 THEN 组合。可以选择对 ELSE 分支进行编程。
参数
下表列出了该指令的参数:
参数 | 数据类型 | 存储区 | 说明 |
---|---|---|---|
<条件> | BOOL | I、Q、M、D、L | 待求值的表达式。 |
<语句> | - | 在满足条件时,要执行THEN后的语句。如果不满足条件,则执行 ELSE 后编写的语句。 |
示例
图7 IF示例
下表展示了不同的操作数数值对目标变量的影响:
操作数 | 值 | |||
---|---|---|---|---|
"Tag_1" | True | False | False | False |
"Tag_2" | False | True | False | False |
"Tag_3" | False | False | True | False |
"Tag_Value" | 10 | 20 | 30 | 0 |
说明:使用"创建多路分支"指令,可以根据数字表达式的值执行多个指令序列中的一个。
按如下方式声明此指令:
CASE <变量> OF
<常数1>: <语句1>;
<常数2>: <语句2>;
......
<常数n>: <语句n>;
ELSE <语句>;
END_CASE;
图8 CASE语句
参数
下表列出了该指令的参数:
参数 | 数据类型 | 存储区 | 说明 |
---|---|---|---|
<变量> | 整数、位序列* | I、Q、M、D、L | 与设定的常数值进行比较的值。 |
<常数> | 位序列 | - | 若为位序列,则常数可以为以下值:二进制数(例如,2#10)八进制数(例如,8#77)十六进制数(例如,16#AD)未定型的常数(例如,1000) |
整数 | 作为指令序列执行条件的常数值。常数可以为以下值:整数(例如,5)整数范围(例如,15 到 20)由整数和范围组成的枚举(例如,10、11、15 到 20) | ||
<语句> | - | - | 当表达式的值等于某个常数值时,将执行该常数后的各种指令。如果不满足条件,则执行 ELSE 后编写的指令。如果两个值不相等,则执行这些指令。 |
整数作为指令序列执行条件的常数值。常数可以为以下值:
<语句>--当表达式的值等于某个常数值时,将执行该常数后的各种指令。如果不满足条件,则执行 ELSE 后编写的指令。如果两个值不相等,则执行这些指令。
* TIA PORTAL V16开始支持位序列数据类型的变量
示例
图9 CASE示例
下表展示了不同的操作数数值对目标变量的影响:
操作数 | 值 | ||||
---|---|---|---|---|---|
"Tag_Value" | 0 | 1,3,5 | 6,7,8,9,10 | 16,17,20,21,22,23,24,25 | 其他 |
"Tag_1" | 1 | - | - | - | - |
"Tag_2" | - | 1 | - | - | - |
"Tag_3" | - | - | 1 | - | - |
"Tag_4" | - | - | - | 1 | - |
"Tag_5" | - | - | - | - | 1 |
说明:使用"在计数循环中执行"指令,重复执行程序循环,直至运行变量不在指定的取值范围内。
也可以嵌套程序循环。在程序循环内,可以编写包含其它运行变量的其它程序循环。
通过指令"复查循环条件"(Continue),可以终止当前正在运行的程序循环。通过指令"立即退出循环"(Exit)终止整个循环的执行。
注意:
有关运行次数和运行变量的信息:
程序运行时无法更改运行次数。出于性能原因,应在块接口的"Temp"部分中声明运行变量。在循环中,该运行变量无法更改。
按如下方式声明此指令:
FOR <运行变量> := <起始值> TO <结束值> BY <增量> DO
<语句>;
END_FOR;
如果增量为1,可以简写为:
FOR <运行变量> := <起始值> TO <结束值> DO
<语句>;
END_FOR;
图10 FOR语句
下表列出了该指令的参数:
*TIA PORTAL V16开始支持无符号整数类型的变量
示例
图11 FOR示例
Tag_Value 操作数乘以b_array 数组变量的元素 (2, 4, 6, 8)。并将计算结果读入到a_array 数组变量的元素 (2, 4, 6, 8) 中。
下表展示了给定 Tag_Value 与 b_array[i] 的值得到 a_array[i] 的结果:
设定 | Tag_Value | |||
---|---|---|---|---|
值 | 5 | |||
设定 | b_array[2] | b_array[4] | b_array[6] | b_array[8] |
值 | 3 | 5 | 7 | 9 |
结果 | a_array[2] | a_array[4] | a_array[6] | a_array[8] |
值 | 15 | 25 | 35 | 45 |
说明:使用"满足条件时执行"指令可以重复执行程序循环,直至不满足执行条件为止。该条件是结果为布尔值(True 或 False)的表达式。可以将逻辑表达式或比较表达式作为条件。
执行该指令时,将对指定的表达式进行运算。如果表达式的值为 True,则表示满足该条件;如果其值为 False,则表示不满足该条件。
也可以嵌套程序循环。在程序循环内,可以编写包含其它运行变量的其它程序循环。
通过指令"复查循环条件"(Continue),可以终止当前连续运行的程序循环。通过指令"立即退出循环"(Exit)终止整个循环的执行。
可按如下方式声明此指令:
WHILE <条件>
DO <语句>;
END_WHILE;
图12 WHILE语句
参数
下表列出了该指令的参数:
参数 | 数据类型 | 存储区 | 说明 |
---|---|---|---|
<条件> | BOOL | I、Q、M、D、L | 表达式,每次执行循环之前都需要进行求值。 |
<语句> | - | 在满足条件时,要执行的语句。如果不满足条件,则程序将从 END_WHILE 后继续执行。 |
示例
图13 WHILE示例
下表展示了循环初始和循环结束时变量值的变化
初始 | 循环结束 | |
---|---|---|
Tag_2 | 5 | |
Tag_1 | 0 | 5 |
说明:使用"不满足条件时执行"指令可以重复执行程序循环,直至不满足执行条件为止。该条件是结果为布尔值(True 或 False)的表达式。可以将逻辑表达式或比较表达式作为条件。
执行该指令时,将对指定的表达式进行运算。如果表达式的值为 True,则表示满足该条件;如果其值为 False,则表示不满足该条件。
即使满足终止条件,至少也会执行一次循环内的语句。
也可以嵌套程序循环。在程序循环内,可以编写包含其它运行变量的其它程序循环。
通过指令"复查循环条件"(Continue),可以终止当前连续运行的程序循环。通过指令"立即退出循环"(Exit)终止整个循环的执行。
可按如下方式声明此指令:
REPEAT <语句>;
UNTIL <条件>
END_REPEAT;
图14 REPEAT语句
参数
下表列出了该指令的参数:
参数 | 数据类型 | 存储区 | 说明 |
---|---|---|---|
<语句> | - | 在设定条件的值为 False 时执行的指令。即使满足终止条件,此指令也执行一次。 | |
<条件> | BOOL | I、Q、M、D、L | 表达式,每次执行循环之后都需要进行求值。如果表达式的值为 False,则将再次执行程序循环。如果表达式的值为 True,则程序循环将从 END_REPEAT 后继续执行。 |
示例
图15 REPEAT示例
下表展示了循环初始和循环结束时变量值的变化
初始 | 循环结束 | |
---|---|---|
Tag_2 | 5 | |
Tag_1 | 0 | 6 |
说明:使用"复查循环条件"指令,可以结束 FOR、WHILE 或 REPEAT 循环的当前程序运行。
执行该指令后,将再次计算继续执行程序循环的条件。该指令将影响其所在的程序循环。
图16 CONTINUE用在FOR循环
图17 CONTINUE用在WHILE循环
图18 CONTINUE用在REPEAT循环
示例
图19 CONTINUE示例
下表展示了计算结果:
变量 | 计算结果 |
---|---|
"DB10".Test[0] | - |
"DB10".Test[1] | - |
"DB10".Test[2] | - |
"DB10".Test[3] | - |
"DB10".Test[4] | - |
"DB10".Test[5] | 1 |
"DB10".Test[6] | 1 |
"DB10".Test[7] | 1 |
如果满足条件 i < 5,则不执行后续值分配 ("DB10".Test[i] := 1)。运行变量 (i) 以增量"1"递增,然后检查其当前值是否在设定的循环取值范围内。如果执行变量在循环取值范围内,则将再次计算 IF 的条件。
如果不满足条件 i < 5,则将执行后续值分配 ("DB10".Test[i] := 1) 并开始一个新循环。在这种情况下,执行变量也会以增量"1"进行递增并接受检查。
说明:使用"立即退出循环"指令,可以随时取消 FOR、WHILE 或 REPEAT 循环的执行,而无需考虑是否满足条件,并在循环结束(END_FOR、END_WHILE 或 END_REPEAT)后继续执行程序。
该指令将影响其所在的程序循环。
图20 EXIT语句
示例
图21 EXIT示例
下表展示了计算结果:
变量 | 计算结果 |
---|---|
"DB10".Test[0] | 1 |
"DB10".Test[1] | 1 |
"DB10".Test[2] | 1 |
"DB10".Test[3] | 1 |
"DB10".Test[4] | 1 |
"DB10".Test[5] | 1 |
"DB10".Test[6] | - |
"DB10".Test[7] | - |
如果满足条件 i > 5,则将取消循环执行。程序将从 END_FOR 后继续执行。
如果不满足条件 i <= 5,则将执行后续值分配 ("DB10".Test[i] :=1) 并开始一个新循环。将运行变量 (i) 以 1 进行递增,并进行检查该变量的当前值是否在程序中设定的循环取值范围之内。如果执行变量 (i) 在循环取值范围内,则将再次计算 IF 的条件。
说明:使用"跳转"指令,可以从标注为跳转标签的指定点开始继续执行程序。
跳转标签和"跳转"指令必须在同一个块中。在一个块中,跳转标签的名称只能指定一次。每个跳转标签可以是多个跳转指令的目标。不允许从"外部"跳转到程序循环内,但允许从循环内跳转到"外部"。
注意:
LAD/FBD语言内的SCL段,不能使用GOTO指令。
跳转标签遵循以下语法规则:
可按如下方式声明此指令:
GOTO <跳转标签>;
...
<跳转标签>: <语句>
示例
图22 GOTO示例
下表展示了每个操作数数值对目标变量的变化影响:
操作数 | 值 | |||||||
---|---|---|---|---|---|---|---|---|
Tag_Value | 1 | 2 | 3 | 其他 | ||||
初始值 | 结束值 | 初始值 | 结束值 | 初始值 | 结束值 | 初始值 | 结束值 | |
Tag_1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
Tag_2 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 |
Tag_3 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 |
Tag_4 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 |
根据"Tag_Value"操作数的值,程序将从对应的跳转标签标识点开始继续执行。例如,如果"Tag_Value"操作数的值为 2,则程序将从跳转标签"MyLABEL2"开始继续执行。在这种情况下,将跳过"MyLABEL1"跳转标签所标识的程序行。
说明:使用"退出块"指令,可以终止当前处理块中的程序执行,并在调用块中继续执行。
如果该指令出现在块结尾处,则可以跳过。
图23 RETURN语句
示例
图24 RETURN示例
如果"Tag_Error"操作数的信号状态不为 0,则将终止当前处理块中的程序执行。
正常监视如图1所示,无法监控到循环程序内部的执行情况。
图1 监视页面
①点击监视按钮
②可以看到FOR循环内部没有任何变量显示
如果希望监视循环内部执行情况,可以在监视中的SCL程序任意位置,如图2中操作。
图2 点击监视循环
激活监视循环后,跳出窗口如图3所示,点击按钮“是”。
图3 警告窗口
之后,就可以如图4所示的,看到循环内的情况,不过这会造成增加CPU循环时间,并且只能监控到第一个循环。
图4 监视循环
通过CASE OF指令,可以比较容易实现类似顺控的功能,并且编程方法便捷、可读性较好。可以使用类似于下面的编程方式实现类似顺控的功能:
CASE 步骤号 OF //Int类型步骤号,一般位于FB的Static 0: 步骤0 逻辑编程 //一般初始步不执行具体操作,只是初始化,然后是等待开始 IF 条件 THEN 步骤号:=1; ELSIF 错误 THEN 步骤号:=100; END_IF;
1: 步骤1 逻辑编程 置位复杂指令i.REQ IF 复杂指令i.DONE THEN 复位复杂指令i.REQ 步骤号:=2; ELSIF 复杂指令i.ERROR 复位复杂指令i.REQ 步骤号:=100; END_IF;
2: 步骤2 逻辑编程 置位复杂指令m.REQ IF 复杂指令m.DONE THEN 复位复杂指令m.REQ 步骤号:=3; ELSIF 复杂指令m.ERROR 复位复杂指令m.REQ 步骤号:=100; END_IF;
. . .
n: 步骤n 逻辑编程 置位复杂指令x.REQ IF 复杂指令x.DONE THEN 复位复杂指令x.REQ 步骤号:=n+1; ELSIF 复杂指令x.ERROR 复位复杂指令x.REQ 步骤号:=100; END_IF; . . . 100: 错误处理 逻辑编程 步骤号:=0 END_CASE;
复杂指令0 //复杂指令调用 复杂指令1 . . . 复杂指令n
输出Busy、Done、Status等
复杂指令一般包含:通信、运动控制、读配方、写数据日志、读写数据记录、定时器等异步指令,这些指令通常不放在CASE语句的逻辑中,而是在最后统一调用。
一般通过复杂指令完成位、错误位等作为跳转条件。如果是定时器,也可以通过判断时间是否到达作为跳转条件。
例子:使用CASE OF指令编程运动控制,第一步相对运动以200mm/s的速度移动10000mm,第二步速度控制以100mm/s的速度移动15s,第三步停止。
图5为FB块的参数部分,图6为程序。
图5 FB参数
图6 源程序
可以将SCL编写的块,或者全局DB以及UDT导出成源文件,可以导出块或UDT,也可以导出所关联嵌套的块或者UDT,如图7所示。
外层块 | |||||||
---|---|---|---|---|---|---|---|
SCL编写 OB/FC/FB | 全局DB | UDT | 背景DB | 工艺DB | PLC变量 | ||
嵌套 | 无 | 可以导出 | 可以导出 | 可以导出 | 可以导出但没有变量 | 不可以导出 | 不可以导出 |
UDT | 可以导出 | 可以导出 | 可以导出 | 可以导出但没有变量 | 不可以导出 | 不可以导出 | |
SCL编写 FC/FB | 可以导出 | - | - | - | - | - | |
背景DB | - | - | - | 可以导出但没有变量 | - | - |
导出方式参见图7。
图7 导出源文件
通过选择“仅所选块”导出当前块,即表中绿色底色的部分。通过选择“包含所有关联块”,导出嵌套的UDT、程序块,即表中红色底色的部分。
导入源文件方式如图8-9所示。
图8 导入源文件
图9 从源生成块
通过导入的方式可以导入单独内容的源文件,也可以导入包含多个内容的源文件。
在TIA PORTAL V15.1之前,SCL块的接口方式和其他编程语言是一致的。从V15.1开始,SCL块的接口方式可以修改成和经典STEP7相同的方式,操作方式如图10所示。
图10 块接口设置
①在TIA PORTAL选项中选择设置
②左边选择“SCL(结构化控制语言)”
③在块接口选择“文本视图”,此设置默认选择表格视图。设置完,再新建的SCL块即使用所选择的视图。之前新建的SCL块不变。
如图11所示为文本视图的SCL。
图11 文本视图SCL
如图12-13所示,在LAD/FBD中的SCL编写GOTO指令时会编译报错,所以不要在这里编写GOTO指令。建议在LAD/FBD中的SCL不要使用过于复杂的编程,如果需要实现较为复杂的程序,建议单独把SCL组织成为一个子程序,然后在LAD/FBD中调用。
图12 编译报错
图13 语法错误