浅谈PLC的“扫描周期”以及ST指令的特性
扫描周期大家应该都知道,是PLC完整扫描一遍程序的时间,PLC就像一个读报纸的人,而报纸上的内容就是程序,读完一次报纸的时间就是一个扫描周期。
这个扫描周期可以是指定一个时间,也可以不指定,指定时间时无论程序有多长,PLC都在设定的时间内全部读完,如果实在读不完,PLC就会报警,说明PLC的性能不够需要更换。时间不指定时PLC按照一个固定的速度去读程序,程序多时间长些,程序少时间就短。
但这并不是今天我们要说的重点,重点是如何从一个扫描周期的角度去看程序。
一个扫描周期下的IF指令
习惯于梯形图编程的人可能不太会去关注一个扫描周期下的程序与连续运行的程序有何区别,因为梯形图最开始就是用来代替继电器的,采用的也是硬件的逻辑思维,但如果想要学习ST,你一定要知道程序在微观下与宏观下的区别,以及不同指令如何运行。
举个例子,判断下面这两段程序有没有区别:
程序1
程序2
从宏观上来看,这两段程序的效果都是iNumber变量+1后持续+10,iNumber的值一直在增长。
但是从一个扫描周期上来看,结果就完全不一样了,为了看到一个扫描周期下程序的运行结果,我们给两段程序加上限制条件,保证程序执行一个扫描周期:
程序1的运行结果
程序2的运行结果
注:iNumber的初始值=0。
可以看到,执行一个扫描周期以后,两段程序给出两个不同的结果,导致这个结果的原因是IF指令的运行特性导致的,一个IF语句在一个扫描周期内最多只执行其中的一个条件 。
在程序1中,两个判断条件是由两个IF语句写出,条件1(iNumber=0)判断并执行后还会继续判断条件2(iNumber>0),所以最后的结果是iNumber=0+1+10=11。
而在程序2中,两个判断条件写入一个IF语句中,在程序读到IF语句时会依次判断IF下面的所有条件哪个成立,去执行条件成立下的程序。发现条件1(iNumber=0)成立,执行iNumber+1后跳出IF判断,后面的所有条件不再过问了。条件1下的程序执行后,iNumber=1,即便后面的条件2(iNumber>0)这时也成立了PLC也不会去管他了。
这个例子中IF的两个条件同时只有一个条件成立,那如果是在一个扫描周期下,有多个条件成立时PLC如何选择呢?我们稍微改下程序:
我们把条件2改为iNumber>-1,PLC复位后iNumber=0,同时满足两个判断条件,执行一个扫描周期后iNumber仍然=1,这里说明IF有多个条件同时成立时,执行第一个成立的条件。
不知道有没有人对我加的限制条件有点疑惑,bTrig触发后,程序立即复位了bTrig,也就是最外层的IF语句条件不成立了,为什么后面的程序还会执行呢?这里体现出IF语句的第三个特性,只要判断时条件成立,条件下的程序会全部执行,无论在这个过程中条件有没有变化。
当然,如果想要终止某个条件下程序的运行也是有方法的,可以使用RETURN 指令。比如程序1,在条件1执行后我们不希望在执行条件2了的话,可以在条件1后面加一句return;PLC会跳出当前正在执行的指令。
RETURN指令
可以看到,在条件1执行后iNumber=1,满足了return的执行条件,返回上一层的IF语句,下面的条件不会再判断了。
总结:
一个IF语句在一个扫描周期内最多只执行其中的一个条件 。
在一个扫描周期内IF语句有多个条件同时成立时,执行第一个成立的条件。
在一个扫描周期内IF语句只要判断时条件成立,条件下的程序会全部执行,无论在这个过程中条件有没有变化
IF与CASE的区别
上面刚刚总结的3个特性,case语句是同样具有的,那case与if有什么区别呢?
1.PLC的占用不同 。
PLC在解析IF语句时,在一个扫描周期内要依次判断所有条件是否成立,找到第一个成立的条件后去执行,而解析case语句时,直接根据判断变量的值跳转至相应的程序中,举个例子:
IF判断
在这段程序中,iStep的值=8;在bTrig触发后PLC先判断第1个条件iStep=0,发现不成立后判断第2个条件iStep=1,发现不成立后判断第3个条件。。。最后判断第9个条件iStep=8,发现条件成立,开始执行,共判断了9步。
我们再看看case如何编写:
在bTrig触发后,PLC判断iStep的值=8,直接去执行“8”后面的程序,只判断了一步。在复杂程序中多使用case去判断数字变量,可以非常有效的减少PLC的运行负荷。(由于三菱软件编译的原因,实际的步数不一定谁多谁少,不用过于关注。)
2.判断的变量类型不同。
IF指令能够判断数字变量,开关变量等多种类型的变量,甚至可以在判断条件中编写复杂数学公式和逻辑计算。例如:
如图,直接在判断的数组变量的角标中写入数学公式,且多个变量使用and 、or 、not 等逻辑符号进行计算。
而case语句只能判断数字类型的变量,或者枚举变量(三菱不支持),例如:
理解循环的意义
ST的循环可以指定循环次数(FOR循环),可以不指定循环次数(while循环),而这里所说的循环次数 都是一个扫描周期下的执行次数 。举个例子:
这句话的意思是在一个扫描周期内,执行100次iNumber+1,而且每次执行后,ii的值增加1 。我们如果想看到一个周期内的结果扔然要增加限制条件:
可以看到执行一个扫描周期后,iNumber增加了100次1,最后等于100。
那它有什么作用呢?我用if语句也能实现iNumber增加100次1啊,比如:
bTrig触发后,iNumber满足<100 的条件,执行iNumber+1的程序,100扫描周期后,条件不再满足。他们虽然实现了同样的功能(iNumber增加了100次1),区别是IF用了100个扫描周期,而for只用了一个。在我举的例子当中区别确实不大,但是在正常程序中,PLC的扫描周期一般要在2-5ms左右,一千次的扫描周期就达到了2-5秒的时间,假设要实现从一个容量为1万的数组里面找出一个特定数值,如果用IF的方法,大约要耗费20-50秒才能完成,这个时间成本是有点高的,而for循环只需要几毫秒,可以说一瞬间完成。
例如:假设容量为1万的数组iNumber[0..9999],从中找出第一个数值为888的变量,记录他的角标:
大家可以试着理解一下这个程序。
上升沿/下降沿
字面理解上升沿和下降沿,是一个变量变化的一瞬间,是一个无穷小的时间。但是在plc的程序里最小的时间单位就是扫描周期,所以所谓的沿就是一个扫描周期。
上面举的例子中用到的bTrig变量都是为了让下面的程序执行一个扫描周期,也可以理解为执行bTrig的一个上升沿, 与下面的编程效果一样:
上升沿功能块R_TRIG的功能,实际上就是检测输入变量,在输入变量由低电平变为高电平的第一个扫描周期内输出高电平, 然后输出低电平。也就是输出一个扫描周期。
下降沿与上升沿同理,检测的是输入变量由高到低变化的第一个扫描周期。
理解的上升沿与下降沿的含义,我们可以非常灵活的应用在程序中,像让程序执行一个扫描周期,可以检测一个变量的上升/下降沿,可以用我们上面的例子中在IF语句置位复位一个变量,也可以在case中执行一个条件后立刻改变判断变量的数值等等。
实例 SCL编程,这9种程序控制指令必须掌握
SCL作为一种编程语言,可以实现LAD/FBD所有的功能,大多数的指令与LAD/FBD都是相同的,只是在编辑器中的外形不同。只有一些指令使用是不太一样的甚至LAD/FBD没有的,这里只介绍这些不同的。
SCL特殊的指令有以下几种,如图1-3红框中的指令:
图1 读写存储器
图2 转换操作
图3 程序控制指令
在这三部分中,读写存储器的PEEK POKE指令可以参考链接,转换操作可以参考链接,这里只介绍图3的程序控制指令。
【文末免费领取学习资料】
【文末免费领取学习资料】
【文末免费领取学习资料】
程序控制指令
程序控制指令是SCL编程的基础,接近高级语言的指令,虽然这些功能通过LAD/FBD也可以实现,但使用SCL编写会更加方便,逻辑条理也更加清晰。
程序控制语句说明选择IF-THEN语句用于将程序执行转移到两个备选分支之一(取决于条件为 True 还是 False);CASE语句用于选择执行 n 个备选分支之一(取决于变量值)循环;FOR语句只要控制变量在指定值范围内,就重复执行某一语句序列;WHILE-DO语句只要仍满足执行条件,就重复执行某一语句序列;REPEAT-UNTIL语句重复执行某一语句序列,直到满足终止条件为止;程序跳转CONTINUE语句停止执行当前循环迭代;EXIT语句无论是否满足终止条件,都会随时退出循环;GOTO语句使程序立即跳转到指定标签;RETURN语句使程序立刻退出正在执行的块,返回到调用块。下面详细介绍各条指令的用法。
(1)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"TrueFalseFalseFalse"Tag_2"FalseTrueFalseFalse"Tag_3"FalseFalseTrueFalse"Tag_Value"1020300
(2)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"01,3,56,7,8,9,1016,17,20,21,22,23,24,25其他"Tag_1"1----"Tag_2"-1---"Tag_3"--1--"Tag_4"---1-"Tag_5"----1
【文末免费领取学习资料】
【文末免费领取学习资料】
【文末免费领取学习资料】
(3)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]值3579结果a_array[2]a_array[4]a_array[6]a_array[8]值15253545
(4)WHILE:满足条件时执行
说明:使用"满足条件时执行"指令可以重复执行程序循环,直至不满足执行条件为止。该条件是结果为布尔值(True 或 False)的表达式。可以将逻辑表达式或比较表达式作为条件。
执行该指令时,将对指定的表达式进行运算。如果表达式的值为 True,则表示满足该条件;如果其值为 False,则表示不满足该条件。
也可以嵌套程序循环。在程序循环内,可以编写包含其它运行变量的其它程序循环。
通过指令"复查循环条件"(Continue),可以终止当前连续运行的程序循环。通过指令"立即退出循环"(Exit)终止整个循环的执行。
可按如下方式声明此指令:
WHILE <条件>
DO <语句>;
END_WHILE;
图12 WHILE语句
参数
下表列出了该指令的参数:
参数
数据类型
存储区
说明
<条件>
BOOL
I、Q、M、D、L
表达式,每次执行循环之前都需要进行求值。
<语句>
-
在满足条件时,要执行的语句。如果不满足条件,则程序将从 END_WHILE 后继续执行。
示例
图13 WHILE示例
下表展示了循环初始和循环结束时变量值的变化
初始循环结束Tag_25Tag_105
【文末免费领取学习资料】
【文末免费领取学习资料】
【文末免费领取学习资料】
(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_25Tag_106
(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"进行递增并接受检查。
(7)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 的条件。
【文末免费领取学习资料】
【文末免费领取学习资料】
【文末免费领取学习资料】
(8)GOTO:跳转
说明:使用"跳转"指令,可以从标注为跳转标签的指定点开始继续执行程序。
跳转标签和"跳转"指令必须在同一个块中。在一个块中,跳转标签的名称只能指定一次。每个跳转标签可以是多个跳转指令的目标。不允许从"外部"跳转到程序循环内,但允许从循环内跳转到"外部"。
注意:
LAD/FBD语言内的SCL段,不能使用GOTO指令。
跳转标签遵循以下语法规则:
字母(a 至 z,A 至 Z) 字母和数字组合;请必须字母为开始可按如下方式声明此指令:
GOTO <跳转标签>;
...
<跳转标签>: <语句>
示例
图22 GOTO示例
下表展示了每个操作数数值对目标变量的变化影响:
操作数值Tag_Value123其他
初始值结束值初始值结束值初始值结束值初始值结束值Tag_101000000Tag_201010000Tag_301010100Tag_401010101
根据"Tag_Value"操作数的值,程序将从对应的跳转标签标识点开始继续执行。例如,如果"Tag_Value"操作数的值为 2,则程序将从跳转标签"MyLABEL2"开始继续执行。在这种情况下,将跳过"MyLABEL1"跳转标签所标识的程序行。
(9)RETURN:退出块
说明:使用"退出块"指令,可以终止当前处理块中的程序执行,并在调用块中继续执行。
如果该指令出现在块结尾处,则可以跳过。
图23 RETURN语句
示例
图24 RETURN示例
如果"Tag_Error"操作数的信号状态不为 0,则将终止当前处理块中的程序执行。
(来源:网络,版权归原作者所有,侵删)
相关问答
plc枚举详细讲解?
plc枚举是说光波导位于一个平面内。正如大家所熟悉的单层电路板,所有电路都位于基板的一个平面内一样。因此,plc枚举是一种技术,它不是泛指某类产品,更不是...
plc如何定义变量类型?
PLC的变量需要自己定义的,PLC变量的数据类型主要如下:一.BOOL布尔型变量可被赋予“TRUE”真或“FALSE”假。这个值为逻辑量,占用1位存储空间可以看作是普...
关于PKS组态咨询-盖德问答-化工人互助问答社区
pks中文教材满世界都是,论坛百度下就行。其实仪表自动化学号是关键,编程了解组态就好作为用户,还是要参与组态和调试,这样能更好的做好维护的。可...