本章主要知识点
掌握五种语言的编程结构
很多学者在学习 MetaFacture 的过程中常会问一个问题,哪种编程语言最好?
其实,没有哪种编程语言是绝对的好或不好,不同的工程应用具有不同的最佳编程方式,每种编程语言都具有其不同的特点,可根据实际工程应用的需求选用合适的编程语言,下面简单介绍下MetaFacture 的 6 种不同语言的特点。
-
梯形图(LD):与电气操作原理图相对应,其优点它的直观性,电气技术人员易于掌握和学习。缺点是在应对复杂的控制系统编程时往往程序描述性不够清晰。梯形图在国内的工业自动化领域中是使用最多的一种 PLC 编程语言。
-
功能块图(FBD):以功能块为设计单位,能从控制功能入手,优点是使控制方案的分析和理解变得容易,功能块具有直观性强、容易掌握的特点,有较好的操作性。在应对复杂控制系统时仍可用图形方式清晰描述。缺点是每种功能块要占用程序存储空间,并延长程序执行周期。
-
指令表(IL):优点是易于记忆及掌握,与梯形图(LD)有对应关系,便于相互转换和对程序的检查,且编程及调试时不受屏幕大小的限制,输入元素不受限制。缺点和梯形图一样,对复杂系统的程序描述不够清晰。
-
结构化文本(ST):优点是可实现复杂运算控制,对编程人员的技能要求高,其缺点是编译时需要将代码转换为机器语言,会导致编译时间长、执行速度慢,且直观性和易操作性差。
-
顺序流程功能图(SFC):已完成的功能为主线,优点是操作过程条理清楚,便于对程序操作过程的理解和思路;对大型程序可分工设计,采用较灵活的程序结构,节省程序设计时间和调试时间,由于只对活动步进行扫描,因此,可缩短程序执行时间。
-
连续功能图(CFC):实际上是功能块图(FBD)的另一种形式。在整个程序中可自定义运算块的计算顺序,易于实现大规模、数量庞大但又不易细分功能的流程运算。在连续控制行业中,得到大量使用。
编程语言的多样性是 MetaFacture 一大优点。所以在实际的工程项目中,从优化程序和编程便利性的角度建议大家,涉及到算法部分请选择 ST 语言,编写的程序往往简洁而高效;涉及到流程控制部分,请选择 SFC 语言,编写的程序会条理清晰,逻辑关系不会混乱;涉及到逻辑控制部分,请选择 LD 语言,编写的联锁,互锁等逻辑简单易懂;涉及到功能块部分,请选择 CFC 或者FBD,编写的程序会形成一个网络清晰的网状电路图,易于读懂。当然,在实际的编程时,用户也可以根据自己的使用习惯来选择编程语言,虽然实现的方法不同,但是都能得到同一个结果。
8.1 指令表(IL)
IEC 61131-3 中的指令表 IL(Instruction List)语言是一种低级语言,与汇编语言很相似,是在借鉴、吸收世界范围的 PLC 厂商的指令表语言的基础上形成的一种标准语言,可以用来描述功能,功能块和程序的行为,还可以在顺序功能流程图中将动作和转变的行为。
指令表语言能用于调用,如有条件和无条件地调用功能块和功能,还能执行赋值以及在区段内执行有条件或无条件的转移。指令表语言不但简单易学,而且非常容易实现,可不通过编译就可以下载到 PLC。指令表编程语言常常被作为基础编程语言,其他编程语言能够方便的转换为指令表语言。但是指令表编程语言对大型的复杂控制问题缺少有效的工具,因此,在大型复杂的控制问题中,通常不采用指令表编程语言。
8.1.1 指令表编程语言简介
-
简介
指令表语言是由一系列指令组成的语言。每条指令在新一行开始,一条完整的指令由操作符和紧随其后的操作数组成,操作数是指在 IEC 61131-3 的“公共元素”中定义的变量和常量。有些操作符可带若干个操作数,这时各个操作数用逗号隔开。指令前可加标号,后面跟冒号,在操作数之后可加注释。指令表 IL 编辑器的编程界面如图 8.1 所示。
指令表语言是一种面向行的语言,类似于汇编语言。一条指令是 PLC 可执行的一项命令,它严格要求有一个行来描述,也允许空白行形式的空指令。
指令表编程语言的特点是:
-
指令表编程语言的指令具有简单易学的特点。适用于小型较简单控制系统的编程
-
操作符被用于操纵所有基本数据类型的变量、调用函数和功能块。
-
指令表编程语言的是能够直接在 PLC 内部解释的语言,适用于大多数 PLC 制造商。
-
大多数指令表编程语言编写的程序要在运行期才能检出程序出错。
-
指令表编程语言的编写较难转换到其他编程语言,其他编程语言编写的程序容易转换到指令表编程语言。
-
程序执行顺序
指令表编程语言的执行过程是从上至下的顺序进行执行,如图 8.1 所示。

图 8.1 指令表 IL 编辑器中的编程
样例代码请参考样例程序\第8章\01_IL_Basic\中。
-
指令的格式
在指令表编程语言中,指令具有如下的格式:
标号:操作符/函数 操作数 注释
【例 8.1】使用指令表实现电机的起保停控制。

