结构式文件编程语言 (Structured Text) 也称为ST语言,是IEC 61131-3标准定义的语言之一,属高阶设计语言,可以执行多种操作,例如调用功能、功能块、赋值、有条件的执行语句和重複任务等,因此ST适用于完成较複杂的运算。ST编程语言由各种元素组成,具体如下。
註解
註解多用于註记一些文字,以提高后续代码的维护性。它并不占用任何容量与影响执行结果。撰写註解的方式共区分单行、多行与区块几种方式。
单行註解
i := i + 1 // comment;
区块註解
ADD(a (* comment *) , b);
多行註解
(* start comment ... end comment*) i := i + 1;
名词解释
操作符与表示式
ST语言内的操作符与许多高阶语言皆十分相似,多用于数据的处理。而由操作数与操作符组合的结构我们称之为「表示式」,它在计算之后即获得返回值。下表表列ST所有可使用的操作符,并按其优先级进行排序(由高至低)。
操作符 | 含意 | 优先级 | 适用的操作数 | 范例 |
( ) | 最高优先级的括号 | 最高 | 表示式 |
A := 1 + 2 * 3; // A = 7 B := (1 + 2) * 3; // B = 9 |
Function | 函式调用 | 运算式、变数或常数,其数据型态主要依据函式引述的定义。 | A := ADD(1,2) * 3; // A = 9 | |
– | 取反 | INT、DINT或REAL48 的表示式、变数或常数。 |
A := 4; B := – A; // B = -4 |
|
NOT | BOOL 的表示式、变数或常数。 |
A := TRUE; B := NOT A; // B = FALSE |
||
** | 幂 | [REAL48] ** [INT] | A := 2.0 ** 2; // A = 4.0 | |
* | 乘 | INT、DINT或REAL48 的表示式、变数或常数。 | A := 2 * 3; // A = 6 | |
/ | 除 | A := 6 / 3; // A = 2 | ||
MOD | 模除 | INT或DINT的表示式、变数或常数。 | A := 5 MOD 2; // A = 1 | |
+ | 加 | INT、DINT或REAL48 的表示式、变数或常数。 | A := 1 + 2; // A = 3 | |
– | 减 | A := 1 – 2; // A = -1 | ||
= | 等于比较 | BOOL、INT、DINT或REAL48 的表示式、变数或常数。 | A := 5 = 2; // A = FALSE | |
<> | 不等于比较 | A := 5 <> 2; // A = TRUE | ||
> | 大于比较 | A := 5 > 2; // A = TRUE | ||
< | 小于比较 | A := 5 < 2; // A = FALSE | ||
>= | 大于或等于比较 | A := 5 >= 2; // A = TRUE | ||
<= | 小于或等于比较 | A := 5 <= 2; // A = FALSE | ||
& | 逻辑与 | BOOL 的表示式、变数或常数。 |
// A = FALSE A := TRUE & FALSE; |
|
AND |
// A = FALSE A := TRUE AND FALSE; |
|||
XOR | 逻辑异或 | BOOL 的表示式、变数或常数。 |
// A = TRUE A := TRUE XOR FALSE; |
|
OR | 逻辑或 | 最低 | BOOL 的表示式、变数或常数。 |
// A = TRUE A := TRUE OR FALSE; |
语句
语句是构成ST程序的基本单位,每项语句的最末皆以分号符号「;」表示结束。因此,一个语句可以分成数行编写,同时也可以将多个语句编写在同一行,只需在语句结束用分号隔开即可。
:= 赋值语句
表示式在经运算后会获得返回值,然而如何将其值指派给指定变数,我们可以採用赋值操作符与语句来达成这件事。赋值运算式的结构以赋值操作符 「:=」为主,左边置放目标变数,然后右边则为来源变数、常数或会含返回值的表示式。
赋值操作的目标与来源需属同样的数据型态。编译器会于运行时检查此规则并于错误时给予告警。
A := 10; B := A + 7; // B = 17 fA := INT_TO_R48(B); // "B" Data Type is INT, "fA" Data Type is REAL48
条件语句
条件语句的目的在于做决定,在ST语言中有两种条件语句可以使用,分别为IF与CASE。
IF
IF语句的特性为根据布林表示式的回传值(TRUE/FALSE)决定是否执行内部的语句组,是(TRUE)则执行,反之亦然。
IF [BOOL Expression] THEN <Statements>; END_IF ;
通常我们也会搭配ELSE来处理当布林条件式不成立(FALSE)时,执行ELSE内部的语句组。
IF [BOOL Expression] THEN <Statements>; ELSE <Statements>; END_IF ;
当有多个条件的需求时则可使用ELSIF,也就是说当条件不成立(FALSE)时会再判断下个ELSIF内的布林表示式,一旦成立(TRUE)则执行对应的语句组,反之则再判断下个ELSIF或是执行ELSE语句组。
IF [BOOL Expression] THEN <Statements>; ELSIF [BOOL Expression] THEN <Statements>; ELSE <Statements>; END_IF ;
如下范例,IF语句最终会将变数a设定为4。
i := 2 ; IF i = 0 THEN a := 1; // i = 0, a = 1 ELSIF i = 1 THEN a := 2; // i = 1, a = 2 ELSE a := 4; // other, a = 4 END_IF ;
CASE
条件语句的另一种选择为CASE语句,但不同于IF语句,它的条件是採用数字表示式,因此很适用于某些用途。
CASE [numeric expression] OF [result1]: <Statements> [resultN]: <Statemtents> ELSE <Statements> END_CASE;
一个简单的CASE语句范例如下:
STEP := 3; CASE STEP OF 1: a := a+1; 2: a := a+2; 3: a := a+3; ELSE a := 0; END_CASE;
循环语句
执行循环是编程过程中常见的方式,举凡资料搬移、数值累加…等情境下都会运用到循环语句。
根据条件或计数,循环内的语句组将有机会重複运行直到条件或计数次数达指定条件
在ST语言裡分别提供 FOR、WHILE与REPEAT三种循环语句。当条件成立时FOR与WHILE将重複运行内部语句组,但与其相反的REPEAT则是一但条件成立即停止循环。
FOR
具体的指定预循环次数是FOR语句的特点。把一变数当计数使用,该计数当未达指定值时将持续执行内部的语句组。
FOR count := initial_value TO final_value BY increment DO <statement>; END_FOR;
initial_value : 计数变数的初始值。
final_value :计数终点值,当计数变数超出该值时则停止循环。
increment : 每次迭代时的累加值。 在省略 BY 关键字时,编译器会自动将 increment 设为 1 , 也因此计数变数将在每次循环时累加1。
FOR i := 0 TO 10 DO sum := sum + i; END_FOR; // sum = 55
多数情境下,我们应避免于FOR语句内中串改计数变数的数值,以防止造成不可预期的的循环次数。
WHILE
当布林条件成立(TRUE)时WHILE语句将不断的执行内部的语句组,直到条件不成立(FALSE)离开循环。
WHILE [boolean expression] DO <statement>; END_WHILE;
简单的使用方式如下
i := 0; WHILE i <= 10 DO sum := sum + i; i := i + 1; END_WHILE;
REPEAT
REPEAT正好与WHILE相反,循环会一值持续到布林条件成立(TRUE)即停止。
REPEAT <statement>; UNTIL [boolean expression] END_REPEAT;
其他语句
EXIT
不管循环语句是否已满足结束条件,EXIT语句可用于中断循环过程。
如果 EXIT 坐落于于多层的循环语句内,则退出循环仅發生在第一个遇到的循环语句(向外寻找)。
FOR i := 1 TO 3 DO FOR j := 1 TO 5 DO IF FLAG THEN EXIT; END_IF; SUM := SUM + j; END_FOR; END_FOR;
RETURN
提供从函式、功能块或程序的出口。如下范例,函式将在某条件成立时立即返回,因此在RETURN后的代码将不再执行。
FOR i := 0 TO 360 DO IF FLAG THEN RETURN; END_IF; X := a * COS(i); Y := b * SIN(i); END_FOR;
以下内容属ServoMotion扩充支援的部分,可能与IEC61131-3规格略有不同
调用 (Funtion/物件)
透过调用语句来呼叫函式或物件功能。
a. 函式支援命名空间
命名空间又称函式库名称,在同个命名空间下不允许有重複的函式名称,换言之,如果有想保留相同命名的函式需求,可将他们分别定义在不同的命名空间。
ASD:SET_MODE(X_AXIS, PATH); ASD:JOG(X_AXIS, 200, 200, 100000);
函式的调用需依指定规则撰写 : [函式库名称]:[函式名称](引述1,引述2, … ,引述n); ,但调用基本函式库中的函式则是能省略库名称 ,如下:
a := BASIC:SIN(0); a := SIN(0);
b. 支援Multi-Output
填入函式引述时请注意,由于函式支援多个VAR_OUTPUT参数,调用上可以针对VAR_OUTPUT的参数选择全填或全省略,而函式表示式本身的回传值是第一个VAR_OUTPUT参数。
//DIV([input1],[inpout2],[output1],[output2]) DIV(5, 3, 商, 馀); //取得'商'与'馀' 商 := DIV(5, 3); //取得'商',忽略'馀' result := DIV(5, 3, 商, 馀); //取得'商'与'馀',且result = 商
填写引述时由左至右的顺序排列为 : VAR_INPUT → VAR_IN_OUT → VAR_OUTPUT,务必依照该顺序方能正确传入参数至函式。
使用 MSM语言
部分情境下也许是效能、习惯与功能支援度等考量,你可在高阶语言(ST)中穿插低阶的MSM语言,如下演示:
nINC := Var1 * 10000 + Var2; MSM(" SELECT X_AXIS"); //SELECT指令操作 MSM(" PINC nINC"); //PINC指令操作 MSM("LABEL1:"); //标籤LABEL1
依据MSM语言的规则,每行代码的起头若有含空白符号则表示为指令(Instruction),反之则为标籤(Label)。