SCL入门教程

SCL介绍

SCL 编程语言

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 个操作数,那么可根据以下条件来确定结果的数据类型:

  • 如果这 2 个操作数均为有符号的整数,但长度不同,那么结果将采用长度较长的那个整数数据类型(例如,Int + DInt = DInt)。

  • 如果这 2 个操作数均为无符号整数,但长度不同,那么结果将采用长度较长的那个整数数据类型(例如,USInt + UDInt = UDInt)。

  • 如果一个操作数为有符号整数,另一个为无符号整数,那么结果将采用另一个长度较大的有符号数据类型(其包含此无符号整数)(例如,SInt + USInt = Int)

  • 如果一个操作数为整数,另一个为浮点数,那么结果将采用浮点数的数据类型(例如,Int + Real = Real)。

  • 如果 2 个操作数均为浮点数,但长度不同,结果将采用长度较长的那个浮点数的数据类型(例如,Real + LReal = LReal)。

  • 对于操作数为'Time'和'日期和时间'数据类型组,运算结果的数据类型请参见表1。

算术表达式的数据类型

表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。

编写关系表达式时,请注意以下规则:

  • 以下数据类型组中的所有变量都可以进行比较:

    • 整数/浮点数

    • 位、位序列

    • 字符串

  • 对于以下数据类型,只能比较相同类型的变量:

    • TIME

    • 日期和时间

    • UDT

    • Array

    • Struct

    • Variant

  • String 比较是对以 Windows 字符集编码的字符进行比较;而 WSting比较则是对 UTF-16 编码的字符进行比较。在比较过程中,将比较变量的长度及各字符对应的数值。

  • Array 比较需要数组维度、数组元素数据类型与数量完全相同

  • UDT、Array、Struct、Variant等进行的比较只能使用S7-1200 V4.2及其以上的版本。

关系表达式的数据类型

表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;

赋值运算

定义:通过赋值运算,可以将一个表达式的值分配给一个变量。赋值表达式的左侧为变量,右侧为表达式的值。

函数名称也可以作为表达式。赋值运算将调用该函数,并返回其函数值,赋给左侧的变量。

赋值运算的数据类型取决于左边变量的数据类型。右边表达式的数据类型必须与该数据类型一致。

赋值运算的计算按照从右到左的顺序进行。

可通过以下方式编程赋值运算:

  • 单赋值运算:执行单赋值运算时,仅将一个表达式或变量分配给单个变量:

    示例:a := b;

  • 多赋值运算:执行多赋值运算时,一个指令中可执行多个赋值运算。

    示例:a := b := c;

    此时,将执行以下操作:

    b := c;

    a := b;

  • 组合赋值运算:执行组合赋值运算时,可在赋值运算中组合使用操作符'+'、'-'、'*'和'/':

    示例:a += b;

    此时,将执行以下操作:

    a := a + b;

    也可多次组合赋值运算:

    a += b += c *= d;

    此时,将按以下顺序执行赋值运算:

    c := c * d;

    b := b + c;

    a := a + 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块变量:'DB块名称'(.'变量名称')

    • PLC变量:变量名称

    • 局部变量:#变量名称

  • 地址寻址

    • DB块变量:%DB块号(.变量地址),TIA PORTAL软件会判断该地址有没有对应符号名称,如果有则立即转换为符号名称,没有则保留绝对地址

    • PLC变量:%变量地址,TIA PORTAL软件会判断该地址有没有对应符号名称,如果有则立即转换为符号名称,没有则新建符号名称

    • Temp变量:SCL支持非优化FC/FB的Temp变量的地址寻址

举例:

    符号名 说明
符号寻址 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调用

  • FB调用

  • FB多重背景调用

调用可以从指令列表或者项目树程序块中拖拽入程序编辑区域,也可以直接输入。

FC调用

FC调用的格式是

  • '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

有两种方式新建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编写会更加方便,逻辑条理也更加清晰。

IF:条件执行

说明:使用'条件执行'指令,可以根据条件控制程序流的分支。该条件是结果为布尔值(True 或 False)的表达式。可以将Bool变量、逻辑表达式或比较表达式作为条件。

执行该条件执行指令时,将对指定的表达式进行运算。如果表达式的值为 True,则表示满足该条件;如果其值为 False,则表示不满足该条件。

参数

根据分支的类型,可以对以下形式的指令进行编程:

  • IF...THEN... 分支:

    IF <条件>

    THEN <语句1>

    END_IF;

图4 IF...THEN... 分支

如果满足该条件,则将执行 THEN 后编写的指令。如果不满足该条件,则程序将从 END_IF 后的下一条指令开始继续执行。

  • IF...THEN... ELSE...分支:

    IF <条件>

    THEN <语句1>

    ELSE <语句2>

    END_IF;