例 8.1 中的程序用于对某设备的电机进行起保停控制。程序中,标号为 START,指令第 1 行将变量 bStart 的结果存放至累加器中。第 2 行的指令用于将第 1 行指令的结果和 bHold 输出保持信号进行或逻辑运算,结果仍覆盖到累加器中。第 3 行指令用于将第 2 行运算结果和停止信号 bStop 进行取反后的逻辑与运算,结果仍存放在累加器中。第 4 行指令用于将当前累加器中的结果输出至变量 bDone 中。
8.1.2 连接元素
指令表包含一系列指令,每个指令在新一行开始,包含操作符,根据操作的类型,一个或多个操作域用逗号分开,操作符可以用修饰符扩展。表8-1 所示的操作符和修饰符。
表8-1 操作符及修饰符含义
| 操作符 | 修饰符 | 含 义 | 举 例 |
| ST | N | 将累加器中的数(取反)存入操作数变量中 | ST iErg |
| S | N | 当累加器中的数为真,将操作数(布尔型)设为真 | S iVar1 |
| R | N | 当累加器中的数为假,将操作数(布尔型)设为真 | R bVar1 |
| AND | N.( | 累加器中的数和(取反的)操作数逐位进行与运算 | AND bVar2 |
| OR | N.( | 累加器中的数和(取反的)操作数逐位进行或运算 | OR iVar2 |
| XOR | N.( | 累加器中的数和(取反的)操作数逐位进行异或运算 | XOR N.(bVar1, bVar2) |
| NOT | 累加器中的数逐位取反 | NOT | |
| ADD | ( | 将累加器中的数和操作数相加,其结果复制到累加器中 | ADD (iVar1, iVar2) |
| SUB | ( | 累加器中的数减去操作数,其结果复制到累加器中 | SUB iVar2 |
| MUL | ( | 累加器中的数和操作数相乘,其结果复制到累加器中 | MUL iVar2 |
| DIV | ( | 累加器中的数除以操作数,其结果复制到累加器中 | DIV 44 |
| GT | ( | 检查累加器中的数是否大于操作数,其结果(布尔型)复制到累加器中 | GT 23 |
| GE | ( | 检查累加器中的数是否大于或等于操作数,其结果(布尔型)复制到累加器中 | GE iVar2 |
| EQ | ( | 检查累加器中的数是否等于操作数,其结果(布尔型)复制到累加器中 | EQ iVar2 |
| NE | ( | 检查累加器中的数是否不等于操作数,其结果(布尔型)复制到累加器中 | NE iVar1 |
| LE | ( | 检查累加器中的数是否小于或等于操作数,其结果(布尔型)复制到累加器中 | LE 5 |
| LT | ( | 检查累加器中的数是否小于操作数,其结果(布尔型)复制到累加器中 | LT cVar1 |
| JMP | CN | 无条件(有条件)跳转到标签 | JMPN next |
| CAL | CN | (有条件)调用一个程序或功能块(当累加器中的数为正时) | CAL prog1 |
| RET | 从当前 POU 中返回,跳回到调用的 POU 中 | RET | |
| RET | C | 有条件 — 仅当累加器中的数为真时,从当前 POU 中返回,跳回到调用的 POU 中 | RETC |
| RET | CN | 有条件 — 仅当累加器中的数为假时,从当前 POU 中返回,跳回到调用的 POU 中 | RETCN |
| ) | 评估延迟的操作数 |
|
注意:
|
左圆括号“(”表示操作符的运算被延缓直到遇到右圆括号“)”。因此,对传统 PLC 中的程序块操作,主控操作等都可以采用该操作符实现。
-
操作数
操作数可以直接表示变量或符号的符号变量。例如,
-
LD A:表示设置当前值等于符号变量 A 所对应的数值。
-
AND %IX1.3:表示将当前结果与输入单元 1 的第 3 位进行与逻辑运算,结果作为当前值。
-
JMP ABC:表示当前计算值为布尔值 1 时,从标号 ABC 的位置开始执行。
-
RET:是无操作数的操作符,当执行到该指令时,程序将返回到原断点后的指令处执行。
断点是由于函数调用、功能块调用或中断子程序等造成的。
-
指令
IEC 61131-3 标准的指令表编程语言对传统指令表编程语言进行了总结,取长补短,采用函数和功能块,使用数据类型的超载属性等,使编程语言更简单灵活,指令更简单。其主要优点如下:
-
可调用函数和功能块调用。如定时器和计数器这种功能块指令可以通过标准库在指令表
-
编程语言中直接被调用;
-
数据类型的过载属性使运算变得简单;
-
采用圆括号可以方便的将程序块组合,并实现主控等指令;
-
采用边沿检测属性的方法,对信号设置微分功能,简化了指令集;
-
数据传送指令可以直接用赋值函数 MOVE 实现。
-
操作符
在引入操作符的概念之前,需要介绍一个概念,即累加器,他在指令表编程语言中尤为重要。
指令表编程语言提供了一个存储当前结果的累加器,与传统的可编程控制器使用的累加器不同,这种标准累加器存储位数是可变的,即标准指令表编程语言提供了一种存储位数可变的虚拟累加器,其存储位数取决于正在处理的操作数和数据类型。同样,虚拟累加器的数据类型也可以发生变化,以适应最新运算结果的操作数的数据类型。
指令执行过程中,数据存储采用的方法如下 :
运算结果:=当前运算结果 操作 操作数
因此,在操作符规定的操作下,当前运算结果与操作数进行由操作符规定的操作运算。运算结果作为新的运算将结果存放回当前运算结果的累加器。
-
修饰符
修饰符有三种--“C”、“N” 和 “N,( ”,如表 8-2 中所示,修饰符本身不能独立构成,需要配合之前的操作符才能构成一句完整的语句。
表8-2 修饰符指令列表
| 修饰符 | 使用 | 功能 |
| C | 结合 JMP, CAL, RET 使用 | 本指令仅当前面的表达式结果为真时执行 |
| N | 结合 JMPC, CALC, RETC 使用 | 本指令仅当前面的表达式结果为假时执行 |
| N.( | 其他 | 操作数(而非累加器中的数)取反 |
修饰符 C 表示有关指令只有当运算结果为 TRUE(或当操作符为 FALSE,并与“N”修饰符结合使用时)才执行。修饰符 N 的逻辑与 C 正好相反。
【例 8.2】修饰符示例。
首先,装载 TRUE 至累加器,其次将变量 bVar1 的值取反和累加器的值进行与运算,在此使用了 ANDN 指令,如果使用 AND 则表示直接进行与运算。如果结果为 TRUE,则程序跳转至 m1,反之将变量 bVar2 取反加载至累加器并输出,此条指令使用的是 LDN,也使用了修饰符 N,在此也是取反的意思。
8.1.3 操作指令
指令表编程语言共有 9 大类,其指令说明分别如下。
-
数据存取类指令
数据存取类指令是读取数据存储单元内的操作。标准指令采用 LD 和 LDN 指令表示存取和存取取反指令。编程语言的格式如下:
LD 操作数 //将操作数规定的数据存储单元中的内容作为当前结果存储。
LDN 操作数 //将操作数规定的数据存储单元中的内容取反后作为当前结果存储。
LD 是 Load 的缩写,LDN 是 Load Not 的缩写。
数据存取类指令的操作对象,即 LD 或 LDN 的操作对象,是操作数。它是对操作数对应的数据存储单元内容进行的读取操作。读取的数据被存放在运算结果累加器,该数据也被称为当前值。
对常开触点的数据读取用 LD 指令,对常闭触点的数据读取用 LDN 指令。
与继电器逻辑电路相似,对常开触点,即动点接点,采用存储 LD 指令,例如 ,LD %IX0.0 指令执行存取操作数地址为%IX0.0 接点状态的操作。从寄存器看,该操作过程是把地址为%IX0.0 的输入状态传送到了运算结果累加器。图 8-2 的 a)和 b)为继电器逻辑电路和语句表编程语言指令的示例。
![]() |
![]() |
a ) 继电器逻辑电路 b )语句表编程语言
图 8.2 LD 和 LDN 指令的示例和操作过程

图 8.3 LD 和 LDN 指令的操作过程
图 8.3 为数据存取的执行过程。对常闭接点,即动端接点,采用逻辑取反 LDN 指令,例如 LDN %IX0.1 指令执行存取操作数地址为%IX0.1 接点状态的操作。从寄存器看,该操作过程是把地址为%IX0.1 的输入状态寄存器状态取反,并把取反结果传送到运算结果累加器中。表 8-3 是 LD 和LDN 指令的示例。
表8-3 LD 和 LDN 指令的示例
| 指 令 | 说 明 | 累加器的数据类型 |
| LD FALSE | 当前值等于 FALSE | 布尔量 |
| LD TRUE | 当前值等于 TRUE | 布尔量 |
| LD 3.14 | 当前值等于 3.14 | 实数 |
| LD 100 | 当前值等于 100 | 整数 |
| LD T#0.5s | 当前值等于时间常数 0.5s | 时间数据 |
| LD START | 当前值等于变量 START 的状态 | 根据变量 START 的类型而定 |
-
输出类指令
输出类指令用于将运算结果累加器中的内容传送到输出状态寄存器。标准指令采用 ST 和 STN 指令表示存取和存取取反指令。编程语言的格式如下:
ST 操作数 //将当前结果存储到操作数规定的数据存储单元。
STN 操作数 //将当前结果取反后,存储到操作数规定的数据存储单元。
须指出,在执行 ST 或 STN 指令后,当前运算结果仍被保留在运算结果累加器的存储单元,ST是 Store 的意思,STN 是 Store Not 的缩写。
与继电器逻辑电路相似,对线圈用 ST 指令,例如 ST %QX0.0 指令执行输出到%QX0.0 的线圈的操作:从寄存器看,该操作过程是把运算结果累加器的状态传送到地址为%QX0.0 的输出地址中。图 8-4 的 a)和 b)为继电器逻辑电路和语句表编程语言指令的示例。
![]() |
![]() |
a ) 继电器逻辑电路 b )语句表编程语言
图 8.4 ST 和 STN 指令的示例和操作过程
图 8.5 为数据存取的执行过程。使用 STN %QX0.1 指令执行输出到%QX0.1 失励线圈的操作;该操作过程是把运算结果累加器的状态取反,并把取反的结果传送至输出为%QX0.1 的地址。

图 8.5 ST 和 STN 指令的操作过程
-
置位复位类指令
标准指令集采用 S 和 R 指令表示置位和复位类指令,其编程语言的格式如下:
S 操作数 //当前结果为 False 时,将操作数对应的数据存储单元内容设置为 True,并保持。
R 操作数 //当前结果为 True 时,将操作数对应的数据存储单元内容设置为 False,并保持。
这类指令具有记忆属性。执行 S 操作数后,操作数对应的数据存储单元内容被设置为 True,并且该数据存储单元内容被记忆和保持到执行 R 操作数指令,执行 R 操作数指令使操作数对应的数据存储单元内容被设置为 False。同样,该存储单元的内容要保持到执行 S 操作数的指令,并使其内容设置到 True 为止。
S 和 R 指令可以用 SR 和 RS 功能块的调用实现。与功能块比较,其不同点是:S 指令和 R 指令的执行时根据程序中的先后位置确定执行先后次序,因此,优先级的确定和 RS 和 SR 有所不同。此外,功能块要先设置 S 和 R 端,才能执行调用指令。
S 是 Set 的缩写,R 是 Reset 的缩写。表 8-4 是 S 和 R 指令的示例。
表8-4 S和R指令的示例
| 指 令 | 说 明 |
| SET: LD TRUE | 当前值等于 TRUE |
| S START | 当前值等于 TRUE 时,START 变量置 TRUE 并保持 |
| LD FALSE | 当前值等于 FALSE |
| S STOP | 当前值等于 FALSE 时,STOP 变量置 FALSE 并保持 |
| RESET: LD TRUE | 当前值等于 TRUE |
| R STOP | 当前值等于 TRUE 时,STOP 变量置 FALSE 并保持 |
S 指令有条件的输出 STC 指令,R 表是有条件的输出 STCN 指令。因此,当前结果存储器为 TRUE 时,S 操作数指令执行设置输出操作数为置位操作,同样,R 操作数指令执行设置输出操作数为复位的操作,即置位取反的操作。
-
逻辑运算类指令
标准的逻辑运算有:AND(N)、OR(N)、XOR(N)和 NOT 等。编程语言的格式如下:
逻辑运算操作符 操作数
或
逻辑运算操作符 N 操作数
-
逻辑运算操作符。操作数用于将当前结果存储器内容与操作数对应的数据存储单元内容进行规定的逻辑运算,运算结果作为新的当前结果,存放在当前结果存储器内。
-
逻辑运算操作符 N。操作数用于将当前结果存储器内容与操作数对应的数据存储单元内容的取反结果进行规定的逻辑运算,运算结果作为当前结果,存放在当前结果存储器内。
【例 8.3】电动机控制程序示例。

此例为典型的电机控制程序,输入变量 A,B 和输出变量 C 都是符号变量,须在声明部分对其实际地址的赋值。
-
算术运算类这类
指令包括 ADD、SUB、MUL、DIV 和 MOD 等。编程语言的格式如下:
ADD 操作数//当前结果加操作数对应的数据存储单元内容,运算结果存在当前结果存储器。
SUB 操作数//当前结果减操作数对应的数据存储单元内容,运算结果存在当前结果存储器。
MUL 操作数//当前结果乘操作数对应的数据存储单元内容,运算结果存在当前结果存储器。
DIV 操作数//当前结果除操作数对应的数据存储单元内容,运算结果(商)存在当前结果存储器。
MOD 操作数//当前结果以操作数对应的数据存储单元内容为模进行模除运算结果(取余数),将运算结果存在当前结果存储器。
【例 8.4】温度补补偿系数的运算示例。

例 8.4 中用于对气体流量进行温度补偿,其中 rTem1 是实际温度,单位是℃。程序在第一行读取 273.15;第二行将温度实际值 rTem1 与 273.15 进行累加并作为当前值。第三行将该当前值除以设计温度值,结果存放在当前值存储器;第四行将运算结果作为温度补偿值存放在 rCompensate 中。可以看到,程序中 ADD 和 DIV 的运算都是实数数据类型的运算。样例代码请参考样例程序\第8章\02_ IL_Arithmetic\中。
-
比较运算类
比较指令包括:GT(>)、GE(≥)、EQ(=)、NE(≠)、LE(
GT 操作数//当前操作数>操作数对应数据存储单元内容,运算结果 TRUE 送当前结果寄存器。
GE 操作数//当前操作数≥操作数对应数据存储单元内容,运算结果 TRUE 送当前结果寄存器。
EQ 操作数//当前操作数=操作数对应数据存储单元内容,运算结果 TRUE 送当前结果寄存器。
NE 操作数//当前操作数≠操作数对应数据存储单元内容,运算结果 TRUE 送当前结果寄存器。
LE 操作数//当前操作数
LT 操作数//当前操作数≤操作数对应数据存储单元内容,运算结果 TRUE 送当前结果寄存器。
这类指令用于将他当前结果与操作数对应的数据存储单元内容进行比较,满足操作符规定的比较条件时,当前结果被置为 TRUE,反之为 FALSE。比较累指令将当前结果存储器的数据类型改变为布尔数据类型。使用时需要注意的事项为:
|
注意:
|
【例 8.5】比较运算类指令示例。

例 8.X 中,变量 rRealVar 为过程测量值,当其值大于 50 时,表示测量值超限,红色警报等 bRed 为 TRUE,反之,bGreen 为 TRUE。样例代码请参考样例程序\第8章\ 03_IL_Compare\中。
-
跳转与返回指令
跳转指令为 JMP,返回指令为 RET。两者的编程语言格式如下:
JMP 标号 //跳转到标号的位置继续执行
RET //返回到跳转时的断点后继续执行
跳转指令的操作数是标号,不是操作数对应的数据存储单元地址。
返回指令是没有操作数的指令,用于调用函数、功能块及程序的返回。
JMP 是 Jump 缩写。执行该指令时,如果当前结果为 TRUE,则跳转条件满足,程序在该点中断,并跳转到该标号所在的程序行继续执行。它与 RET 指令配合,用于实现子程序的执行。可以带修饰符 C 或 N,表示根据当前结果存储器内容执行或取反。
RET 是 Return 的缩写。执行该指令后,程序返回,并从原断电后第一条指令开始执行。可以带修饰符 C 或 N,表示根据当前结果存储器内容执行或取反。
|
注意:
|
【例 8.6】跳转指令的示例

例 8.6 用于自动和手动程序的切换控制。当 AUTO 开关切到自动位置,则 AUTO 为 TRUE,程序则会执行跳转指令 JMPC。因此程序跳转到 AUTOPRO 子程序,及执行在自动条件下的有关程序。当跳转条件不满足时,执行 JMP 指令,因此,程序跳转到 MANPRO 子程序,即执行手动操作时的有关程序。
在此需要特别注意的是 AUTOPRO 和 MANPRO 为子程序的标号,并非程序名。
-
调用指令
IEC 61131-3 的标准调用指令为 CAL 指令。编程语言的格式如下:
CAL 操作数 //调用操作数表示的函数、功能块或程序
通过执行该指令,可以调用函数、功能块和程序,使程序结构简洁化,程序描述清晰。调用通用格式如下。
CAL 是 Call 的缩写,表是调用。CAL 指令的操作数是函数名或功能块实例名。实例名中的参数用逗号分隔。
-
圆括号指令
IEC 61131-3 的标准采用圆括号对指令进行修正,即进行优先执行的操作。
左圆括号“(”用于将当前累加器的内容压入堆栈,并将操作符的操作命令存储,这时,堆栈的其他内容向下移一层。右圆括号“)”用于将堆栈最上层的内容弹出,并于当前累加器内容进行对应的操作,操作结果放在当前累加器内,此时,堆栈的内容向上移一层。因此左圆括号被称为操作延迟,它产生的瞬时结果不影响当前累加器。表 8-5 为圆括号的表达特性。
表8-5 圆括号的表达特性
| 序 号 | 描述 / 示例 |
| 1 | 圆括号表达式开始于显示操作符: AND( LD %IX0.1 OR %IX0.2 |
| 2 | 圆括号表示(短格式): AND( LD %IX0.1 OR %IX0.2 |
【例 8.7】圆括号对算术运算操作的修正。

从例 8.7 中,其最终实现的算法为 rVar1+rVar2*(rVar3+rVar4),整个操作过程中,数据类型需保持一致。此外,数据类型被传递。操作从最里层的可圆括号开始,逐层向外操作,直到最外层圆括号。样例代码请参考样例程序\第8章\04_ IL_Bracket_1\。
【例 8.8】圆括号对逻辑运算操作的修正。

样例代码请参考样例程序\第8章\05_ IL_Bracket_2\。
【例 8.9】圆括号在程序块并联中的应用。

在此示例中,两个 OR 开始的指令是两个程序块,是两个触点串联的程序,最后经或运算后,将运算结果存放到 bOutput 变量中。样例代码请参考样例程序\第8章\06_IL_ Bracket_3\。
数学运算中,圆括号具有括号相类似的功能,即括号外的操作被延迟执行。
【例 8.10】圆括号的延迟功能。

例 8.10 中,其运算结果为(rVar1+ rVar2)* (rVar3- rVar4)。样例代码请参考样例程序\第8章\07_ IL_Bracket_4\。
通过如下的示例说明累加器和堆栈之间的关系。
【例 8.11】累加器和堆栈之间的关系。

例 8.11 中堆栈内数据和当前累加器数据内容如表 8-6 所示。
表8-6 堆栈内数据和当前累加器数据内容的变化
| 指 令 | 1 | 2 | 3 | 4 | 5 | 6 |
| 当前累加器 | rVar1 | rVar1 | rVar1 | rVar1 | rVar1 | rVar1 + rVar2*(rVar3 - rVar4) |
| 堆栈 1 | -- | rVar2 | rVar2 | rVar2 | rVar2*(rVar3 - rVar4) | -- |
| 堆栈 2 | -- | -- | Var3 | Var3 - rVar4 | -- | -- |
最终,例 8.11 的运算结果为 rVar1+ rVar2* (rVar3- rVar4)。样例代码请参考样例程序\第8 章\08_ IL_Bracket_5\。
所以对较复杂运算关系使用结构化文本或梯形图语言实现较简单。从圆括号指令内进行跳转有时会产生不可预测的结果,故在使用时需要谨慎应对。
8.1.4 函数及功能块
-
函数的调用
指令表语言中,函数的调用相对简单。
-
函数调用方法:
在操作符区输入函数名,第一个输入参数作为 LD 的操作数。如果有更多的参数,下一个必须是在同一行作为函数名输入,之后的参数可以添加到这一行并用逗号隔开或添加到下面的行里。函数返回值将被保存在累加器中。需要注意的是,根据 IEC 标准的规定,返回值只能有一个。函数调用的编程格式和示例如表 8-7 所示。
表8-7 函数调用的编程格式及示例
| 方 式 | 编程格式 | 示 例 |
| 单参数 | LD 参数 函数名 ST 返回值 |
LD 0.5 // 读取弧度 0.5 COS // 调用 COS 函数 ST Var1 // 将运算结果 0.87758 存放在变量 Var1 中 |
| 双参数 | LD 参数 1 函数名 参数 2 ST 返回值 |
LD Var1 // 读取变量 Var1 的值 ADD Var2 // 与变量 Var2 的值相加 ST Var3 // 将运算结果返回值存放在 Var3 |
| 多参数 | LD 参数 1 函数名 参数 2… 参数 n ST 返回值 |
LD Var1 // 读取变量 Var1 的值 SEL IN0, IN1 // 根据 Var1 的值选择 IN0 或 IN1 作为返回值 ST Var2 // 将运算结果返回值存放在 Var2 |
1)带非形参表的函数调用格式
函数名 非形参,非形参,…,非形参
2)带形参表的函数调用格式
函数名 (第一形参 := 实参,…,最后形参:=实参)
-
函数调用示例:
下面通过 2 个调用函数的示例让读者有更清晰地理解。
【例 8.12】非形参的函数调用示例。

例 8.X 中,用 ADD 函数直接实现多个数值的想加运算。因此,与传统 PLC 的相加运算比较,程序被简化。须注意,一些传统 PLC 产品只允许有一个操作数。例如,ADD 10。而MetaFacture可以直接进行叠加。样例代码请参考样例程序\第8章\09_IL_FUN_ADD\。
【例 8.13】带形参的函数调用示例。

调用 RIGHT 函数,该函数第一个参数为 LEN,取的是变量 strVar1 的数据长度,第二个参数是 sub 1,将当前累加器中的数据长度-1,在函数中的功能为右移的位数,即每次移 1 位。上述程序如果转换为结构化文本其程序为:
strVar1:= RIGHT(strVar1, (LEN(strVar1) - 1))
其样例代码请参考样例程序\第8章\10_IL_FUN_RIGHT\。
-
功能块的调用
-
功能块及程序调用方法:
非形参编程语言中,功能块调用有下列 2 种方式。
-
带形参表的功能块调用,编程语言的格式如下:
CAL 功能块实例名(形参表)
-
带参数读/存储的功能块调用,编程语言的格式如下:
CAL 功能块实例名
-
功能块及程序调用示例:
下面以调用 TON 功能块为例说明功能块的调用方法。
【例 8.14】带形参表的功能块调用,其程序如下:

其样例代码请参考样例程序\第8章\11_IL_FB_CAL1 \。
【例 8.15】带参数读/存储的功能块调用。程序如下:

其样例代码请参考样例程序\第8章\12_IL_FB_CAL2\。
8.1.5 应用举例
【例 8.16】称重显示示例。
在实际工业生产中很多设备拥有称重筛选设备,当实际产品的重量不符合设定值时,需要将该产品作为次品并触发剔除信号将该产品剔除,这种设备中就有称重相关程序。
-
控制要求
称重装置将物料称后的毛重数据存储在 PLC 寄存器内,使用称重函数将毛重减去皮重,最终将净重以 REAL 类型变量输出。
假设:毛重变量:rGrossWeight;皮重变量:rTareWeigh;净重变量:rActuallyWeight。
为了控制称重信号的执行,需要设置手动触发信号作为称重命令,使用布尔变量 bStart 作为启动命令。
数据的显示类型毛重 rGrossWeight,皮重 rTareWeight 及净重 rActuallyWeight 均为 REAL 数据类型。
-
编程
编写功能块 FB_Weight,如下部分为功能块声明区域。
FUNCTION_BLOCK FB_WEIGHT
VAR_INPUT
bStart: BOOL;
rGrossWeight:REAL;
rTareWeight:REAL;
END_VAR
VAR_OUTPUT
ENO:BOOL;
rActuallyWeight:REAL;
END_VAR
VAR
END_VAR
如下部分为功能块的逻辑程序部分:

当功能块部分的程序编写完成后,实际测试,新添加一个程序,在程序中调用功能块FB_Weight 并填写相应的输入输出参数,最终的程序如图 8.6 所示。

图 8.6 称重程序示例
例如,当毛重的重量为 5(g)时,皮重设定的值为 1(g),只有当 bStart 被触发变为 TRUE 时,最终的净重才会有输出 4(g),否则一直为 0。其样例代码请参考样例程序\第 8章\13_IL_Weigh\。
【例 8.17】循环计算的示例。
-
控制要求
计算 1 到 10 的累加和及阶乘的程序,程序中可以使用 JMPC 跳转指令。
-
编程
变量声明如下:
PROGRAM PLC_PRG
VAR
diSum,diProduct:DINT;
i:BYTE;
END_VAR

上述程序可以简单的进行累加及阶乘运算,运算结果在 diSum 中为 55,在变量 diProduct 中存放 3628800。需要注意的是,当运算结果大于变量设置的数据类型允许范围时,结果会被置为 0。例如,如果计算 1 到 50 的累加和及阶乘时,阶乘的结果超过了双整长整数的允许范围,此时,计算结果被置为 0,为此,可将变量的数据类型改为实数或双精度实数类型。
使用语句表指令配合跳转指令和比较指令也可以实现高级编程语言中的条件语句功能。其样例代码请参考样例程序\第8章\14_IL_LOOP\。
8.2 梯形图(LD)/功能块(FBD)
8.2.1 梯形图/功能块图编程语言简介
在 IEC 61131-3 的标准中定义了两种图形类编程语言。即梯形图(Ladder Diagram,LD)编程语言和功能块图(Function Block Diagram,FBD)编程语言。梯形图编程语言用一系列梯级组成梯形图,表示工业控制逻辑系统中各变量之间的关系。功能块图编程语言用一系列功能块的连接表示程序组织单元的本体部分。
-
梯形图(LD)
梯形图来源于美国,它基于图形表示的继电器逻辑,是 PLC 编程中被最广泛使用一种图形化语言。梯形图程序的左、右两侧有两垂直的电力轨线,左侧的电力轨线名义上为功率流从左向右沿着水平梯级通过各个触点、功能、功能块、线圈等提供能量,功率流的终点是右侧的电力轨线。每一个触点代表了一个布尔变量的状态,每一个线圈代表了一个实际设备的状态,功能或功能块与IEC 1131-3 中的标准库或用户创建的功能或功能块相对应。
梯形图是国内应用最为广泛的编程语言,它也是 IEC 1131-3 的三种图形化编程语言种一种,梯形图是传统 PLC 使用得最多的图形编程语言,也被称为 PLC 的第一编程语言。根据梯形图中各触点的状态和逻辑关系,求出与图中各线圈对应的编程元件的状态,称为梯形图的逻辑解算。
梯形图中的某些编程元件沿用了继电器这一名称,如线圈、触点等,但是它们不是真实的物理继电器,而是一些存储单元(软继电器),每一软继电器与 PLC 存储器中映像寄存器的一个存储单元相对应。该存储单元如果为 “TRUE”状态,则表示梯形图中对应软继电器的线圈“通电”,其常开触点接通,常闭触点断开,称这种状态是该软继电器的“TRUE”或“ON”状态。如果该存储单元为“FALSE”状态,对应软继电器的线圈和触点的状态与上述的相反,称该软继电器为“FALSE”或“OFF”状态。使用中也常将这些“软继电器”称为编程元件。
-
功能块图(FBD)
功能块图用来描述功能、功能块和程序的行为特征,还可以在顺序功能流程图中描述步、动作和转变的行为特征。功能块图与电子线路图中的信号流图非常相似,在程序中,它可看作两个过程元素之间的信息流。功能块图普遍地应用在过程控制领域。
功能块用矩形块来表示,每一功能块的左侧有不少于一个的输入端,在右侧有不少于一个的输出端,功能块的类型名称通常写在块内,但功能块实例的名称通常写在块的上部,功能块的输入输出名称写在块内的输入输出点的相应地方。
-
程序执行顺序
梯形图和功能块图的执行过程相仿,都是按照从左至右,从上到下的顺序进行执行,如图 8.7 所示。

图 8.7 程序执行顺序
-
执行过程
-
母线
梯形图采用网络结构,一个梯形图的网络以左母线为界。在分析梯形图的逻辑关系时,为了借用继电器电路图的分析方法,可以想象左右两侧母线(左母线和右母线)之间有一个左正右负的直流电源电压,母线之间有“能流”从左向右流动。右母线不显示。
-
节
节是梯形图网络结构中最小单位,从输入条件开始,到一个线圈的有关逻辑的网络称为一个节。在编辑器中,节垂直排列。在 MetaFacture 中,每个节通过左侧的一系列节号表示,包含输入指令和输出指令,由逻辑式、算术表达式、程序、跳转、返回或功能块调用指令所构成。 要插入一个节,可以使用命令插入节或从工具箱拖动它。一个节所包含的元素都可以通过在编辑器中拖放来进行复制或移动。
梯形图执行时,从标号最小的节开始执行,从左到右确定各元素的状态,并确定其右侧连接元素的状态,逐个向右执行,操作执行的结果由执行控制元素输出。然后进行下一节的执行过程。图8.7 显示了梯形图的执行过程。
-
能流
图 8.7 中左侧的加粗蓝色线即为能流,可以理解为一个假想的“概念电流”或“能流” (PowerFlow)从左向右流动,这一方向与执行用户程序时的逻辑运算的顺序是一致的。能流只能从左向右流动。利用能流这一概念,可以帮助我们更好地理解和分析梯形图。
-
分支
当梯形图中有分支出现时,同样依据从上到下,从左至右的执行顺序分析各图形元素的状态,对垂直连接元素根据上述有关规定确定其右侧连接元素的状态,从而逐个从左向右,从上向下执行求值过程。在梯形图中,没有反馈路径的求值不是很明确。其所有外部输入值与这些有关的触点必须在每个梯级以前被求值。
-
执行控制
跳转及返回:当满足跳转条件时,程序跳转到 Label 标号的节开始执行,直至该部分程序执行到 RETURN 时,返回原来的节并继续执行。其结构图如 8.8 所示。

图 8.8 跳转指令执行过程
当程序执行到图 8.8 左侧的 Label1 时,此时程序开始执行跳转,直接跳转至图 8.8 右侧,找到以 Label1 为标号的程序段并开始执行接下来的程序,直至程序运行至 RETURN,则跳转程序执行完成并回到图左侧的主程序循环中。
MetaFacture 中使用梯形图的跳转指令和返回指令如下,如例 8.18 所示。
【例 8.18】使用跳转指令执行程序的示例。

图 8.9 跳转指令执行
如图 8.9 所示,当 bInput1 被置为 TRUE 时,主程序执行跳转语句,根据标签 Label1,程序跳转至第 3 节的 Label1 程序段,从图 8.9 中不难看出,尽管第 2 节的 bInput3 被置为 ON,但 bOutput2 始终不会被置为 TRUE,因为程序直接跳过了该语句。只有当 bInput1 为 FALSE 时,且 bInput3 为TRUE 时,bOutput2 才会 TRUE。
8.2.2 连接元素
IEC 1131-3 中的梯形图语言是对各 PLC 厂家的梯形图语言合理地吸收、借鉴,语言中的各图形符号与各 PLC 厂家的基本一致,图 8.10 为梯形图编辑器视图。IEC 61131-3 的主要的图形符号包括:
-
基本连接类:电源柜先、连接元素。
-
触点类:常开触点、常闭触点、正转换读出触点、负转换触点。
-
线圈类:一般线圈、取反线圈、置位(锁存)线圈、复位去锁线圈、保持线圈、置位保持线圈、复位保持线圈、正转换读出线圈、负转换读出线圈。
功能和功能块:包括标准的功能和功能块以及用户自己定义的功能块。

图 8.10 梯形图编辑器
-
线元素
-
电源轨线(母线)
梯形图电源轨线(Power Rail)的图形元素亦称为母线。其图形表示是位于梯形图左侧,也可称其为左电源母线。如图 8.11 为左母线的图形表示。

图 8.11 左母线图形表示
-
连接线
在梯形图中,各图形符号用连接线连接,连接线的图形符号有水平线和垂直线,它是构成梯形图的最基本元素。图 8.12 的 a)和 b)是水平和垂直连接线的图形表示。
![]() |
![]() |
a )水平连接线 b ) 垂直连接线
图 8.12 连接线的图形表示
-
连接元素的传递规则:
连接元素的状态从左向右传递,实现能流的流动。状态的传递遵守如下规则 :
-
连接到左电源轨线的连接元素,其状态任何时刻都为 TRUE,它表示左侧电源轨线是能流的起点。右电源轨线类似于电气图中的零电位。
-
水平连接元素用水平线表示,水平连接元素从它紧靠左侧的图形开始将图形元素的状态传递到靠它右侧的图形元素。
-
垂直连接元素总是与一个或多个水平连接元素连接,即它由一个或多个水平连接元素在每一侧与垂直线相交组成。垂直连接元素的状态根据与其连接的各左侧水平连接元素的状态或运算表示。
因此,垂直连接元素的状态根据下列规则确定:
-
如果左侧所有连接的水平连接元素的状态为 FALSE,则该垂直连接元素的状态为 FALSE。
-
如果左侧的一个或多个水平连接元素的状态为 TRUE,则该垂直连接元素的状态为 TRUE。
-
垂直连接元素的状态被传递到与其连接的所有水平连接元素,但不能传递到与其左侧连接元素的所有水平连接元素。
【例 8.19】连接元素及状态传递的示例。

图 8.13 连接元素及状态的示例
图 8-13 是连接元素及其状态的示例.
连接元素 1 与左电源轨线连接,其状态为 TRUE;
连接元素 2 与连接元素 1 相连,其状态从连接元素 1 传递,因此,其状态为 TRUE;
连接元素 3 是垂直连接元素,它与水平连接元素 1 连接,其状态为 TRUE;
连接元素 2 和 3 分别传递 4,5,由于图形元素 4 和 5 对应的变量 bInput2 和 bInput3 分别为常开触点,因此连接元素 6 和 7 的状态经图形元素的传递而成为 FALSE;
由于连接元素 8 的左侧所有的状态都为 FALSE。
-
连接元素的输入和输出数据类型必须相同。标准中,触点和线圈等图形元素的数据类型并不局限于布尔类型。因此,连接元素的输入输出数据类型相同才能保证状态的正确传递。
-
节
节是 LD 和 FBD 的基本实体, 在 LD/FBD 编辑器中,节是数值顺序安排的。每个节在左侧开始有一个节编号,并有一个由逻辑或算数表达式,程序,函数,功能块调用,跳转或返回指令组成的结构。节的示意图如图 8.14 中的红色阴影部分所示,序号依次排列。

图 8.14 节视图
-
节注释
一个节同时还可以分配一个标题,注释和标号。标题和注释区域的可用性可以通过“选项”-->“FBD, LD 和 IL 编辑器”对话框打开或关闭,如图 8.15 所示。

图 8.15 节标题注释和标号功能
如果上述选项被激活,用户可通过鼠标单击节上边界下面,为标题打开一个编辑区域。输入注释则打开标题区域下相应的编辑区域。注释可以是多行的。换行可以通过回车键实现,注释文本的输入是通过[ Ctrl ] +[ Enter ] 终止的。 图 8.16 为节标题注释和节注释的视图。

图 8.16 节标题注释与节注释
-
节标题注释
节也可以通过“切换节注释状态”设置为“注释状态”,设置后该节会像注释一样显示,不会被执行。
-
节分支
通过在工具箱中插入“
”来创建“子节”,如图8.17中则使用了分支功能。

图 8.17 通过分支功能创建子节
-
标签
标签是一个可选的标识符且当定义 跳转 时可以确定其地址。它可以包含任何字符。
在节区域下,每个 FBD,LD 或 IL 节都有一个文本输入区域来定义一个标号。标号是节的一个选择性辨识符,可以在定义跳转时寻址到, 它可以包含任意顺序的字符。
在节的空白处鼠标右击,选择“插入标号”,如图 8.18 中的 1 所示,然后会在 2 中弹出 Label:的标号,用户可以对其进行编辑。

图 8.18 在节中添加标号
-
触点
-
触点类型
触点是梯形图的图形元素。梯形图的触点(Contact)沿用了电气逻辑图的触点术语,用于表示布尔型变量的状态变化。触点是向其右侧水平连接元素传递一个状态的梯形图元素。
触点可以分为常开触点(Normally Open Contact,NO)和常闭触点(Normally Closed Contact, NC)。常开触点指在正常工况下,触点断开,其状态为 FALSE。常闭触点指在正常工况下,触点闭合,其状态为 True。表 8-8 列出了 MetaFacture 梯形图中常用的触点图形符号及说明。
表8-8 触点元素的图形符号与说明
| 类 型 | 图形符号 | 说 明 |
| 常开触点 | ![]() |
如果该触点对应当前布尔变量值为 True 时,则该触点吸合,如触点左侧连接元素的状态为 True 时,则状态TRUE被传递至该触点右侧,使右侧连接元素 的状态为 True。反之,当布尔变量值为False时,右侧连接元素状态为 FALSE。 |
| 常闭触点 | ![]() |
如果该触点对应当前布尔变量值为False时,则该常闭触点处于吸合状态,如触点左侧连接元素的状态为 True 时,则状态 True 被传递至该触点右侧,使右侧连接元素的状态为 True。反之,当布尔变量值为 True 时,触点断开,则右侧连接元素状态为False。 |
| 插入右触点 | ![]() |
可以进行多个触点的串联,在右侧插入触点。多个串联的触点都为吸合状态时,最后一个触点才能传输 True。 |
| 插入并联下常开触点 | ![]() |
可以进行多个触点的并联,在触点下侧并联插入常开触点。两个并联触点中只需一个触点为 True,则平行线传输 True。 |
| 插入并联下常闭触点 | ![]() |
可以进行多个触点的并联,在触点下侧并联插入常闭触点。常闭触点默认为吸合状态,如该触点对应当前布尔变量值为False时,左侧连接元素的状态为 True 时,则该并联触点右侧传输 True。 |
| 插入并联上常开触点 | ![]() |
可以进行多个触点的并联,在触点上侧并联插入常开触点。两个并联触点中只需一个触点为 True,则平行线传输 True。 |
-
状态传递规则
根据触点的状态和该触点连接的左侧连接元素的状态,按下列规则确定其右侧图形符号的状态。
-
当触点左侧图形元素状态为 TRUE 时,才能将其状态传递到出点右侧图形元素,根据下列原则进行传递:
-
如果触点状态为 TRUE,则该触点右侧图形元素的状态为 TRUE;
-
如果触点状态为 FALSE,则该触点右侧图形元素的状态为 FALSE。
-
当触点左侧图形元素状态为 FALSE 时,不管触点的状态如何,都不能将其状态传递到触点右侧图形元素,即右侧图形元素的状态为 FALSE。
-
从 FALSE-->TRUE 在触点左侧图形左侧变化时,其有关变量也从 FALSE-->TRUE,则该触点的右侧图形状态从 FALSE-->TRUE,并保持一个周期,然后再变为 FALSE,则这称为上升沿触发。
-
从 TRUE-->FALSE 在触点左侧图形左侧变化时,其有关变量也从 TRUE-->FALSE,则该触点的右侧图形状态从 TRUE-->FALSE,并保持一个周期,然后再变为 TRUE,则这称为下降沿触发。
-
线圈
-
线圈类型
线圈是梯形图的图形元素。梯形图中的线圈沿用了电气逻辑图的线圈术语,用于表示布尔型变量的状态变化。
根据线圈的不同特性,可以分为瞬时线圈和锁存线圈,锁存线圈分为置位线圈和复位线圈。表8-9 列出了 MetaFacture 梯形图中常用的线圈图形符号及说明。
表 8-9 线圈元素的图形符号与说明
| 类 型 | 图形符号 | 说 明 |
| 线圈 | ![]() |
左侧连接元素的状态被传递到有关的布尔变量和右侧连接元素,如果线圈左 侧连接元素的状态为TRUE,则线圈的布尔变量为TRUE,反之线圈为FALSE。 |
| 置位线圈 | ![]() |
线圈中有一个S。当左侧连接元素的状态为TRUE时,该线圈的布尔变量被置位并且保持,直到由Reset(复位)线圈的复位。 |
| 复位线圈 | ![]() |
线圈中有一个R。当左侧连接元素的状态为TRUE时,该线圈的布尔变量被复位并且保持,直到由Set(置位)线圈的置位。 |
-
线圈的传递规则
线圈是将左侧水平或垂直连接元素的状态毫无改变的传递到其右侧水平连接元素的梯形图元素。在传递过程中,将左侧连接的有关变量和直接地址的状态存储到合适的布尔变量中。相反,取反线圈是将其左侧水平或垂直连接元素的状态取反后传递到传递到其右侧水平连接元素的梯形图元素。
置位线圈和复位线圈将左侧水平连接元素状态从 FALSE 至 TRUE 和从 TRUE 至 FALSE 的瞬间保持一个求值周期,其他时间将其左侧水平连接元素状态传递至右侧水平连接元素。
上升沿和下降沿跳变线圈在其左侧水平连接元素状态从从 FALSE 至 TRUE 和从 TRUE 至 FALSE 的瞬间,将有关线圈的变量保持一个求值周期,其他时间将其左侧水平连接元素状态传递至其右侧连接水平元素。
在右侧没有制定只能链接一个元素,因此,用户可在右侧进行扩展,从而达到简化程序的目的。例如,可以在右侧并联其它线圈,如例 8.20 所示。
【例 8.20】线圈状态的传递。

图 8.19 线圈状态的传递
图 8.19 显示了线圈状态的传递过程。图中,当触点 bInput 闭合时,其触点右侧的连接元素状态也为 TRUE,分别经过水平和垂直连接元素后连接到线圈 bOutputVar1 和 bOutputVar2,并将其状态也置为 TRUE。
-
双线圈
所谓双线圈就是在用户程序中,同一个线圈使用了两次或两次以上,该现象称为双线圈输出。图 8.20 的 a)中有输出变量“bOutputVar1”两个线圈,在同一个扫描周期,两个线圈的逻辑运算结果可能刚好相反,即变量 bOutputVar1 的线圈一个可能“通电”,另外一个可能“断电”。对于变量 bOutputVar1 控制来说,真正起作用的是最后一个 bOutputVar1 的线圈的状态。
bOutputVar1 的线圈的通断状态除了对外部负载起作用外,通过它的触点,还可能对程序中别的变量的状态产生影响。所以一般应避免出现双线圈输出现象,尽量使用图 8.20 中的 b)采用的并联方式来解决双线圈问题。
![]() |
![]() |
a )双线圈 b )避免双线圈
图 8.20 双线圈示例
只要能保证在同一扫描周期内只执行其中一个线圈对应的逻辑运算,这样的双线圈输出是允许的。下列 3 种情况允许双线圈输出:
-
在判断条件相反的两个程序段(例如自动程序和手动程序)中,允许出现双线圈输出,即同一变量的线圈可以在两个程序段中分别出现一次。实际上 PLC 只执行正在处理的程序段中双线圈元件的一个线圈输出指令。
-
在调用条件相反的两个子程序(例如自动程序和手动程序)中,允许出现双线圈现象。即同一变量的线圈可以在两个子程序中分别出现一次。子程序中的指令只是在该子程序被调用时才执行,没有调用时不执行。
-
为了避免双线圈输出,针对同一变量可以多次使用置位/复位指令。
-
函数及功能块调用
如要实现函数或功能块的调用就要用到运算块,运算块可以代表所有的 POU,包括功能块、函数甚至包括程序。功能块如计时器,计数器等。可以在 FBD,LD 的节中插入。运算块可以有任意的输入,任意输出。函数及功能块的图形符号说明详见表 8-10。
与接点和线圈一起,用户也可以插入功能块和程序。在网络中,它们必须有带布尔值的一个输入和一个输出,并可在相同位置上像接点那样使用,也就是说在 LD 网络的左侧。
表8-10 函数及功能块图形符号与说明
| 类 型 | 图形符号 | 说 明 |
| 插入运算快 | ![]() |
插入函数或功能块,根据弹出的对话框通过鼠标选择想要使用的函数及功能块。适用于对函数和功能块不太熟悉者使用。 |
| 插入空运算快 | ![]() |
直接插入矩形块,在“???”处直接输入函数或功能块名,适用于对函数及功能块较为熟悉的用户。 |
| 插入带EN/ENO 的运算快 | ![]() |
只有当EN为True时,才执行函数或功能块并允许将状态传递至下游。适用于对函数和功能块不太熟悉者使用。 |
| 插入带EN/ENO 的空运算快 | ![]() |
插入带EN/ENO矩形块,在“???”处直接输入函数或功能块名,只有当 EN为True时,才执行函数或功能块并允许将状态传递至下游。适用于对函数及功能块较为熟悉的用户。 |
梯形图编程语言支持函数和功能块的调用。在函数和功能块调用时,需要注意如下事项:
-
梯形图中,函数和功能块用一个矩形框表示。函数可以有多个输入参数但只能有一个返回参数。功能块可以有多个输入参数和多个输出参数。
-
输入列于矩形框的左侧,输出列于矩形框的右侧。
-
函数和功能块的名称显示在框内的上中部,功能块需要将其实例化,实例名列于框外的上中部。用功能块的实例名作为其在项目中的唯一标识。
-
为了保证能流可以通过函数或功能块,每个被调用的函数或功能块至少应有一个输入和输出参数。为了使被连接的功能块执行,至少应有一个布尔输入经水平梯级连接到垂直的左电源轨线。
-
功能块调用时,可以直接将实际参数值填写在该内部形参变量名的功能块外部连接线处。
【例 8.21】功能块调用实参的设置。
图 8.21 调用 TON 延时 ON 功能块,TON_1 为功能块 TON 实例化后的实例名。功能块的输入形参 PT 设置为 t#5s。输出形参 Q 及 ET,当不需要输出形参如示例中的 ET 时可以不连接变量。

图 8.21 调用功能块时实参的设置
可以看到,功能块 TON 的输出 Q 连接到了线圈 bWorking。表示当触点 bStartButton 为 True 且 bEmg_Stop 为 False 持续时间超过 5s 后,bWorking 为 True。当 bEmg_Stop 断开即为 True 时,bWorking 为 False。
-
如果没有 EN 和 ENO 的专用输入输出参数,则函数和功能块会被自动执行,且将状态传递至下游。例 8.22 中,调用了带 EN 和 ENO 的功能块。
在工具箱中可以选择插入标准运算块“
”,或插入带有 EN/ENO 的功能块 “
”。在编辑器中通过拖拽释放复制或移动。图 8.22 的 a)和 b)为标准的运算块与带有 EN/ENO 的运算块的示图比较。
![]() |
![]() |
a ) 标准运算块 b ) 带有 EN/ENO 的功能块
图 8.22 FBD 中两种运算块比较
在图 8.22 的 a)中只要前端条件满足,该功能块则会被直接执行,而 b)中,功能块只有当EN 为 TRUE 时,该功能块才会被执行,否则,即使前端条件全部满足,该功能块不会被程序执行。如果将 b)中的 EN 的输入信号置为常数“TRUE”,此时 a)和 b)的作用是完全一致的。
【例 8.22】调用带 EN 和 ENO 的功能块。
图 8.23 为带 EN 和 ENO 的功能块,布尔输入量 bEnable 用于计数器功能块 CTU_0 的启动, bWorking 作为该功能块被启用的状态变量信号。