图5 IF...THEN... ELSE...分支

如果满足该条件,则将执行 THEN 后编写的语句。如果不满足该条件,则将执行 ELSE 后编写的语句。不论执行哪一个语句,之后都将从 END_IF 后的下一条指令开始继续执行。

  • IF...THEN... ELSIF...分支:

    IF <条件1>

    THEN <语句1>

    ELSIF <条件2>

    THEN <语句2>

    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:创建多路分支

说明:使用'创建多路分支'指令,可以根据数字表达式的值执行多个指令序列中的一个。

按如下方式声明此指令:

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 后编写的指令。如果两个值不相等,则执行这些指令。

* 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

FOR:在计数循环中执行

说明:使用'在计数循环中执行'指令,重复执行程序循环,直至运行变量不在指定的取值范围内。

也可以嵌套程序循环。在程序循环内,可以编写包含其它运行变量的其它程序循环。

通过指令'复查循环条件'(Continue),可以终止当前正在运行的程序循环。通过指令'立即退出循环'(Exit)终止整个循环的执行。

注意:

有关运行次数和运行变量的信息:

程序运行时无法更改运行次数。出于性能原因,应在块接口的'Temp'部分中声明运行变量。在循环中,该运行变量无法更改。

按如下方式声明此指令:

FOR <运行变量> := <起始值> TO <结束值> BY <增量> DO

<语句>;

END_FOR;

如果增量为1,可以简写为:

FOR <运行变量> := <起始值> TO <结束值> DO

<语句>;

END_FOR;

图10 FOR语句

下表列出了该指令的参数:

参数

数据类型

存储区

说明

<运行变量>

有符号整数、无符号整数*

I、Q、M、D、L

执行循环时会计算其值的操作数。执行变量的数据类型将确定其它参数的数据类型。

<起始值>

I、Q、M、D、L

表达式,在运行变量首次执行循环时,将为运行变量分配该表达式的值。

<结束值>

I、Q、M、D、L

表达式,在运行程序最后一次循环时会为运行变量分配该表达式的值。在每个循环后都会检查运行变量的值:

  • 未达到结束值:
    执行符合 DO 的语句

  • 达到结束值:
    最后执行一次 FOR 语句

  • 超出结束值:
    完成 FOR 循环

执行该指令期间,不允许更改结束值。

<增量>

I、Q、M、D、L

表达式,根据增量表达式的值,执行变量在每次循环后都会递增(正增量)或递减(负增量)自身变量值。

如果未指定增量,则在每次循环后执行变量的值加 1。

执行该指令期间,不允许更改增量。

<语句>

-

只要运行变量的值在取值范围内,每次循环都就会执行的语句。取值范围由起始值和结束值定义。

*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

WHILE:满足条件时执行