图 8.23 调用带 EN 和 ENO 的功能块
可以看出,当 bCounter 有上升沿触发信号时,则形参输出变量 CV 进行加 1 计算。
当 EN 为 False 时,功能块本体定义的操作不被执行,ENO 的值也相应为 False。
当 ENO 的值为 True,则说明该功能块的正在被执行。
-
分配
可以将分配功能理解为运算块分配输入/输出。在工具箱中可以选择插入“
”工具,将其拖拽至程序的编辑区中,此时编辑区中的预算块对应的输入输出接口处会出现灰色的菱形小图案,读者可以直接将其拖拽至接口处,插入之后,文本字符串 “??? ”可以用要分配的变量的名字替换,也可以使用
按钮调用“输入助手”,此时已完成了对运算块输入/输出接口变量的分配。分配视图如图 8.24 所示。

图 8.24 分配视图
-
跳转执行
-
跳转执行控制元素
跳转(Jump)执行控制元素用终止与双箭头的布尔信号线表示。跳转信号线开始与一个布尔变量、一个函数或功能块的布尔输出或梯形图的能流线。
跳转分为有条件跳转和无条件跳转。
当跳转信号开始与一个布尔变量、函数或功能块输出时,该跳转是条件跳转。只有程序控制执行到特定网络标号的跳转信号线及该布尔值为 TRUE 时才发生跳转。
无条件跳转如跳转信号线开始于梯形图的左电源轨线时,该跳转是无条件的。功能块图编程语言中,如果开始于布尔常数 1 时,该跳转也是无条件的。跳转控制元素图形如表 8-11 所列举。
表8-11 跳转控制元素图形
| 执行控制类型 | 执行控制元素的图形符号 | 说明 | |
| 无条件跳转 | LD语言 | ![]() |
直接无条件跳转至Label |
| FBD语言 | ![]() |
||
| 条件跳转 | LD语言 | ![]() |
当bInput为1时条件跳转 至Label |
| FBD语言 | ![]() |
||
| 条跳转返回 | LD语言 | ![]() |
当bInput为1时条件跳转返回 |
| FBD语言 | ![]() |
||
-
跳转目标
在程序组织单元中,跳转目标是发生跳转的该程序组织单元内的一个标号。它表示跳转发生后,程序将从该目标开始执行。
-
跳转返回
跳转返回(Return)分条件跳转返回和无条件跳转返回两类。
适用于从函数、功能块的条件返回,当条件跳转返回的布尔输入量为 TRUE 时,程序执行将跳转返回到调用的实体。当布尔输入为 FALSE 时,程序执行将继续在正常方式进行无条件跳转返回由函数或功能块的物理结束来提供。如表 8-11 所示,将 RETURN 语句直接连接到左轨线表示无条件返回。
-
跳转执行的组态
在工具箱中插入“
”,插入之后,自动输入的“???”,跳转目标的标号替换。可以直接输入目标的标号或者通过点击“
”浏览键使用输入助手进行选择,如图 8.25 所示,系统会自动筛选可以使用的标号供用户选择。

图 8.25 跳转输入助手
【例 8.23】跳转语句示例。
在气缸控制中,控制气缸电磁阀的伸出信号为 bExtrent,如果发出伸出信号 bExtrent 后 5s 内没有收到伸出传感器的反馈信号 bExtrented_Sensor1,则跳转至报警程序 Alarm,变量声明及程序如下。
PROGRAM PLC_PRG VAR
bExtrent:BOOL;
bExtrented_Sensor1:BOOL;
fb_TON:ton;
END_VAR

图 8.26 跳转语句示例程序
图 8.26 为跳转语句的示例程序,最终当 fb_TON 功能块的输出信号 Q 和 bExtrent 信号同时满足时,与逻辑的输出信号 Alarm 被置为 TRUE 。样例代码请参考样例程序 \ 第 8 章\15_PRG_AlarmJump \。
8.2.3 应用举例
【例 8.24】信号闪烁灯。
-
控制要求
使用定时器和逻辑函数构成信号闪烁灯系统。该线路输出可使信号灯按一定的周期 ON 和 OFF。
-
编程
程序实现将 bLamp 和 bLamp1 的交替 ON 和 OFF 实现闪烁信号灯的控制要求。程序如图 8.27 所示的梯形图来实现。
用户可以通过 t_SetValue 用来设定 ON 和 OFF 切换的时间,如下将其设定为 500 毫秒,具体变量的定义如下所示:
PROGRAM PLC_PRG
VAR
fb_TON:ton; //TimeDelay
t_SetValue:TIME:=t#500ms; //SetTime
bLamp AT%QX0.0:BOOL; //Output0
bLamp1 AT%QX0.1:BOOL; //Output1
END_VAR

图 8.27 闪烁信号灯的梯形图程序
其输出效果如图 8.28 所示,bLamp 与 bLamp1 的输出曲线正好相反,其状态切换的时间正好为1s。完整的样例代码请参考样例程序\第8章\16_PRG_SignalBlink\。

图 8.28 闪烁信号灯的输出图形
【例 8.25】pH 值控制系统。
-
控制要求
在废水处理或者发酵的过程中常常需要采用 pH 控制。pH 控制系统的被控对象具有非线性和时滞性,常用非线性和时滞补偿控制方案。但在简单控制方案中也可以采用如下的控制策略进行控制:当pH 值测量超过设定的酸度值时,等待一定的时间然后加入一定时间的碱性液体。当 pH 超过设定值时,接点 PHH 闭合,反之,当小于设定值时,其加碱阀为 bValves1。其控制方案为“看一看,调一调”。
-
当 pH 控制在线性区域时,可假设控制过程中 pH 的变化呈现线性性特性,即加碱液或酸液进行中和时,pH 的变化呈线性特性。通常,当设定值上限
和设定值下限
之间较小时,线性关系成立。 -
设置发酵过程中 pH 值从
变化到
所需时间为 t,加碱后 pH 值从
变化到
的时间为 t2,则延时时间可设置为 t1=t/2,加碱控制阀门打开的时间为 t2。 -
实际 pH 控制的设定值 SP=(
+
)/2 。减少
和
之间的差值有利于提高控制精度。 -
加碱阀 bValves1 的启动条件是定时器 t1 的设定时间到,因此,程序中用 t1.Q 作为启动条件,加碱阀 bValves1 的停止条件是 t2 的设定时间到,因此,程序中用 t2.Q 作为停止条件。
-
定时器 t1 的启动条件是 pH 到设定值 SP,因此,用触点 PHH 的上升沿触发 fb_Trigger 功能块,并用 RS 功能块将其信号暂存,定时器 t2 的启动条件是定时器 t1 的计时达到。

图 8.29 pH 控制信号波形
-
编程
根据上述的控制要求,使用梯形图编程语言编写 pH 值控制程序,其变量声明及程序如图 8.30 所示。程序中分别采用了两个定时器。
PROGRAM PLC_PRG
VAR
t1,t2:ton; //定时器 t1,t2
PHH:BOOL; //超过设定值信号
bValves1 AT%QX0.0 :BOOL;
fb_R_Trig:R_Trig;
fb_RS_0,fb_RS_1:RS; //加碱阀
END_VAR

图 8.30 pH 控制梯形图程序
在上图中,程序将定时器 t1 的时间设定为 20s,定时器 t2 的时间设定为 50s。当 t1 的时间到达后马上触发 t2 定时器并打开加碱阀降低酸度,当 t2 定时时间到后关闭加碱阀。完整的样例代码请参考样例程序\第8章\17_PRG_pHControl\。
8.3 结构化文本(ST)
8.3.1 结构化文本编程语言简介
-
简介
结构化文本(ST)是一种高级的文本语言,可以用来描述功能,功能块和程序的行为,还可以在顺序功能流程图中描述步、动作和转变的行为。
结构化文本编程语言是一种高级语言,类似于 Pascal,是一种特别为工业控制应用而开发的一种语言,也是在 MetaFacture 中最常用的一种语言,对于熟悉计算机高级语言开发的人员来说,结构化文本语言更是易学易用,它可以实现选择、迭代、跳转语句等功能。此外,结构化文本语言还易读易理解,特别是当用有实际意义的标识符、批注来注释时,更是这样。在复杂控制系统中,结构化文本可以大大减少其代码量,使复杂系统问题变得简单,缺点是调试不直观,编译速度相对较慢。结构化文本的视图如图 8.31 所示。

图 8.31 结构化文本视图
-
程序执行顺序
使用结构化文本的程序执行顺序根据“行号”依次从上至下开始顺序执行,如图 8.32 所示,每个周期开始,先执行行号较小的程序行。

图 8.32 结构化文本程序执行顺序
-
表达式执行顺序
表达式中包括操作符和操作数,操作数按照操作符指定的规则进行运算,得到结果并返回。操作数可以为变量、常量、寄存器地址、函数等。
【例 8.26】表达式示例。
a+b+c;
3.14*R*R;
ABS(-10)+var1;
如果在表达式中有若干个操作符,则操作符会按照约定的优先级顺序执行:先执行优先级高的操作符运算,再顺序执行优先级低的操作符运算。如果在表达式中具有优先级相同的操作符,则这些操作符按照书写顺序从左至右执行。操作符的优先级如表 8-12 所示:
表8-12 操作符优先级
| 操作符 | 符 号 | 优先级 |
| 小括号 | () | 最高 |
| 函数调用 | Function name (Parameter list) | ![]() |
| 求幂 | EXPT | |
| 取反 | NOT | |
| 乘法 | * | |
| 除法 | / | |
| 取模 | MOD | |
| 加法 | + | |
| 减法 | - | |
| 比较 | , = | |
| 等于 | = | |
| 不等于 | ||
| 逻辑与 | AND | |
| 逻辑异或 | XOR | |
| 逻辑或 | OR | 最低 |
8.3.2 指令语句
结构化文本语句表主要有 5 种类型,即赋值语句、函数和功能块控制语句、选择语句、迭代(循环)语句、跳转语句。表 8-13 列举了所有结构化文本用到的语句。
表8-13 结构化文本语句表
| 指令类型 | 指令语句 | 举 例 |
| 赋值语句 | := | bFan:= TRUE; |
| 函数及功能块控制语句 | 功能块 / 函数调用(); | |
| 选择语句 | IF | IF THEN ; END_IF |
| 选择语句 | CASE | CASE OF : ; … : ; ELSE ; END_CASE; |
| 迭代语句 | FOR | FOR := TO {BY } DO END_FOR; |
| 迭代语句 | WHILE | WHILE ; END_WHILE; |
| 迭代语句 | REPEAT | REPEAT UNTIL END_REPEAT; |
| 跳转语句 | EXIT | EXIT; |
| 跳转语句 | CONTINUE | CONTINUE; |
| 跳转语句 | JMP | : … JMP ; |
| 返回语句 | RETURN | RETURN; |
| NULL 语句 | ; | ; |
-
赋值语句
-
格式及功能
是结构化文本中最常用的语句之一,作用是将其右侧表达式产生的值赋给左侧的操作数(变量或地址),使用“:=”表示。
具体格式如下:
:=;
【例 8.27】分别给两个布尔型变量赋值,bFan 置 TRUE,bHeater 置 FALSE。
VAR
bFan: BOOL;
bHeater:BOOL;
END_VAR
bFan:= TRUE;
bHeater:= FALSE;
通过使用“:=”赋值语句实现上述功能。
-
使用中的注意事项
-
数据类型的匹配。如果赋值操作符的两侧数据类型不同,应调用数据类型转换函数。例如, rVar1 是 Real 实数类型,iVar1 是 Int 整数类型,当 iVar1 赋值给 rVar1 时,应调用 INT_TO_REAL 的转换函数。例如:
rVar1:= INT_TO_REAL(iVar1);
-
一行中语句可以有多个,例如,arrData[1]:=3; arrData[2]:=12; 该两句指令可以写在一行。
【例 8.28】一行中可有多个数据。
arrData1[i]:=iDataInLine1; arrData2[j]:= iDataInLine2;
-
函数调用时,函数返回值被赋值作为表达式的值,它应是最新的求值结果。
【例 8.29】函数调用的返回值作为表达式的值。
Str1:=INSERT(IN1:=’CoDe’, IN2:=’Sys’ ,P:=2);
-
函数及功能块控制语句
函数和功能块控制语句用于调用函数和功能块。
-
函数控制语句
函数调用后直接将返回值作为表达式的值赋值给变量。例如,rVar1:=SIN(rData1);语句中,调用正弦函数 SIN,并将返回值赋值给变量 rVar1。其语句格式如下:
变量:=函数名(参数表);
【例 8.30】函数控制语句示例。
rResult:=ADD (rData1, rData2); //使用 ADD 函数,将 rData1 加 rData2 的结果赋值给变量 rResult。
-
功能块控制语句
功能块调用采用将功能块名进行实例化实现调用,如 Timer 为 TON 功能块的实例名,具体格式如下:
功能块实例名:(功能块参数);
如果需要在 ST 中调用功能块,可直接输入功能块的实例名称,并在随后的括号中给功能块的各参数分配数值或变量,参数之间以逗号隔开;功能块调用以分号结束。
例如,在结构化文本中调用功能块 TON 定时器,假设其实例名为 TON1,具体实现如图 8.33 所示。

图 8.33 结构化文本调用功能块
-
选择语句
选择语句是根据规定的条件选择表达式来确定执行它所组成的语句。从大类上可分为 IF 和CASE 两类。
-
IF 语句
用 IF 语句实现单分支选择结构,基本格式如下。
IF THEN
;
END_IF
如果使用上述格式,只有当为 TRUE 时,才执行语句内容,否则不执行 IF 语句的。语句内容可以为一条语句或者可以为空语句,也可以并列多条语句,该语句表达式执行流程图如图 8.34 所示。

图 8.34 简单 IF 语句执行流程图
【例 8.31】使用 PLC 判断当前温度是否超过了 60 摄氏度,如果超过,始终打开风扇进行散热处理,具体实现代码如下。
VAR
nTemp:BYTE; (*当前温度状态信号*)
bFan:BOOL; (*风扇开关控制信号*)
END_VAR
nTemp:=80;
IF nTemp>60 THEN bFan:=TRUE;
END_IF
-
IF…ELSE 语句
用 IF 语句实现双分支选择机构,基本格式如下:
IF THEN
;
ELSE
;
END_IF
如上表达式先判断内的值,如果为 TRUE,则执行,如为 FALSE,则执行,程序执行流程图如图 8.35 所示。

图 8.35 IF…ELSE 语句执行流程图
【例 8.32】使用 PLC 判断当温度小于到 20 摄氏度时,开启加热设备,否则(温度大于等于 20 摄氏度)加热设备断开状态。
VAR
nTemp:BYTE; (*当前温度状态信号*)
bHeating:BOOL; (*加热器开关控制信号*)
END_VAR
IF nTemp
bHeating:=TRUE;
ELSE
bHeating:=FALSE;
END_IF
当程序的条件判断式不止一个时,此时,需要再一个嵌套的 IF…ELSE 语句,即多分支选择结构,基本格式如下。
IF THEN
IF THEN
;
ELSE
;
END_IF
ELSE
;
END_IF
如上,在 IF…ELSE 中有放入了一个 IF…ELSE 语句,实现嵌套,下面通过一个例子说明嵌套的使用。
如上表达式先判断内的值,如果为 TRUE,则继续判断的值,如果的值为 FALSE,则执行,回到判断,如果为 TRUE,则执行,反之则执行。
【例 8.33】当设备进入自动模式后,如实际温度大于 50 摄氏度时,才开启风扇并关闭加热器,小于等于 50 摄氏度时关闭风扇打开加热器,如在手动模式时,加热器风扇均不动作。
VAR
bAutoMode: BOOL; (*手/自动模式状态信号*)
nTemp:BYTE; (*当前温度状态信号*)
bFan:BOOL; (*风扇开关控制信号*)
bHeating:BOOL; (*加热器开关控制信号*)
END_VAR
IF bAutoMode=TRUE THEN
IF nTemp>50 THEN bFan:=TRUE; bHeating:=FALSE;
ELSE bFan:= FALSE; bHeating:= TRUE;
END_IF
ELSE bFan:= FALSE; bHeating:=FALSE;
END_IF
-
IF..ELSIF..ELSE 语句
此外,多分支选择结构还能通过如下方式来呈现。具体格式如下
IF THEN
;
ELSIF THEN ;
ELSIF THEN
;
. . .
. . .
ELSE
;
END_IF
如果表达式为 TRUE,那么只执行指令,不执行其它指令。否则,从表达式开始进行判断,直到其中的一个布尔表达式为 TRUE,然后执行与此布尔表达式对应语句内容。如果布尔表达式的值都不为 TRUE,则只执行指令,程序执行流程图如图 8.36 所示。

图 8.36 IF..ELSIF..ELSE 语句执行流程图
-
CASE 语句
CASE 语句是多分支选择语句,他根据表达式的值来使程序从多个分支中选择一个用于执行的分支,基本格式如下。
CASE OF
: ;
: ;
: ;
: ;
...
: ;
ELSE
;
END_CASE;
CASE 语句按照下面的模式进行执行:
如果的值为,则执行指令。
如果没有任何指定的值,则执行指令。
如果条件变量的几个值都需要执行相同的指令,那么可以把几个值相继写在一起,并
且用逗号分开。这样,共同的指令被执行,如上程序第四行。
如果需要条件变量在一定的范围内执行相同的指令,可以通过写入初、终值,以两个点分开。这样,共同的指令被执行,如上程序第五行。
【例 8.34】当前状态为 1 或 5 时,设备 1 运行和设备 3 停止;状态为 2 时,设备 2 停止和设备 3 运行;如当前状态在 10 至 20 之间,设备 1 和设备 3 均运行,其他情况时要求设备 1, 2, 3 均停止,具体实现的代码如下:
VAR
nDevice1,nDevice2,nDevice3:BOOL; (*设备 1..3 开关控制信号*)
nState:BYTE;
END_VAR (*当前状态信号*)
CASE nState OF
1, 5:
nDevice1 := TRUE;
nDevice3 := FALSE;
2:
nDevice 2 := FALSE;
nDevice 3 := TRUE;
10..20:
nDevice 1 := TRUE;
nDevice 3:= TRUE;
ELSE
nDevice 1 := FALSE;
nDevice 2 := FALSE;
nDevice 3 := FALSE;
END_CASE;

图 8.37 CASE 语句例流程图
CASE 语句流程图见图 8.37 所示,当 nState 为 1 或者 5 时,设备 1 开,设备 3 关;
nState 为 2 时,设备 2 关,设备 3 开;
nState 为 10~20 时,设备 1 关,设备 3 开;
其他情况则设备 1 关,设备 2 关,设备 3 关。
-
迭代语句
迭代语句主要用于重复执行的程序,在 MetaFacture 中,常见的迭代语句有 FOR,REPEAT 及WHILE 语句,下面对这种语句做详细解释。
-
FOR 循环
FOR 循环语句用于计算一个初始化序列,当某个条件为 TRUE 时,重复执行嵌套语句并计算一个迭代表达式序列,如果为 FALSE,则终止循环,具体格式如下。
FOR := TO {BY } DO
END_FOR;
FOR 循环的执行顺序如下:
计算是否在与的范围内;
当小于,执行;
当大于,则不会执行;
当每次执行时,总是按照指定的步长增加其值。步长可以是任意的整数值。
如果不指定步长,则其缺省值是 1。当大于时,退出循环。
从某种意义上理解,FOR 循环的原理就像复印机,在复印机上先预设要复印的份数,在此即循环的条件,当条件满足时,即复印的张数等于设置的张数,停止复印。
FOR 循环是循环语句中最常用的一种,FOR 循环体现了一种规定次数、逐次反复的功能,但
由于代码编写方式不同,也可以实现其他循环功能,下面通过一个实例,演示如何使用 FOR 循环。
【例 8.35】使用 FOR 循环实现 2 的五次方计算。
VAR
Counter: BYTE; (*循环计数器*)
Var1:WORD;
END_VAR (*输出结果*)
FOR Counter:=1 TO 5 BY 1 DO
Var1:=Var1*2;
END_FOR;
假设 Var1 的初始值是 1,那么循环结束后,Var1 的值的为 32。
|
注意: 如果等于的极限值,则会进入死循环。假设【例 8.X】中的计数变量 Counter 的类型为SINT(-128 至 127),将设定为 127 时,控制器会进入死循环。故不能对设极限值。 |
-
WHILE 循环
WHILE 循环与 FOR 循环使用方法类似。二者的不同之处是,WHILE 循环的结束条件可以是任意的逻辑表达式。即可以指定一个条件,当满足该条件时,执行循环,具体格式如下。
WHILE
;
END_WHILE;
WHILE 循环的执行顺序如下:
计算的返回值。
当的值为 TRUE 时,重复执行。
当初始值为 FALSE,那么指令不会被执行,跳转至 WHILE 语句的结尾。其流程图见图 8.38 所示