说明:使用'满足条件时执行'指令可以重复执行程序循环,直至不满足执行条件为止。该条件是结果为布尔值(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

REPEAT:不满足条件时执行

说明:使用'不满足条件时执行'指令可以重复执行程序循环,直至不满足执行条件为止。该条件是结果为布尔值(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

CONTINUE:复查循环条件

说明:使用'复查循环条件'指令,可以结束 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'进行递增并接受检查。

EXIT:立即退出循环

说明:使用'立即退出循环'指令,可以随时取消 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 的条件。

GOTO:跳转

说明:使用'跳转'指令,可以从标注为跳转标签的指定点开始继续执行程序。

跳转标签和'跳转'指令必须在同一个块中。在一个块中,跳转标签的名称只能指定一次。每个跳转标签可以是多个跳转指令的目标。不允许从'外部'跳转到程序循环内,但允许从循环内跳转到'外部'。

注意:

LAD/FBD语言内的SCL段,不能使用GOTO指令。

跳转标签遵循以下语法规则:

  • 字母(a 至 z,A 至 Z)

  • 字母和数字组合;请必须字母为开始

可按如下方式声明此指令:

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'跳转标签所标识的程序行。

RETURN:退出块

说明:使用'退出块'指令,可以终止当前处理块中的程序执行,并在调用块中继续执行。

如果该指令出现在块结尾处,则可以跳过。

图23 RETURN语句

示例

图24 RETURN示例

如果'Tag_Error'操作数的信号状态不为 0,则将终止当前处理块中的程序执行。

常见问题

问题1:如何监视循环指令?

正常监视如图1所示,无法监控到循环程序内部的执行情况。

图1 监视页面

①点击监视按钮

②可以看到FOR循环内部没有任何变量显示

如果希望监视循环内部执行情况,可以在监视中的SCL程序任意位置,如图2中操作。

图2 点击监视循环

激活监视循环后,跳出窗口如图3所示,点击按钮“是”。

图3 警告窗口

之后,就可以如图4所示的,看到循环内的情况,不过这会造成增加CPU循环时间,并且只能监控到第一个循环。

图4 监视循环

问题2:CASE指令如何实现顺控功能?

通过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 源程序

问题3:如何导入导出SCL源文件?

可以将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 从源生成块

通过导入的方式可以导入单独内容的源文件,也可以导入包含多个内容的源文件。

问题4:如何使用经典Step7的接口型式

在TIA PORTAL V15.1之前,SCL块的接口方式和其他编程语言是一致的。从V15.1开始,SCL块的接口方式可以修改成和经典STEP7相同的方式,操作方式如图10所示。

图10 块接口设置

①在TIA PORTAL选项中选择设置

②左边选择“SCL(结构化控制语言)”

③在块接口选择“文本视图”,此设置默认选择表格视图。设置完,再新建的SCL块即使用所选择的视图。之前新建的SCL块不变。

如图11所示为文本视图的SCL。

图11 文本视图SCL

问题5:为什么GOTO指令会编译报错?

如图12-13所示,在LAD/FBD中的SCL编写GOTO指令时会编译报错,所以不要在这里编写GOTO指令。建议在LAD/FBD中的SCL不要使用过于复杂的编程,如果需要实现较为复杂的程序,建议单独把SCL组织成为一个子程序,然后在LAD/FBD中调用。

图12 编译报错

图13 语法错误

(0)

相关推荐

  • SCL语言基本语法规则:表达式

    SCL:Structured Control Language,结构化控制语言. SCL是一种类似于计算机高级语言的编程方式,只是这种语言编写的程序,可以在PLC中运行.如果学过C语言或者VB语言,就 ...

  • 显微镜下的 i 与 i

    低并发编程,周一很颓废,周四很硬核 注意,以下讨论的语言是 Java 这个问题被网上的好多文章写烂了,但基本重复度很高,我看过后的感觉是,大部分都是错误的.误导读者的. 随便百度一下,我们打开第一条. ...

  • 前端教程:JavaScript运算符

    简单的答案可以使用表达式4+5等于9.在这里,4和5被称为操作数:+被称为运算符.JavaScript语言支持下列类型的运算符. 算术运算符 比较运算符 逻辑(或关系)运算符 赋值运算符 有条件的(或 ...

  • C语言标准头的使用,C语言入门教程,你我的好帮手

    每个标准库函数都会被声明在一个或多个标准头(standard header)中.这些标准头也包括了 C 语言标准提供的所有宏和类型的定义. 每个标准头都包含一组相关的函数声明.宏和类型定义.例如,数学 ...

  • 沿用上百年的楷书入门教程,看过都说好!

    .................................................................................................... ...

  • 电路板维修入门教程

    (一)          电容篇 1.电容在电路中一般用"C"加数字表示(如C25表示编号为25的电容). 电容是由两片金属膜紧靠,中间用绝缘材料隔开而组成的元件.电容的特性主要是 ...

  • 国画入门教程:山石的画法

    山石是山水画最基本的内容,石是山的局部,山石的绘画,要经过勾.皴.擦.点.染等几个基本步骤或再增加提的程序. 今天我们就来讲讲几种皴的画法,帮助大家学习一下. 批麻皴 01 披麻皴,是山水画皴法之一, ...

  • 光功率计快速入门教程,光功率计使用方法图解

    光功率计快速入门教程 一.按键说明 1 . DET 删除数据键:   删除测量过的数据 2 . dBm /  W  REL 键:测量结果的单位转换,每按一次此键,显示方式在   " W &q ...

  • 笔法、笔势,练的是手上的功夫!(详细入门教程)

    笔法.笔势是蕴含在点画书写中的规律性技法,是真.草.隶.篆.行各体都用的着的技法,提炼出转.折.提.按.中锋.侧锋.入笔.行笔.收笔等关键的笔法.笔势,有意识的.逐个的加以强化日常训练.或集中练习.反 ...

  • 【组队学习】【25期】Web开发入门教程

    Web开发入门教程 开源内容: https://github.com/datawhalechina/whale-web 基本信息 贡献人员:张梁.王晓亮.何锋丽.张少波.谢文昕 学习周期:16天 学习 ...

  • Python爬虫入门教程(十四):爬取有声小说网站数据

    前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理. Python爬虫.数据分析.网站开发等案例教程视频免费在线观看 https://space. ...

  • 奇门遁甲最全入门教程

    看本文需要了解天干地支和阴阳五行,奇门遁甲的学习必须掌握节气历法. 奇门遁甲之由来:约5000年前黄帝创始---360天/年*12时辰/天*1局/时辰=4320局/年风后简之---4320局/年/4= ...