图 8.38 WHILE 语句流程图
|
注意: 如果的值始终为 TRUE,那么将会产生死循环,应当避免死循环的产生。可以通过改变循环指令的条件来避免死循环的产生。例如:利用可增减的计数器避免死循环的产生。 |
WHILE 语句在像在工程中控制一台电机,当按下“启动”按钮时(布尔表达式为 TRUE 时),电机不停的旋转,当按下“停止”按钮后(布尔表达式为 FALSE 时),电机也立即停止。下面通过一个实例,演示如何使用 WHILE 循环。
【例 8.36】只要计数器不为零,则始终执行循环体内的程序。
VAR
Counter: BYTE;
Var1:WORD;
END_VAR (*计数器*)
WHILE Counter0 DO
Var1 := Var1*2;
Counter := Counter-1;
END_WHILE
在一定的意义上,WHILE 循环比 FOR 循环的功能更加强大,这是因为在执行循环之前, WHILE 循环不需要知道循环的次数。因此,在有些情况下,只使用这两种循环就可以了。然而,如果清楚地知道了循环的次数,那么 FOR 循环更好,因为 FOR 循环可以避免产生死循环。
-
REPEAT 循环
REPEAT 循环与 WHILE 循环不同,因为只有在指令执行以后,REPEAT 循环才检查结束条件。
这就意味着无论结束条件怎样,循环至少执行一次。
具体格式如下。
REPEAT
UNTIL
END_REPEAT;
REPEAT 循环的执行顺序如下:
当的值为 FALSE 时,执行。
当的值为 TRUE 时,停止执行。
在第一次执行后,如果的值为 TRUE,那么只被执行一次。
注意:
如果的值始终为 TRUE,那么将会产生死循环,应当避免死循环的产生。可以通过改变循环指令部分的条件来避免死循环的产生。例如:利用可增减的计数器避免死循环的产生。
下面通过一个实例,演示如何使用 REPEAT 循环。
【例 8.37】REPEAT 循环举例,当计数器为 0 时,则停止循环。
VAR
Counter: BYTE;
END_VAR
REPEAT
Counter := Counter+1;
UNTIL
Counter=0
END_REPEAT;
此例的结果为,每个程序周期都进入该 REPEAT 循环,Counter 为 BYTE(0-255),即每个周期内都进行了 256 次自加一计算。
因为之前提到的“这就意味着无论结束条件怎样,循环至少执行一次”,所以每当进入该REPEAT 语句时,Counter 先为 1,每个周期内都执行了 256 遍的 Counter := Counter+1 指令,直到将 Counter 变量累加至溢出为 0,跳出循环。再被加到溢出,如此往复。
-
跳转语句
-
EXIT 语句
如果 FOR、WHILE 和 REPEAT 三种循环中使用了 EXIT 指令,那么无论结束条件如何,内循环立即停止,具体格式如下。
EXIT;
【例 8.38】使用 EXIT 指令避免当使用迭代语句时中出现除零。
FOR Counter:=1 TO 5 BY 1 DO
INT1:= INT1/2;
IF INT1=0 THEN
EXIT; (* 避免程序除零*)
END_IF
Var1:=Var1/INT1;
END_FOR
当 INT1 等于 0 时,则 FOR 循环结束。
-
CONTINUE 语句
该指令为 IEC 61131-3 标准的扩展指令,CONTINUE 指令可以在 FOR、WHILE 和 REPEAT 三种循环中使用。
CONTINUE 语句中断本次循环,忽略位于它后面的代码而直接开始一次新的循环。当多个循环嵌套时,CONTINUE 语句只能使直接包含它的循环语句开始一次新的循环,具体格式如下。
CONTINUE;
【例 8.39】使用 CONTINUE 指令避免当使用迭代语句时中出现除零。
VAR
Counter: BYTE; (*循环计数器*)
INT1,Var1: INT; (*中间变量*)
Erg: INT;
END_VAR (*输出结果*)
FOR Counter:=1 TO 5 BY 1 DO
INT1:= INT1/2;
IF INT1=0 THEN
CONTINUE; (* 为了避免除零 *)
END_IF
Var1:=Var1/INT1;
END_FOR;
Erg:=Var1; (*只有当 INT1 不等于 0 的情况下才执行*)
-
JMP 语句
跳转语句,跳转指令可以用于无条件跳转到使用跳转好标记的代码行,具体格式如下。
:
...
JMP ;
可以是任意的标识符,它被放置在程序行的开始。JMP 指令后面为跳转目的地,即一个预先定义的标识符。 当执行到 JMP 指令时,将跳转到标识符所对应的程序行。
|
注意: 必须避免制造死循环,可以配合使用 IF 条件控制跳转指令。 |
【例 8.40】使用 JMP 语句实现计数器在 0..10 范围内循环。
VAR
nCounter: BYTE;
END_VAR
Label1:nCounter:=0;
Label2:nCounter:=nCounter+1;
IF nCounter
Label2;
ELSE
JMP Label1;
END_IF
上例中的 Label1 和 Label2 属于标签,不属于变量,故在程序中不需要进行变量声明。
通过 IF 语句判断计数器是否在 0-10 的范围内,如果在范围内,则执行语句 JMP Label2,程序会在下一个周期跳转到至 Label2,执行程序 nCounter:=nCounter+1,将计数器进行自加 1,反之,则会跳转至 Label1,执行 nCounter:=0,将计数器清零。
此例子中的功能同样可以通过使用 FOR,WHILE 或者 REPEAT 循环来实现。通常情况下,应该避免使用 JMP 跳转指令,因为这样降低了代码的可读性和可靠性。
-
RETURN 指令
RETURN 指令是返回指令,用于退出程序组织单元(POU),具体格式如下。
RETURN;
【例 8.41】使用 IF 语句作为判断,当条件满足时,立即终止执行本程序。
VAR
nCounter: BYTE;
bSwitch: BOOL; (*开关信号*)
END_VAR
IF bSwitch=TRUE THEN
RETURN;
END_IF;
nCounter:= nCounter +1;
当 bSwitch 为 FALSE 时,nCounter 始终执行自加 1,如 bSwitch 为 TRUE 时, nCounter 保持上一周期的数值,立刻退出此程序组织单元(POU)。
-
空语句
即什么内容都不执行。
具体格式如下。
;
-
注释
注释是程序中非常重要的一部分,它使程序更加具有可读性,同时不会影响程序的执行。在 ST 编辑器的声明部分或执行部分的任何地方,都可以添加注释。
在 ST 语言中,有两种注释方法:
-
多行注释以(* 开始,以 *) 结束。这种注释方法允许多行注释,如图 8.39 的 a)所示。
-
单行注释以“//”开始,一直到本行结束。这是单行注释的方法,如图 8.39 的 b)所示。
![]() |
![]() |
a )多行注释 b )单行注释
图 8.39 结构化文本语言注释
8.3.3 应用举例
【例 8.24】磁滞功能块 FB_Hystersis。
-
控制要求
该功能块有三个输入信号,分别为当前实时值输入信号,比较设定值输入信号和偏差值输入信号。此外需要有一个输出值,当输出为 TRUE 时,只有当输入信号 IN1 小于 VAL-HYS 时,输出才切换到 FALSE。当输出信号为 FALSE 时,只有当输入信号 IN1 大于 VAL+HYS 时输出才切换到TRUE。
功能块 FB_Hystersis 的输入输出变量定义如下。
FUNCTION_BLOCK FB_Hysteresis
VAR_INPUT
IN1:REAL; //输入信号
VAL:REAL; //比较信号
HYS:REAL; //磁滞偏差信号
END_VAR
VAR_OUTPUT
Q:BOOL;
END_VAR
图 8.40 的 a)和 b)分别为磁滞过程的示意图及功能块图形的示意图。
![]() |
![]() |
a )磁滞过程示意图 b )功能块图形示意图
图 8.40 磁滞功能块
-
功能块编程功能块本体用于判断输入信号的程序如下。
IF Q THEN
IF IN1
Q:=FALSE; //IN1 减小
END_IF
ELSIF IN1>(VAL+HYS) THEN
Q:=TRUE;
END_IF //IN1 增加
-
功能块应用
FB_Hysteresis 功能块可以用于位信号控制,其中 IN1 连接过程变量 rActuallyValue,VAL 链接过程设定值 rSetValue,rTolerance 为所需的控制偏差,程序的声明部分如下:
PROGRAM POU
VAR
fbHysteresis:FB_Hysteresis; //fbHysteresis 是 FB_Hysteresis 功能块的实例
rActuallyValue:REAL; //实际测量值
rSetValue:REAL; //过程设定值
rTolerance:REAL; //偏差设定值
bOutput AT%QX0.0:BOOL; //位信号输出
END_VAR
程序的本体如下:
fbHysteresis(IN1:=rActuallyValue , VAL:=rSetValue , HYS:=rTolerance , Q=>bOutput );
如上的程序部分同样也可以用如下的程序表示,其结果是一样的。
fbHysteresis(IN1:=rActuallyValue , VAL:=rSetValue , HYS:=rTolerance);
bOutput:=fbHysteresis.Q;
图 8.41 为实际程序运行的结果图,程序中将 rSetValue 设定为 100,rTolerance 设定为 20。当 rActuallyValue 的数值由 0 开始递增,达到 120 时,bOutput 信号被置为 TRUE,随后 rActuallyValue 降为 0 时,bOutput 也变为 FALSE,理论上降到 80 时,bOutput 就会变为 FALSE。完整的样例代码请参考程序\第8章\18_FB_Hysteresis\。

图 8.41 磁滞功能块程序运行结果
【例8.25】时滞功能块 FB_Delay。
功能块 FB_Delay 是时滞功能块,它与 FB_Hystersis 磁滞功能块不同。输出信号在时间上滞后输入信号的时间称为时滞。生产过程的被控对象常用一阶滤波环节加时滞描述。这里只介绍时滞功能块,不对一阶滤波做过多介绍。
时滞环节的传递函数是:

假设采样周期为
,则离散化后,得到,

式中,X 是时滞环节的输入信号;Y 是时滞环节的输出信号。设离散化所采用的采样周期是
,则时滞
与采样周期
之比为滞后拍数 N。
-
功能块 FB_Delay 的变量声明
程序中采用数组存储输入信号,数组中存储不同时刻的采样数据,即第 1 单元存储时刻 1×
的采样值,第 i 单元存储时刻 i×
的采样值。时滞时间
与采样周期
之比的整数值是 N(N 的小数部分去除后,用 N 表示)。因此,如果某时刻,输入信号存储在第 N 单元,则经时滞的输出信号应从第 1 存储单元输出。
FUNCTION_BLOCK FB_Delay
VAR_INPUT
IN:REAL; //输入信号
bAuto: BOOL; //自动手动标志信号
tCycleTime:TIME; //采样周期
tDelayTime:TIME; //时滞时间
END_VAR
VAR_OUTPUT
rOutValue:REAL; //经过时滞后环节处理后的输出
END_VAR
VAR
N:INT; //滞后拍数
arrValue:ARRAY[0..2047] OF REAL; //先进先出的数组堆栈
i:INT; //数组的下标,用于输入
j:INT; //数组的下标,用于输出
fbTrig:R_TRIG; //将自动信号转化为脉冲
fbTon:TON;
END_VAR
当填写完上述输入输出参数后,通过图形化编程语言调用该功能块图可以看到图 8.42 的效果示意图。

图 8.42 FB_Delay 功能块图形示意图
-
功能块 FB_Delay 的程序本体
N:=TIME_TO_INT(tDelayTime)/TIME_TO_INT(tCycleTime);
fbTrig(CLK:= bAuto);
IF fbTrig.Q THEN
i:=N;
j:=0;
END_IF
fbTon(IN:= NOT fbTon.Q , PT:=tCycleTime);
IF fbTon.Q AND bAuto THEN
i:=(i+1)MOD 2000;
arrValue[i]:=i;
j:=(j+1)MOD 2000;
rOutValue:=arrValue[j];
END_IF
功能块本体采用两个下标窗口来管理输入和输出信号的存取和输出。输入信号数据存放在数组 X 的 i 下标地址,初始值等于滞后拍数。输出信号在数组 X 的 j 下标地址,输出初始值等于 0。采用取模的方法确定每次的存放和输出的地址,并在每次执行操作后,将原地址进行加 1 运算。保证下次执行操作时,存放该次的输入和前 N 次输入信号作为该次输出。完整的样例代码请参考程序\第8章\ 19_FB_Delay\。
数组存储单元的数量决定时滞大小和采样周期有关。当时滞越大,采样周期越小时,所需的存储器单元越多。一般可根据应用的大小使滞后拍数 N 大于存储器单元总数即可。
示例中,要求滞后拍数 N 小于 2000(数组长度为 2048)。此外,数组的存储单元从 0 地址开始,实际应用从地址 0 开始。
图 8.43 显示了输入窗口和输出窗口的关系。

图 8.43 输入/输出窗口的关系图
-
使用功能 FB_Delay 注意事项
滞后拍数 N 与时滞、采样周期有关,程序中用运行状态切换到自动状态的信号作为初始值设定的脉冲信号。
该功能块可与一阶滤波环节组合,用于模拟实际生产过程,进行控制系统仿真研究。
【例 8.26】计算最大、最小和平均值。
在一些工业控制中,常常需要计算若干测量值的平均值,最大值及最小值。下面使用结构化文本编程语言实现此类应用。
-
控制要求
有一个窑炉,内共有 32 个点需要测量温度值,分别将这 32 个点的最大值,最小值及平均值计算出来。
-
程序编写
程序中分别定义最大值、最小值、累计总和及平均值,具体变量的定义如下所示:
PROGRAM PLC_PRG
VAR
rMaxValue:REAL; //最大值
rMinValue:REAL; //最小值
rSumValue:LREAL; //总和
rAvgValue:REAL; //平均值
arrInputBuffer AT%IW100 :ARRAY[1..32] OF REAL; //输入源数据
i:INT;
END_VAR
主体程序如下,
rSumValue:=0;
FOR i:=1 TO 32 BY 1 DO
rSumValue:=REAL_TO_LREAL(arrInputBuffer[i])+rSumValue;
IF arrInputBuffer[i]> rMaxValue THEN
rMaxValue:=arrInputBuffer[i];
END_IF
IF arrInputBuffer[i]
rMinValue:=arrInputBuffer[i];
END_IF
END_FOR;
rAvgValue:=rSumValue/32;
使用 FOR…DO 语句扫描所有输入通道,计算平均值、最大和最小值,此外计算总和。样例代码请参考程序\20_PRG_MaxMinAvg\。
8.4 顺序流程图(SFC)
顺序功能流程图语言是为了满足顺序逻辑控制而设计的编程语言。编程时将顺序流程动作的过程分成步和转换条件,根据转移条件对控制系统的功能流程顺序进行分配,一步一步的按照顺序动作,如图 8.44 所示。每一步则代表一个控制功能任务,用方框表示。在方框内含有用于完成相应控制功能任务的梯形图逻辑。这种编程语言使程序结构清晰,易于阅读及维护,可以大大减轻编程的工作量,缩短编程和调试时间。用于系统的规模校大,程序关系较复杂的场合。它的特点是:以功能为主线,按照功能流程的顺序分配,条理清楚,便于对用户程序理解。

图 8.44 顺序功能图语言
8.4.1 顺序流程图编程语言简介
-
基本结构
在 SFC 程序中,从初始步开始,当转移条件成立时按顺序执行转移条件的下一个步,通过END 步结束一系列的动作,完整的过程如图 8.45 所示。

图 8.45 SFC 基本流程
-
如果启动了 SFC 程序,将首先执行初始步,即图 8.45 中的步 0;在初始步的执行过程中,程序将检查初始步的下一个转移条件,即检查图中的 “转移条件 0”是否成立,如果成立,程序则跳转至下一个步。
-
在“转移条件 0”成立之前仅执行初始步;当“转移条件 0”成立时,将停止初始步的执行,执行初始步的下一个步“步 1”,在执行“步1”的过程中,将检查“步 1” 的下一个转移条件,即经检查图中的“转移条件 1”是否成立;
-
当“转移条件 1”成立时,将停止“步 1”的执行,执行“步 2”;
-
按照转移条件的成立顺序依次执行下一个步,当执行 END 步时相应块将结束。
-
程序特点
-
SFC 优点
执行顺控的最佳选择将自动运行的顺序就照原样转换成图形描述即可,因此便于编程,便于理解程序。
-
易于理解的结构化程序
可以采用图形进行层次化和模块化的编写工作,所以便于试运行以及维护工作。如图 8.46 所示,图的左边是设备运行的流程图,通过 SFC 编程语言,能够直接将左边的流程图转换为程序,编程人员只需要在每个动作中加入相应的了逻辑,在流程跳转时加入适当的转换条件即可。

图 8.47 结构化的 SFC 程序
-
工序(步)间不需要互锁
由于 CPU 只对动作中的步进行运算,所以前进动作和后退动作逻辑不需要互锁。而使用 SFC 顺序流程图编程时并不需考虑互锁,因为在前后步条件不满足的情况下,程序并不会执行其他步,故不需要在触点互锁这方面考虑太多。
-
在多个工序(步)中可使用同一线圈
由于 CPU 只对动作中的步进行运算,所以即使在没有动作的步中存在相同的线圈,也不会被作为双线圈处理。(与主顺控程序中的线圈相同时,会变为双线圈处理。)
-
用图形监控动作状态
机械设备因为故障而停机时,通过监控,可以在画面上显示当前停止中的步,从而在第一时间查找出停机的原因,便于排除故障。此外,如果在各步上附有注释,那么动作时为什么会停止的原因就一目了然了。
-
设计的标准化
按照控制流程以图形方式编程,所以无论是谁编写的,都会是几乎相同的没有个人差别的程序,从而达到设计图的标准化。
-
由多人分担程序编写
可以将控制内容分成多个,由不同的人编写程序,然后编辑成一个。
-
按工序进行运算处理
由于 CPU 只对动作中的步进行运算,所有通过好的编程方法可以缩短扫描时间。
-
更容易设计和维护系统
因为整个系统和各个站以及机器本身的控制都是在一对一的基础上与 SFC 程序和步对应,所以即使顺控程序经验较少的人也可以设计和维护系统。此外其它程序员也使该格式设计的程序,相比其他编程语言,可读性更强。
此外,有效地使用 SFC 具备的功能,可以缩短机械动作的节拍时间
-
SFC 缺点
-
不适用的控制内容
采用中断处理方式的紧急停止、一直监控、从计算机接收数据等程序都不是顺序控制,所以不适合编写 SFC 程序。(对这些内容的控制如果在主程序中编写梯形图程序,则便于汇总掌握。)
-
不习惯导致的不放心
因为不习惯,所以有不能在极其复杂的控制中使用的先入为主的成见。(通过 SFC 进行结构化和模块化,可以整理要控制的内容,所以可以只用梯形图编程)。
8.4.2 SFC的结构
在 SFC 编程语言中的“工具箱”中可以添加 SFC 中的工具,SFC 由表 8-14 中的 6 大部分组成。其中,SFC 的基本元素是步配合转换条件,整合各基本元素形成了几种基本结构,任何一个复杂的或简单的 SFC 结构都是以这些基本部件构成的,如图 8.48 所示。

表8-14 SFC工具箱
| 类 型 | 图形符号 | 说 明 |
| 步 | ![]() |
SFC包含一系列的步,这些步通过有向的连接彼此联系。 |
| 转移 | ![]() |
动作是使用其他语言实现的一系列指令,可以用IL或ST语言实现的指令语句,也可以是用LD、FBD或SFC实现的网络。 |
| 动作 | ![]() |
动作命令可以在步中加入入口动作和出口动作。 |
| 跳转 | ![]() |
步之间的切换就是转换。只有当步的转换条件为真时,步的转换才进行。 |
| 宏 | ![]() |
添加宏。 |
| 分支 | ![]() |
添加并行分支。 |
-
步
-
步的定义
步表示整个工业过程中的某个主要功能。它可以是特定的时间、特定的阶段或者是几个设备执行的动作。步属于 SFC 的执行体,所有的实现执行的逻辑代码都包含在其中,转换条件则是决定步的状态,当上一步的转换条件成立,则这个步就被激活,被激活的步将进入执行的状态。
被激活期间,这个步被反复扫描,直到这个步的转换条件成立,步的激活被解除,退出执行到下一个步,下一个步则被激活。
SFC 顺序功能图中的步由一个方框表示,该方框内表示 “步名称”以及由连接线表示的上下转于关系。步的名称可以在当前位置直接编辑,并且步的名称必须在其所在的 POU 内是独一无二的,尤其是在 SFC 内使用动作编程时,需要特别注意。
-
步的组态
步分为两种:初始步和普通步。下文会对这两种不同类型的步做逐一介绍。
-
初始步
初始步是表示各个块的开始的步。可以选中对应的“步”,单击鼠标右键,选择“初始步”或通过快捷菜单中的“
”按钮来进行初始步的设定。如图 8.49 图中的 a)所示,初始步的视图和普通步略有不同,初始步为双矩形方框(被一个双边线包围)的视图,可以通过鼠标右键进行设定,如图 8.49 图 b)所示。
表8-15 步的编辑
| 类 型 | 图形符号 | 说 明 |
| 初始步 | ![]() |
用于将当前SFC 编辑器 中选中的步,设置为初始步。 |
![]() |
![]() |
a )初始步视图 b )设定初始步
图 8.49 设定初始步
-
普通步
当前正在被执行的“普通步”称为“激活步”。在线模式下,“激活步”被填充成蓝色。
每步包括一个动作和一个标记,这个标记用来表示此步是否激活。如果单步动作正在执行,那么所在的步就会显示为蓝色的框,如图 8.50 所示。

图 8.50 普通步
在一个控制循环中激活步的所有动作都将执行。所以,当激活步之后的转换条件是 TRUE 时,它之后的步被激活。当前激活的步将在下个循环中再执行。
-
动作
-
动作的定义
在本节的开始就介绍到,SFC 的执行过程最基本的结构就是步配合转换条件,每当步被激活时,将执行步的操作,直到转换条件成立才转至下一步。下一步被激活开始新的执行动作,直到自己的转换条件成立才离开,如此顺序往下执行,如图 8.51 所示。

图 8.51 SFC 执行步骤
动作是步具体要执行的操作,例如阀门的开启、电动机的起动或停止,工作或产品的移动等。每个步里面,可以是多个动作在执行,转换条件也是执行判定,所以,建立好 SFC 运行的流程结构,其中非常重要的一部就是确定好步和对其动作的组态,。
此外,将产生如下的标签:
-
每当创建一个步,会自动分配一个步的结构标签;
-
每当创建一个动作,会自动分配一个动作的结构标签;
-
每当创建一个转换条件,会自动分配一个 BOOL 量的标签。
这些标签的数据可以在编程中引用。
每个步都可以定义多个(或单个)动作,动作包括了此步执行的详细描述,动作可以使用梯形图、FBD、ST、SFC 等语言编写,用户可以对入口及出口动作进行编辑,其编辑动作的元素如表 8-16 所示。
表8-16 动作
| 类型 | 图形符号 | 说明 |
| 添加入口动作 | ![]() |
步激活前执行的动作。 |
| 添加出口动作 | ![]() |
这个动作会在步执行完的下一周期执行。(“步出口”) |
选择添加动作后,系统会自动弹出提示框,如图 8.52 所示,用户可以选择想要的编程语言来编写动作程序。

图 8.52 步动作支持的编程语言
-
限定符
限定符是用来配置一个动作将以什么样的方式与 IEC 步相关联的。限定符是被插入到一个动作元素的限定符区域内,这些限定符有 IecSfc.library 的 SFCActionControl 功能块来进行处理的,并通过 SFC 插件 IecSfc.library 可以被自动的包含到一个工程中去,SFC 限定符如表 8-17 所示。
表8-17 限定符
| 限定符 | 名 称 | 说 明 |
| N | Non - stored | 只要步激活动作就激活。 |
| S0 | Set (Stored) | 当步激活时动作启动,步失效时仍继续,直到动作重启。 |
| R0 | Overriding Reset | 动作失效。 |
| L | Time Limited | 当步激活时动作启动,动作会继续直到步不活跃或设定时间已到。 |
| D | Time Delayed | 激活后延时启动。延时后如果步仍激活,动作开始直到步失效。 |
| P | Pulse | 当步激活 / 失效时动作开始执行,且仅执行一遍。 |
| SD | Stored and time Delayed | 延时后动作开始,它会继续直到重启。 |
| DS | Delayed and Stored | 具体设定的时间延时之后如果步仍激活,动作开始并继续,直到重启。 |
| SL | Stored and time limited | 步激活后动作开始,并继续一定时间或重启。 |
当使用限定符 L、D、SD、DS 或 SL 时,需要一个时间值,格式为 TIME 的类型。
【例 8.27】限定符 N 的应用举例。

图 8.53 动作限定符 N
如表 8-17 中的说明,限定符“N”的作用是:只要对应的步被激活,则相应的连接的变量也被激活。如图 8.53 中的 bVar2,每次 Step0 被执行,bVar2 就会被置位 ON,反之为 OFF,该限定符可以用于监控步的执行状态。
限定符 L、 D、 SD、 DS 和 SL 需要一个时间常量格式的时间值。格式为 T#(数值)(单位)。如 5 秒的表示为:T#5S。
-
动作的组态
用户可以在设备树中找到该 SFC 编程语言的 POU,鼠标右键选择“添加对象”,可以选择动作,如图 8.54 图中的 a),或者可以直接使用工具栏,在工具栏中选择“
”按钮进行动作的添加,工具栏如图 8.54 的 b)所示。
![]() |
![]() |
a )设备树中添加动作 b )工具箱中添加动作
图 8.54 添加“动作”
使用第二种方式,在工具栏中选择“Action”,将其拖拽至步的上方后,会显示如图 8.55 左图中的四个灰色方框,可以将动作拖拽至对应的方框中,拖拽后会在步对应的“步属性”中也添加相应的设置,如图 8.55 右图所示。
左图中的 1)为 IEC 标准步的动作,MetaFacture 控制平台扩展了 IEC 标准的动作,额外加入了“步入口”,“步出口”和“步活动”三个动作,三种扩展动作分别为 2),3),4)。
![]() |
![]() |
图 8.55 添加“动作”
图 8.55 中所示的(1),(2),(3)和(4)对应具体的步动作解释如下,
-
步入口
该步被激活前执行的动作。只要该步被程序激活,这些步动作就会被执行,且在“步活动”动作之前。 该动作通过步属性的“步入口”区域的入口关联到步。它通过步左下角的“E” 显示,如图 8.56 的 a)所示。
![]() |
![]() |
a ) 步入口”状态图示 b ) “步出口”状态图示
图 8.56 “步入口”及“步出口”状态图示
-
步出口
这个动作会在步执行完的下一周期执行。当步无效时它会被执行一遍。但是,执行不会在同一个周期,在下一步执行周期的开始。动作通过步属性的“步入口”区域的入口关联到步。它通过步右下角的“X”显示,如图 8.56 的 b)所示。
-
步动作
步激活时,步动作会被执行,可能的入口已经执行完。在这一步的“步入口”执行完之后,这种步动作会在步激活后被执行。 但是,不同于 IEC 步动作,当它无效时不会被再执行,且它不可分配资格。动作通过步属性的“步活动”区域的入口关联到步。它通过步右上角的小三角显示,如图 8.57 的 a)所示。
![]() |
![]() |
a ) “步激活”状态图示 b ) 顺序功能图语言举例
图 8.57 “步入口”及“步出口”状态图示
包含两个 IEC 动作的步举例如图 8.57 的 b)所示。
在图 8-58 中使用到了限定符 D,该示例对应的程序变量声明如下所示,
PROGRAM PLC_PRG
VAR
b1,b2,b3: BOOL;
X1, X2: BOOL;
Time1:TIME:=T#5S;
END_VAR

图 8.58 “步激活”状态图示
程序如图 8.48 所示,当转移条件变量 X1 为 True 后,程序则会执行步 Step0,与此同时,对应的步激活状态变量 b2 则为 True,由于 b1 对应的限定符为 D,而具体的时间在程序的声明区定义的是变量 Time,即为 5s,则当 Step0 执行 5s 后,b1 变量由 False 置为 True。
-
步关联动作
步关联动作有前插入和后插入,如表 8-18 所示。使用当前步成为 IEC 标准步时,先鼠标点击步,例如 Step0,然后选择菜单栏“SFC”-->“插入前关联动作”命令,将 IEC 步动作与步进行关联,一个步可以关联一个或多个动作。新动作的位置由当前光标位置及使用的命令决定,动作必须在工程内是可用的,并且被插入时必须采用一个唯一的动作名称,如图 8.59 所示。
表8-18 步关联动作
| 类 型 | 图形符号 | 说 明 |
| 插入前关联动作 | ![]() |
在步中添加前关联动作。 |
| 插入后关联动作 | ![]() |
在步中添加后关联动作。 |

图 8.59 IEC 标准步动作添加关联动作
IEC 的标准步至少被执行两次,第一次执行是在当他们被激活时,第二次执行是在下个周期它们被禁止时。
由于一个步中可以分配多个动作,这些动作按照从上到下的顺序进行执行。例如,动作 Action_AS1 关联到步 AS1,添加一个步动作和添加一个有限定符 N 的 IEC 动作,在这两种情况下,假设转换条件都已经满足,初始步再次到达需要花费 2 个循环周期的时间。假设,一个变量 iCounter 在 Action_AS1 中增加。再次激活步 Init 之后,步动作例子中的 iCounter 值为 1。拥有限定符 N 的 IEC 动作的 iCounter 的值却是 2。
-
转移
在步和步之间的转换条件简称为转换。转换条件的值必须是 TRUE 或 FALSE,因而它可以是一个布尔变量、布尔地址或布尔常量。
只有当步的转换条件为真时,步的转换才能进行。即前步的动作执行完后,如果有出口动作则执行一次出口动作,后步如果有入口动作则执行一次后步入口的动作,然后按照控制周期执行该活动步的所有动作。用顺序功能图编写的程序组织单元包含了一系列的步,步之间是通过定向连接(转换条件)实现的。在顺序功能图中和步转移相关的操作如表 8-19 所示。
表8-19 SFC中的转移操作
| 类 型 | 图形符号 | 说 明 |
| 插入前步转移 | ![]() |
在步之前插入转移条件。 |
| 插入后步转移 | ![]() |
在步之后插入转移条件。 |
通常而言,转换拥有不同的方式,如下是在顺序功能图中常会用到的几种转移方式,下文中会逐一介绍:
-
串行转移
串行转移是指,通过转移条件成立转移至串行连接的下一步执行处理的方法。

图 8.60 串行分支转移
如图 8.60 所示,执行步 n 的动作输出[A]时,如果转移条件 b 成立,则对动作输出[A]进行非执行处理,执行步(n+1)的动作输出[B]。
-
选择转移
选择转移是指,在并行连接的多个步中,仅执行最先成立的转移条件的步的方式。
-
选择分支转移

图 8.61 选择分支转移
选择分支转移示意图如图 8.61,
执行步 n 的动作输出[A]时,选择转移条件 b 或者 c 中最先成立的条件的步(步(n+1)或者步(n+2)),执行该步的动作输出([B]或者[C])。
转移条件同时成立时,左侧的转移条件优先。对步 n 的动作输出[A]进行非执行处理。
选择后,依次执行所选列的各个步,直至进行合并为止。
-
选择合并转移
选择合并转移示意图如图 8.62 所示。

图 8.62 选择合并转移
如果分支中执行列的转移条件(b 或者 c)成立,则对执行步的动作输出([A]或者[B] )进行非执行处理,执行步(n+2)的动作输出[C]。
-
并行转移
并行转移是指,通过转移条件成立同时执行并行连接的多个步的方式。
-
分支转移

图 8.63 并行分支转移
并行分支转移示意图如图 8.63 所示。
执行步 n 的动作输出[A]时,如果转移条件 b 成立,则同时执行步(n+1)的动作输出[B]、步(n+3)的动作输出[D]。
转移条件 c 成立时转移至步(n+2),转移条件 d 成立时转移至步(n+4)。
-
合并转移

图 8.64 并行合并转移并行合并转移示意图如图 8.64 所示。
执行步 n 的动作输出[A]、步(n+1)的动作输出[B]时,如果转移条件 b、转移条件 c 成立,则分别对步 n 的动作输出[A]、步(n+1)的动作输出[B]进行非执行处理,转移至等待步。
等待步是用于使并行处理的步同步的步,通过将并行处理的所有的步转移至等待步,对转移条件 d 进行检查,如果转移条件 d 成立,则执行步(n+2)的动作输出[C]。
等待步被作为虚拟步,即使没有动作输出梯形图也没有关系。
-
跳转
跳转是指通过转移条件成立转移至同一个 POU 内的指定步的执行处理方式。它是通过一条竖线和水平箭头及跳转目标名显示的。 如“
”。
跳转定义了后续转换为 TRUE 时将要执行的步。因为按照程序的执行顺序,程序不能交叉或往上执行,故在此就有跳转存在的必要了。跳转只能用在分支的最后。当最后一个转换被选中时,可以通过 “插入前跳转” 命令插入 ,跳转的可执行的操作如图 8-20 所示。
表8-20 SFC中的跳转元素
| 类 型 | 图形符号 | 说 明 |
| 插入前跳转 | ![]() |
在步前添加跳转。 |
| 插入后跳转 | ![]() |
在步后添加跳转。 |
跳转的目标可以通过关联的文本字符串给定,可内引编辑。它可以是一个步名或平行分支的标签,如图 8.65 所示。

图 8.65 并行合并转移
执行步 n 的动作输出[A]时,如果转移条件 b 成立,则对动作输出[A]进行非执行处理,执行步 m 的动作输出[B]。
在并行转移内进行跳转时,只能在分支的各个纵方向进行跳转。例如,从分支起至合并为止的纵方向内的跳转程序,如图 8.66 所示。

图 8.66 并行合并转移
不能创建如下图 8.67 所示的跳转程序:向分支内的其它纵向梯形图的跳转,向并行分支外部的跳及从并行分支外部向并行分支内的跳转。例如,向并行分支外部的跳转程序(不能指定)。

图 8.67 并行合并转移
例如,如下图所示的转移条件成立时,不要指定至当前步的跳转。如果指定了至当前步的跳转,则无法正常动作。如图 8.68 所示。

图 8.68 并行合并转移
跳转的建立步骤如下:
在工具箱中找到“跳转”即可实现跳转的插入,如图 8.69 的 a)所示。添加后,只需要输入跳转目标名即可,如图 8.69 的 b),跳转的目标是 Step0,就直接写入 Step0 即可。
![]() |
![]() |
a )添加跳转 b )跳转目标名
图 8.69 跳转的建立
图 8.70 所示的是跳转指令的一个典型应用,当跳转指令 t42 条件满足后,根据程序指示,则会自动跳转至 step1,并重新进入程序循环。

图 8.70 SFC 跳转指令典型应用
-
宏
同其他软件对宏的定义一样,SFC 程序中的宏主要功能也是为了避免很多重复性的工作,用户只需提前将宏事先定义好,随后在程序中对其调用即可。对宏常见的操作如表 8-21 所示。
表8-21 SFC中的宏元素
| 类 型 | 图形符号 | 说 明 |
| 插入宏 | ![]() |
插入宏。 |
| 添加宏 | ![]() |
添加宏。 |
| 进入宏 | ![]() |
即打开宏编辑器视图。 |
| 退出宏 | ![]() |
可以返回到SFC标准视图。 |
-
隐形变量
每个 SFC 步和 IEC 动作提供隐含生成变量供运行时监视步和 IEC 动作。还可以定义变量来监视和控制 SFC 执行(超时,重启,尖模式)。这些隐含变量的类型实在库 IecSFC.library 中定义的。SFC 对象添加时这个库会自动被添加。
在 SFC 编程语言里有些隐形变量可以外部调用。正常情况下这些变量不显示出来。要使用这些变量需要对 SFC 属性做设置。右击 SFC 语言的 POU 的“属性”,弹出属性对话框中点击“SFC 设置”选项,将需要使用变量前打勾。如图 8.71 所示:

图 8.71 SFC 隐形属性
为了访问这些标识使它们工作,它们必须声明和激活。这在“ SFC 设置”对话框中设置。 它是对象属性对话框的子对话框。如需使用该变量,则必须在变量前的“使用”前打上勾,该变量在其描述中也说明了其具体的使用方法。
8.5 连续功能图(CFC)
8.5.1 连续功能图编程语言结构
-
简介
连续功能图(CFC)实际上是 FBD 的另一种形式。在整个程序中,可以自定义运算块的顺序,易于实现流程运算,它用于描述资源的顶层结构以及程序和功能块对任务的分配。
连续功能流程图和功能块图之间的主要区别是资源和任务分配的不同。每一功能用任务的名称来描述,如图所示。如果一个程序内的功能块象它的父程序一样在相同的任务下执行,任务关联是隐含的。连续功能图 CFC 示意图如图 8.72所示。

图 8.72 连续功能图 CFC 示意图
-
执行顺序
在 CFC 语言里元素的右上角的数字,显示了在线模式下 CFC 中元素的执行顺序。执行流程从编号为 0 的元素开始,在每个 PLC 运算周期内,0 号元素令总是第一个被执行。当手动移动该元素时,它的编号仍保持不变。当添加一个新元素时,系统自动按照拓扑序列(从左到右,从上到下)会自动获得一个编号,如图 8.73 红色部分所示。

图 8.73 CFC 编程语言顺序编号
CFC 语言中运算块、输出、跳转、返回和标签元素的右上角的数字,显示了在线模式下 CFC 中元素的执行顺序。执行流程从编号为 0 的元素开始。考虑到执行顺序会影响到结果,在一定情况下可以改变执行顺序。操作在菜单“CFC”下的“执行顺序”中的子菜单命令可以改变元素的执行顺序。
执行顺序包含的命令有:置首、置尾、向上移动、向下移动、设置执行顺序、按数据流排序、按拓扑排序,如图 8.74 所示。

图 8.74 CFC 顺序编排
-
置首
把选中元素移到执行顺序的首端。如果选中多个元素执行这个命令时,选中元素的原有的内部顺序保持不变;未选中元素的内部顺序也保持不变。
-
置尾
把所有选中元素移到执行顺序的末端。选中元素的内部顺序保持不变;未选中元素的内部顺序也保持不变。具体操作可以参照上述“置首”功能。
-
向上移动
把所有选中元素(如果某个元素已在执行顺序的首端,除去该元素)在执行顺序上向前移动一位。如选中图 7 中的 3 号元素执行“向上移动”命令,结果是 2 号元素与 3 号元素的执行顺序互换了一下,其余都不变。
-
向下移动
把所有选中元素(如果某个元素已在执行顺序的末端,除去该元素)在执行顺序上向后移动一位。具体操作参考“向上移动”。
-
设置执行顺序
该命令可以对选中元素重新编号,调整元素的执行顺序。执行“设置执行顺序”命令后,会打开“设置执行顺序”对话框。在当前执行次序区域显示当前单元编号,用户可以在“新处理顺序” 中输入需要单元编号,括弧内的值为可选值,如图 8.75所示。

图 8.75 设置执行顺序
-
按数据流排序
数据流排序表示各个元素按照数据流顺序执行,而不是按照元素所在位置(拓扑)决定执行顺序。执行数据流排序命令后,CFC 编辑器内部做如下操作:
-
按照拓扑对所有元素进行排序;
-
创建一个新的执行顺序链表;
-
找到那些已知的输入值,下一步可以被执行但还没有放入到链表中的元素。
数据流排序的优点是:一个算法执行后,连接到它的输出引脚上算法块会立刻执行;但是在拓扑排序中却不一定是这样。拓扑排序的执行结果可能和数据流排序的执行结果不同。
【例 8.76】图 8.77 为打乱元素标号的程序,使用“按数据流排序”的排序方法查看结果。

图 8.77 使用数据流排序之前
选中全部元素后执行“按数据流排序”后结果如图 8.78 所示。

图 8.78 使用数据流排序之后
元素的编号按照数据流的流向重新编排的,函数 MUL 和 SUB 的执行顺序较之前有了改变。
-
按拓扑排序
拓扑排序表示各个元素按照拓扑顺序执行,而不是按照元素数据流决定执行顺序。拓扑排序后,元素按照从左到右,从上到下的顺序执行;左边的元素的执行顺序编号小于右边的,上边的小于下边的。拓扑排序依据的是元素的位置坐标,与连线位置无关。
【例 8.79】图 8.80为打乱元素标号的程序,使用“按拓扑排序”的排序方法查看结果。

图 8.80 使用按拓扑排序之前
选中 SUB 函数,右键执行“按拓扑排序”命令后结果如图 8.81所示,

图 8.81 使用按拓扑排序之后
拓扑排列的顺序就是:从左到右,从上到下的顺序执行;左边的元素的执行顺序编号小于右边的,上边的小于下边的。
8.5.2 连接元素
CFC 的元素包括块、输入、输出、跳转、标记、返回和注释等具体参考表 8.80:

图 8.82 CFC 工具箱具体描述如表 8-22 所示,
表8-22 CFC插入元素一览
| 插入图标 | 类 型 | 图形符号 | 说 明 |
![]() |
指针 | 默认在工具箱最上方。一旦这个条目被选中,光标编程箭头形状,你可以选择编辑窗口中的元素来放置并编辑它们。 | |
![]() |
输入 | ![]() |
通过“???”选择变量或常量 |
![]() |
输出 | ![]() |
|
![]() |
运算块 | ![]() |
运算块可以代表操作符、函数、功能块或程序。“???”代表的文本可以选中并替换为操作符、函数、功能块或程序名。插入功能块后,另一个“???”会出现在运算块的上方,必须用功能块实例的名字代替它 |
![]() |
跳转 | ![]() |
跳转元素用来指示程序从哪里继续。通过修改标签名“???”进行设定 |
![]() |
标签 | ![]() |
标签标记了程序可以跳转的位置 |
![]() |
返回 | ![]() |
注意,在在线模式中,返回元素是自动在第一列及最后一个元素后的。在运行步骤中,离开POU前自动执行 |
![]() |
合成器 | ![]() |
用来处理一个运算块的一种结构体类型的输入变量 |
![]() |
选择器 | ![]() |
选择器同合成器相反,是用来处理运算块的输出的一类结构体 |
![]() |
注释 | ![]() |
用该元素可以为图表添加注释。选中文本,即可以输入注释。用户可以用+在注释中换行。 |
![]() |
输入引脚 | ![]() |
有些运算块可以增加输入引脚。首先在工具箱中选中Input Pin,然后拖放到在CFC编辑器中的算法块上,该运算块就会增加一个输入引脚。 |
![]() |
输出引脚 | ![]() |
有些运算块可以增加输出引脚。首先在工具箱中选中Output Pin ,然后拖放到在CFC编辑器中的算法块上,该运算块就会增加一个输出引脚。 |
-
输入/输出
-
输入
在 CFC 工具箱中插入“
”符号添加合成器功能。在 CFC 编辑器中插入后的图示为“
”。选中“???”文本,然后修改为变量或者常量。通过输入助手可以选择输入一个有效标识符。 -
输出
在 CFC 工具箱中插入“
”符号添加合成器功能。在 CFC 编辑器中插入后的图示为“
”。选中“???“文本,然后修改为变量或者常量。通过输入助手可以选择输入一个有效标识符。
-
运算块
在 CFC 工具箱中插入“
”符号添加合成器功能。在 CFC 编辑器中插入后的图示为“
”。运算块可用来表示操作符,函数,功能块和程序。插入运算块后,选中运算块的“???”文本框,将其修改为操作符名,函数名,功能块名或者程序名。或者可以通过“输入助手”选择输入一个有效的对象。
【例 8.83】通过运算块,在 CFC 编程语言中调用定时器功能块。
新建 POU,使用 CFC 编程语言,添加“运算块”,点击“???”输入“F2”弹出输入助手,在其中选择功能块,找到定时器功能块,如图 8.84 所示。

图 8.84 CFC 输入助手工具
如果需要在 ST 中调用功能块,可直接输入功能块的实例名称,并在随后的括号中给功能块的各参数分配数值或变量,参数之间以逗号隔开;功能块调用以分号结束。
例如,在结构化文本中调用功能块 TON 定时器,假设其实例名为 TON1,具体实现如图 8.85 所示。

图 8.85 连续功能图调用功能块
在例子中,当插入一个功能块,随即运算块上出现另一个“???”,这时要把“???”修改为功能块实例名 0,在本例中实例名为 TON_0 和 TOF_0。
若运算块被修改为另一个运算块(通过修改运算块名),而且新运算块的最大输入或输出引脚数,或者最小输入或输出引脚数与前者不同。运算块的引脚会自动做相应的调整。若要删除引脚,则首先删除最下面的引脚。
-
合成器
合成器用于结构体类型的运算块输入。合成器会显示结构体的所有成员,以方便编程人员使用它们。
在 CFC 工具箱中插入“
”符号添加合成器功能。在 CFC 编辑器中插入后的图示为“
”。
使用方法是:先增加一个合成器到编辑器中,修改“???”为要使用的结构体名字,然后连接合成器的输出引脚和运算块的输入引脚。
【例 8.86】CFC 程序 CFC_PROG 处理一个功能块实例 fubblo1,有一个结构体类型输入变量 struvar。 通过使用合成器元素,结构体变量可以访问:结构 stru1 定义:
TYPE stru1 :
STRUCT ivar:INT;
strvar:STRING:='hallo';
END_STRUCT
END_TYPE
功能块 fublo1,声明和实现:
FUNCTION_BLOCK fublo1
VAR_INPUT
struvar:STRU1;
END_VAR
VAR_OUTPUT
fbout_i:INT;
fbout_str:STRING;
END_VAR
VAR
fbvar:STRING:='world';
END_VAR
fbout_i:=struvar.ivar+2;
fbout_str:=CONCAT (struvar.strvar,fbvar);
程序 CFC_PROG 的 声明和实现:
PROGRAM PLC_PRG
VAR
intvar: INT;
stringvar: STRING;
fbinst: fublo1;
erg1: INT;
erg2: STRING;
END_VAR
程序如图 8.87 所示,1)为合成器,2)为含有结构体输入变量的 stru1,实现了结构体类型的输入块运算。

图 8.87 合成器的应用
最终的程序运行结果如图 8.88 所示。

图 8.88 CFC 合成器最示例运行结果
-
选择器
选择器用于结构体类型的运算块输出。选择器会显示结构体的所有成员,以方便编程人员使用它们。
在 CFC 工具箱中插入“
”符号添加选择器功能。在 CFC 编辑器中插入后的图示为“
”。
使用方法是:先增加一个选择器到编辑器中,修改“???”为要使用的结构体名字,然后连接
选择器的输出引脚和运算块的输出引脚。
【例 8.89】CFC 程序 cfc_prog 处理功能块实例 fubblo2,它有一个 stru1 结构的输出变量 fbout。通过选择元素,结构体成员变量可以被访问:结构定义 stru1:
TYPE stru1 : STRUCT
ivar:INT; strvar:STRING:='hallo';
END_STRUCT END_TYPE
功能块 fublo1,声明与实现:
FUNCTION_BLOCK fublo2
VAR_INPUT
fbin : INT;
-
注释
在CFC工具箱中插入“
””符号可以实现添加注释功能。在CFC编辑器中插入后的图示为“
”。
通过添加该元素,可以在 CFC 程序中为图表添加注释。选中文本,直接输入注释即可。如需要换行,输入+即可实现换行,图 8.90 为 CFC 中的注释视图。

图 8.90 CFC 中插入注释的视图
-
跳转
CFC 程序的跳转由跳转指令和标签两部分组成,如下会对这两部分做详细介绍。
-
跳转
在 CFC 工具箱中插入“
”符号可以实现跳转功能。在 CFC 编辑器中插入后的图示为“
”。
跳转用来指示程序下一步执行到哪,具体去哪最终“标签”所定义,如下会介绍“标签”的使用方法。插入一个新跳转后,要用跳转名替代“???”。
-
标签
在 CFC 工具箱中插入“
”符号可以添加标签。在 CFC 编辑器中插入后的图示为“
”。
“标签”可以标识程序跳转的位置在在线模式下,如果跳转被激活,则可以进入跳转对应的标签,如此循环执行。
标签名不属于变量,故在程序声明区中不需要对其定义,例 8.x 说明了如何正确使用跳转指令和标签。
【例 8.91】CFC 跳转指令和标签功能示例。

图 8.92 CFC 跳转功能示例
程序启动后,当输入值 nInput 大于 10 且小于 100 时,程序执行跳转功能,转至标签 Label1,由于 Label1 的执行序号为 0,故在该程序中执行的顺序为:4—>0—>1—>2—>3—>4,如此循环执行。
由于在此程序中还有自加 1 的功能,但执行序号为 5 和 6,故当跳转指令被执行时,该自累加功能不会被程序执行,反之 nCounter 则进行自累加。
-
返回指令
在 CFC 工具箱中插入“
”符号可以实现返回功能。在 CFC 编辑器中插入后的图示为“
”。 需特别注意该执行顺序号,当条件满足时,则会直接返回程序。
命令返回一个入令插这个命注意在联机模式下带 RETURN 名字的跳转标签自动插入到第一列和编辑器最后元素的后面,在分支中,它自动跳转到执行将离开 POU 之前的地方。
RETURN 指令是返回指令,用于退出程序组织单元(POU)。
|
注意: 在线模式下,RETURN自动插入到编辑器最后那个元素之后。在单步调试中,在离开该POU之前,会自动跳转到该RETURN。 |
8.5.3 CFC的组态
-
在 CFC 程序中添加连接
添加连接时,首先激活连接程序块的管脚,激活后在管脚出会有一个方形区域出现,鼠标左键选中这个方形区域,如图 8.93 的 1)所示,按住鼠标至要连接的另一个连接点处松开鼠标,连接至8.93中的 2)处,即完成了两部分的连接。

图 8..93 CFC 程序添加连接
-
在 CFC 程序中删除连接
删除连接时,首先激活连接程序块的管脚,激活后在管脚出会有一个方形区域出现,鼠标右键选中这个方形区域,在随后显示菜单栏中选择“删除”即可,如图 8.94 中框出部分所示。也可以在快捷菜单栏中选择“
”按钮来删除程序中的连接线。

图 8.94 CFC 程序删除连接用举例
8.5.4 应用举例
【例 8.92】模拟量分辨率选择
-
控制要求
有3个输入选择信号用来选择对应不同的模拟量分辨率以配合不同的传感器类型,当输入信号1 ON 时,对应256,输入信号2 ON 时,对应1024,输入信号3 ON 时,对应4096。通过程序实现上述功能,并在程序内进行互锁。
-
编程
程序变量声明部分如下:
PROGRAM PLC_PRG
VAR
R_TRIG_1,R_TRIG_2,R_TRIG_3:R_TRIG;
END_VAR
VAR_INPUT
S1,S2,S3:BOOL;
END_VAR
VAR_OUTPUT
AnaOut:INT;
END_VAR
程序本体如图8.95所示,完整的样例代码可参考程序\01 Sample\第8章\23 AnalogSelects\。

图8.95 模拟量分辨率选择示例