购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

第3章

S7-200 SMART PLC基本指令

本章主要讲述如何学习和测试指令并学会基本的应用。常用指令有位逻辑指令、系统时钟、比较指令、定时器、计数器、传送指令和数值计算等。

3.1 位逻辑指令

3.1.1 常开和常闭触点

如果启动按钮接开点,停止按钮接闭点,对应的启停程序如图3.1所示。为什么【停止按钮I0.1】在程序里采用常开触点呢?以【启动按钮I0.0】为例,如果外部接常开触点,按下按钮程序里边的I0.0会接通,就是动作接通。如果【停止按钮I0.1】外部接的是常闭触点,不按下按钮就是接通的。按照操作过程来理解一下程序就是:当按下启动按钮,不按下停止按钮时,就开始运行。对于初学者可能不好理解,大家可以进一步对比并理解一下急停故障程序。

图3.1 启停程序

如图3.2所示,【急停按钮:I0.3】外部接常闭触点,程序里也采用常闭触点。外部同样都是接的常闭点,程序中有的需要用开点,有的需要用闭点。初学者就会困惑:怎么与以前学的电气理论知识不一样呢?PLC输入信号全部作为采集使用,采集完输入信号后的逻辑控制全部由PLC程序来执行。结合下图理解一下输入信号接通原则:灯亮开点亮,灯灭开点灭,开点和闭点总相反。

图3.2 急停故障程序

数字量输入部分,外部使用的开关和按钮什么时候接常开,什么时候接常闭呢?外部的开关和按钮接开点和闭点取决于控制系统的设计者,设计者是根据现场使用工艺来确定的。凡是涉及安全和关键部分的,都要保证在外部器件损坏的前提下也必须能停止工作,以免对人员造成伤害和对设备造成损坏。如停止、限位和急停等外部开关都是接常闭触点,当开关损坏以后,PLC程序会立刻收到一个停止信号或者故障信号。因为接常闭触点,正常情况下,PLC输入模块会一直采集到信号,但一旦信号丢失,通过故障程序就能停止相关设备运行。相反,如果采用常开触点做停机类故障,在正常情况下,外部开关和按钮动作以后,PLC才会采集到一个信号,一旦外部开关或者按钮损坏,将无法及时给PLC反馈一个停机信号,从而导致不能及时停机,这样便容易造成事故。

程序里使用常开或者常闭到底跟哪个因素有关系,对应到程序如何编写呢?PLC的数字量输入模块采集开关或者按钮的信号,如果启动按钮接的是常开触点,当按下该按钮以后,PLC才会收到信号,按钮要用什么触点状态,取决于编程人员,编程人员如何使用,取决于工艺。一般工艺要求是:按下启动按钮,在无故障的前提下,设备系统开启。由于按下按钮的动作触发了该事件的启动,那么程序要体现出按下按钮这个过程。如果按钮接的是常开状态,按下按钮后程序里的常开触点亮,那么程序用常开触点;如果外部接的是常闭状态,不按按钮程序里的常开触点就会亮。按下按钮后程序里的常开触点就会灭,而对应的常闭触点才会亮。初学者可以实际编程体验一下。通过表3.1可以理解外部接线和程序的常开触点和常闭触点的关系。

表3.1 外部接线触点和程序触点接通对应表

3.1.2 取反

取反指令(NOT),取反能流输入的状态。

NOT触点会改变能流输入的状态,能流到达NOT触点时将停止。没有能流到达NOT触点时,该触点会提供能流,即NOT是对逻辑结果进行取反。

如图3.3所示,程序段3和程序段4都是为了表达早班不运行的时候,晚班才运行。对V20.1的状态取反就是V20.1的常闭触点的状态,所以程序段3和程序段4中的V30.1的输出结果一样。一般采用程序段4的方式来编写程序,而程序段3的方式就显得复杂了。

图3.3 取反程序对比1

如图3.4所示,程序段5和程序段6都是为了描述能陪孩子的时间,除每个月1日的8点到12点之外的时间都能陪孩子。

图3.4 取反程序对比2

为了表示能陪孩子的时间,程序段5采用了NOT指令,程序显得简洁很多。

通过图3.3和图3.4的对比,图3.4的情况更适合使用NOT指令。要表达“除什么之外的情况”采用NOT指令较为合适。

3.1.3 线圈的使用

凡是数字量输出都需要用到线圈,中间变量的输出也需要用到线圈,如:M10.0的输出。一般M点的输出可以理解为中间继电器输出,Q点的输出是驱动外部器件的输出。Q点可以输出电压,其他的输出点不可以。如S7-200 SMART中的V100.0用作线圈输出和S7-1200中的DB100.DBX0.0用作线圈输出,都是中间继电器输出。

一般输出线圈在同时执行的程序中只能出现一次,出现两次或者多次则属于多线圈输出错误。此时程序不会报错,但是程序会按照最后一次扫描的状态来执行输出,这样会导致程序执行的混乱和逻辑错误。

同一个线圈的辅助触点是可以无限次使用的,如M10.0的常开触点和常闭触点都是可以无限使用的。但是同一线圈的常开触点和常闭触点的状态总是相反的。当线圈接通时常开触点就闭合,常闭触点就断开。当线圈断开时,常开触点就断开,常闭触点就闭合。输出线圈遵循一个原则:同一线圈的常开触点和常闭触点的状态总相反。结合图3.5的程序进行测试并理解上文讲到的触点和线圈的接通原则。

图3.5 自保程序

理论上在同一个程序段是不允许出现多线圈的,但是有些程序不仅出现了双线圈还出现了多线圈,并且也不报故障。情况一:多个子程序不同时被调用,在每一个子程序都可以出现一次该线圈。例如:子程序SBR_0和SBR_1里同时都使用了Q0.0的线圈,只要子程序SBR_0和SBR_1不同时被调用就没有问题。情况二:采用顺控程序,不同的顺控程序里可以调用同一个线圈。由于顺控程序只执行结构体内的一小段程序,而两个或者多个顺控程序也不同时执行,所以实际意义上也不是多线圈的同时使用。

总结:只要程序中没有同时接通的双线圈或者多线圈即可。

【扩展理解】 一个人不能在同一时空的同一时间点出现。例如,2019年9月9日,小徐在北京;2019年9月9日,小徐在天津;2019年9月9日,小徐在上海。那么2019年9月9日这一天小徐到底在哪里?看似很矛盾,其实他可能从北京到了天津,又从天津到了上海,是在同一天完成的,也就是在同一天存在了3个空间。只要从时间上严格区分开是没有问题的。双线圈也是这个道理,只要不是在同一时间出现,从形式上来讲是双线圈或者多线圈是没有问题的。但是如果这个双线圈同时发生了,肯定只有一个线圈会接通。就像2019年9月9日9点9分9秒,小徐只能在现实空间中的一个地方一样。

3.1.4 置位和复位

如图3.6所示,程序段1采用了置位指令S,按下启动按钮(I0.0)置位M10.0。程序段2采用了复位指令R,按下停止按钮(I0.1)复位M10.0,停止按钮外部接常闭触点。程序段1中M10.0下方的1表示置位的位数,如果改成2,就是置位M10.0和M10.1;程序段2中M10.0下方的1表示复位的位数,如果改成3,就是复位M10.0、M10.1和M10.2。

图3.6 置、复位1

如图3.7所示为SR触发器的使用。该指令为置、复位一体的指令,且为置位优先。当置位信号S1和复位信号都为1时,输出为1。当S1输入端和R输入端都接通时,置位有效,此时M10.1接通并保持。

图3.7 置、复位(置位优先指令)

如图3.8所示为RS触发器的使用。该指令为置、复位一体的指令,且为复位优先。当置位信号S和复位信号都为1时,输出为0。当S输入端和R1输入端都接通时,复位有效,此时M10.2断开。

图3.8 置、复位(复位优先指令)

置位的作用是一直让该数据位保持为1,复位的作用是一直让该数据位保持为0;置位作用时间为瞬动,就是激活置位以后无须再持续给信号,复位也一样,激活复位以后也无须持续给信号。

采用置位优先和复位优先的指令是为了区分置位条件和复位条件同时接通时的情况。当置位和复位同时发生时,置位优先的就会执行置位,而复位优先的就会执行复位。

置位可以理解为:某事件发生后,将这个事件写到记事本上,不管什么时候查看记事本,这个事件一直记录着。复位可以理解为将记录的这个事情从记事本上划掉了。只要不划掉,记事本将一直记着这笔账。

线圈可以理解为:事件发生以后,记性好的可能多记一会,就是用了自保。记性不好的,转身就忘记了,这是没有自保的。

如何区分置位优先还是复位优先呢?S为set的代号,表示的是置位,R为reset的代号,表示的是复位,SR触发器是置位优先,RS触发器是复位优先,哪个代号在前边就是哪个优先。针对程序指令的区分就是哪个代号带有“1”就是哪个优先。另外“1”也可以理解为“接通”的意思,所以带“1”的优先。

3.1.5 上升沿和下降沿

如图3.9所示,事件发生的最前端触发的边沿叫上升沿,事件结束的最末端触发的边沿叫下降沿。上升沿和下降沿属于瞬间动作,可以理解为沿的发生几乎不占用时间。如图3.10所示,用启动按钮(I0.0)的上升沿来置位M10.2,用停止按钮(I0.1)的下降沿来复位M10.2。启动按钮(I0.0)外部接常开触点,上升沿是刚按下启动按钮的瞬间;停止按钮(I0.1)外部接常开触点,下降沿是按下停止按钮的那一瞬间。

图3.9 上升沿和下降沿发生示意图

图3.10 上升沿和下降沿的使用

在编程的过程中很多情况都需要用到边沿触发,如:计数器、Modbus通信和运动控制等。有时候可以不用上升沿和下降沿,而是用逻辑控制来达到一个边沿触发的效果。

3.2 系统时钟

3.2.1 读取时钟

READ_RTC是读取时钟指令。读取系统时钟并存放到指定的数据区。如图3.11所示,指定读取后存放的起始地址是VB100,那么读取的时间会依次存放在从VB100开始的8字节内,依次存放的是:年、月、日、时、分、秒、X(未定义)和星期。读取后的数值是以BCD码(十六进制)显示,如果想要显示十进制的数据就要进行数据转换。

图3.11 读取时钟

如图3.12所示,该监控表是读取时钟后的变量数值显示,可以选择监控的变量区域和数值,监控数据的格式可以根据需要进行调整。由于读取的时钟采用十六进制显示才正常,可以使用数据转换指令将数据转换为需要的格式。

图3.12 读取时钟存放状态表

如图3.13所示,有两种将十六进制显示转换为十进制显示的思路。第1种思路:用B_I指令将Byte转成Int,将数据宽度由8位变成16位,然后再利用BCD_I指令实现数据格式显示的转换。转换前为十六进制显示,转换后为十进制显示。第2种思路:做一个进制转换的子程序,如图3.13所示的第二行程序,用子程序来实现数据的转换显示。

从PLC内部读取的时钟未必是准确的,因此需要将PLC的时钟设置准确。第1种方法:通过人工输入来设置时钟,人工输入时会核对准确后再设置时钟。第2种方法:如果触摸屏的时钟是准确的,将触摸屏的时钟设置给PLC。设置时钟后要核实时钟是否写入成功。

图3.13 十六进制转十进制显示

时钟一般用于通过时间来控制外部设备的场合或者利用时钟来设定设备使用的有效期。

3.2.2 设置时钟

如图3.14所示,从VB200开始的6字节分别存放年、月、日、时、分、秒,然后通过设置时钟指令(SET_RTC)将从VB200开始的6字节存放的时间写入CPU内部,指令中用到的地址是用户自定义的。设置时钟前,需要将设置的时间分别写入对应的数据区(将VB200到VB205进行赋值),然后再写入时钟。由于PLC内置万年历,设置好日期后星期会随着日期自动变化,所以星期就不用手动设置了。该程序要表达的意思为:通过V60.0的上升沿给PLC设定时钟为2018年09月01日09时18分0秒。

图3.14 设置时钟并赋值

如图3.15所示,VW830和VW834为触摸屏设置时钟的变量,需要将VW830和VW834都转换为BCD码,然后存放在对应的字节中。

图3.15 年和月数据转换

数据转换过程如下:先通过I_BCD指令将十进制数转换为BCD码,再通过I_B指令将16位的数据转换为8位的数据。

利用上述方法将年设定参数VW830转换后存放在VB200中,将月设定参数VW834转换后存放在VB201中。正确调用设置时钟指令(SET_RTC)后,可以将年和月设置完成。

3.2.3 实例应用

接下来看一个定时响铃的案例。如图3.16读取系统时钟,读取的时钟存放在VB800开始的区域。

图3.16 读取时钟

如图3.17所示,将时钟转换成需要的数据格式。将存放时的VB803转换后存放在VW902中,同理依次转换了分和秒的显示,分别存放在VW906和VW910中。

如图3.18所示,当时间为12时0分时,从0秒到15秒响铃;当时间为17时30分时,从0秒到15秒响铃。

本案例通过读取时钟和数据转换获得系统时间。如果时间准确,将继续沿用当前时钟,如果时间不准确,就要利用上文讲到的设置时钟的方法来纠正时钟。读取时间后,控制每天的12时开始响铃并且响铃15秒,每天17时30分开始响铃并且响铃15秒。如果这个案例应用到学校放学响铃,那么就需要加上星期的控制(如周六和周日休息而不需要响铃),读者可以思考如何完善和修改程序。

图3.17 数据转换

图3.18 定点响铃

3.3 比较指令

3.3.1 比较指令

比较指令用于两个数据的比较,不同的数据类型采用不同的比较指令。

如果要做无符号整形减法运算,就要先比较数值大小,然后再进行减法运算。必须是同一数据类型的数值才能做比较。数据类型可以理解为容纳数据的盒子,盒子一样大才能比较里面哪个盒子放的东西多还是少。涉及数据类型的区分,本书将在第15章做详细的讲解。

比较的结果有6种可能:大于等于、大于、小于等于、小于、等于、不等于。所以每一种数据类型的比较,都将出现6种结果中的一种,具体使用哪种比较方式,取决于比较结果的应用,需根据实际情况而决定。

如图3.19所示,程序段1为无符号字节的6种比较关系;程序段2为有符号字整数的6种比较关系;程序段3为有符号双字整数的6种比较关系;程序段4为有符号实数的6种比较关系。把数据类型的比较指令列举出来方便对比学习。图3.19中都是变量与数值作比较,也可以用两个同一种数据类型的变量进行比较。

图3.19 比较指令对比

编程时进行数据运算和处理的过程中需要用到比较指令。在实际编程的过程中,存在不同数据类型的比较,例如想用VD108的数值和计数器C1的数值作比较。计数器C1的数据宽度是16位,VD108的数据宽度是32位,那么需要将计数器C1的数据宽度转换成32位,并且必须是同一种数据类型才能进行数值比较。

3.3.2 比较指令的应用

如图3.20所示工艺过程是:如果VD200大于等于VD204,那么就置位传感器故障;当VD200小于VD204时按下复位按钮可以复位传感器故障。

图3.20 传感器故障程序

如图3.21所示,需要大数减去小数。两个比较指令存在着一个交叉点,即当两个数相等时,两个比较值都会接通,这样便会导致逻辑混乱。在编写程序时,可以选择一个比较指令用“大于等于”,另一个比较指令用“小于”,这样就不会有交叉,而且从逻辑上也好理解。

如图3.22所示为比较指令的组合使用。要表示一个温度区间,设定的温度是25.0~26.0℃之间,如果包含两边的临界点,需要添加等于;如果不包含临界点,就不需要添加等于。

图3.21 减法运算

图3.22 满足温度比较

如图3.23所示,程序段3也是比较指令的组合使用,用于表示两种不同的温度区间。区间1:VD108小于25.0;区间2:VD108大于26.0;如果V600.0接通,在任何一个温度区间内T50开始计时,T50接通后复位V600.1。

图3.23 区间的表达

如图3.24所示为比较指令的综合使用。当小时显示(VW902)为23时,并且人员计数(C1)大于0时,将C1赋值给VW700。

图3.24 不同的比较组合使用

3.4 定时器

3.4.1 定时器的编号

如表3.2所示,定时器的编号用定时器的名称和数值编号(最大为255)来表示,即T***。如:T51。定时器的编号包含两方面的意义:定时器的类型和时基(分辨率)。定时器既可以位操作,也可以整数操作。

表3.2 定时器

定时器位:与其他继电器的输出相似。当定时器的当前值达到设定值时,定时器的触点动作。

定时器当前值:存储定时器当前所累计的时间,用16位有符号整数来表示,最大计数值为32767。

3.4.2 定时器的类型

根据分辨率区分:1ms定时器、10ms定时器和100ms定时器。

1.1 ms定时器

对于1ms分辨率的定时器来说,定时器位和当前值的更新与扫描周期不会同步。对于大于1ms的程序扫描周期,定时器位和当前值在一个扫描周期内刷新多次。

2.10 ms定时器

系统在每个扫描周期开始时自动刷新,由于在每个扫描周期只刷新一次,故在一个扫描周期内定时器位和定时器的当前值保持不变。

3.100 ms定时器

该类型定时器在定时器指令执行时被刷新,因此,100ms定时器被激活后,如果不是每个扫描周期都执行定时器指令或在一个扫描周期内多次执行定时器指令,都会造成计时失真。在跳转指令和循环指令中使用定时器时要格外注意:100ms定时器仅用在定时器指令在每个扫描周期只执行一次的程序中。

根据接通类型区分:TON、TONR和TOF。

TON:接通延时定时器,用于测定单独的时间间隔。

TONR:保持性接通延时定时器,用于累积多个定时时间间隔的时间值。

TOF:断开延时定时器,用于在OFF条件之后延长一定时间间隔。

3.4.3 定时器的应用

如图3.25所示,V1.5、V100.0和V0.4都接通以后T45开始计时,T45累加到30后定时器T45接通,然后利用T45的常开触点来置位V103.3。延时时间为3s,即3000ms(30×100ms)。

图3.25 定时器的使用

如图3.26所示,V1.5、V100.0、V0.6和Q0.1都接通以后T43开始计时,T43延时6s接通,T43的常开触点置位V101.1。

图3.26 定时器触点的使用

如图3.27所示,3种方法都可以实现1s的延时,如果根据延时需求来选择定时器,则应该选择100ms分辨率的定时器T52较为合适。如果需要实现8ms的延时,就要选择1ms分辨率的定时器T32较为合适。在选择定时器时要根据控制要求来选择对应分辨率的定时器。

以上讲的都是延时接通定时器,延时断开定时器原理与延时接通道理类似。延时接通定时器相当于通电延时型时间继电器,而延时断开定时器相当于断电延时型时间继电器。

图3.27 定时器分辨率的确定

还有一种定时器就是保持性接通延时定时器(TONR),可以理解成带记忆功能的定时器。例如总延时60s,在计时20s时条件断开,该定时器依然保存原来的时间值20s,条件再次接通时继续在20s的基础上累加。

【扩展理解】 定时器的作用就是延时,延时的时间可以为固定值也可以为变量。延时的作用一般用于某动作或事件发生之后的延时,或者用于状态的延时。状态的延时一般用于过滤不稳定的信号。例如信号不稳定带来的故障或者程序执行逻辑的瞬间错误等,加上延时可能就会过滤掉。延时的主要目的就是等待时机,等延时到了以后,再触发其他事件的发生。

3.5 计数器

计数器指令有增计数器(CTU)、减计数器(CTD)和增/减计数器(CTUD)3种类型。如图3.28所示为3种不同类型的计数器指令。

图3.28 计数器分类

增计数器指令:每次CU加计数输入从OFF转换为ON时,CTU加计数指令就会从当前值开始加计数。当前值Cxxx大于或等于预设值PV时,计数器位Cxxx接通。当复位输入R接通或对Cxxx地址执行复位指令时,当前计数值会复位。达到最大值32767时,计数器停止计数。

减计数器指令:每次CD减计数输入从OFF转换为ON时,CTD减计数指令就会从计数器的当前值开始减计数。当前值Cxxx等于0时,计数器位Cxxx接通。LD装载输入接通时,复位计数器位Cxxx并用预设值PV装载当前值。到0后,计数器停止,计数器位Cxxx接通。

增/减计数器指令:每次CU加计数输入从OFF转换为ON时,CTUD加/减计数指令就会加计数,每次CD减计数输入从OFF转换为ON时,就会减计数。计数器的当前值Cxxx保持当前计数值。每次执行计数器指令时,都会将PV预设值与当前值进行比较。

达到最大值32767时,加计数输入处的下一上升沿导致当前计数值变为最小值-32768。达到最小值-32768时,减计数输入处的下一上升沿导致当前计数值变为最大值32767。

当前值Cxxx大于或等于PV预设值时,计数器位Cxxx接通,否则,计数器位关断。当R复位输入接通或对Cxxx地址执行复位指令时,计数器复位。

图3.29为计数器的应用。程序段1,V20.1接通后通过SM0.5(1s脉冲时钟)的上升沿来触发计数器C11来计数,V20.0接通后复位计数器C11,计数器C11的数值清零。PV预设值=10000,当计数到10000后C11的常开触点接通,C11会继续计数。

图3.29 计数器应用

程序段2去掉了上升沿,通过C12来计数,其他条件与程序段1一样。监测结果发现C11和C12两个计数器数值一样,说明计数器本身自带边沿检测。

减计数器和增减计数器同增计数器的使用方法类似。如图3.30通过传送指令判断出计数器为Word或者Int数据类型,数据宽度为16位,计数数值范围是-32768到32767之间。如图3.31所示用C2和VB10作比较,数据类型为Byte,C2报警,证明C2的数据类型不是Byte。通过C2跟VW100作比较不报警,判断出计数器的数据类型。

图3.30 计数器通过传送指令赋值

图3.31 计数器用在比较指令

3.6 转换指令

如图3.32所示,该数据转换在时钟设置时讲过。B_I由Byte变为Int实现了8位数据到16位数据的转换,BCD_I实现了数据格式的转换,而数据宽度不变。

图3.32 十六进制转十进制显示

如图3.33所示,ROUND指令是将数据四舍五入后计算,最后转为整数。TRUNC指令是将数据的小数部分去掉,只保留整数部分。在使用的过程中一定要注意二者的区别。

数据转换指令是把已有的数据转换成编程指令需要的数据。假如需要将VB10里存的数转换为实数。如图3.34所示为数据转换的过程,先用B_I指令转换为Int,再用I_DI指令转换为DInt,最后用DI_R指令转换为Real类型。

图3.33 取整和截取

图3.34 字节转换成实数

3.7 传送指令

传送指令也就是赋值指令,赋值指令后边都跟着数据类型,即在赋值的时候一定是同一数据类型的赋值。如图3.35所示,不仅数据长度有区分,数据类型也有区分。简单说赋值就是把一个盒子里的东西拿出来放到另外一个盒子里,但是两个盒子大小要一致(数据宽度要一致),可以把小盒子里的东西放到大盒子里,但是要是把大盒子里的东西放到小盒子里,有可能放不下,造成数据溢出。官方约定:传送指令的输入和输出需要采用同样的数据类型。常用的赋值指令有4种:MOV_B、MOV_W、MOV_DW和MOV_R,可对不同的数据类型进行赋值操作。

如图3.35所示,将32767赋值给VW300;将327670000赋值给VD304;将32767.0赋值给VD308。这些赋值可理解为将数据放到带地址编号的盒子里,即将数据32767放到名为VW300的盒子里,盒子大小有16个数据位。将数据327670000放到名为VD304的盒子里,盒子大小有32个数据位,盒子小了也放不下。将数据32767.0放到名为VD308的盒子里,盒子大小有32个数据位。当然也可以把一个盒子里的数据放到另一个盒子里。

图3.35 数据传送

如果对多个数据区域进行赋值,难道也要一个一个传送吗?不是的,此时可利用专门的块传送指令,如BLKMOV_B,对连续的多个字节进行赋值和传送。

如图3.36所示,第一行程序是数据区的连续传送,将VB10开始的连续10个字节赋值给VB500开始的连续10个字节。

图3.36 数据块传送

第二行程序是将VW500的高低字节互换,这个将在使用通信程序的时候用得到。此处VB500是127,那么VW500是多少呢?这个取决于VB501是多少,VW500实际数值是多少并不知道,只知道高8位和低8位互换以后是65407。SWAP指令是将一个字的高八位和低八位进行互换,并且显示。

127和65407为十进制显示,其他进制显示:HEX为十六进制,DEC为十进制,BIN为二进制。从十六进制数据看,如图3.37所示,一个是7F,一个是FF 7F,不像是对等高低字节调换,那么可以利用程序测试一下SWAP指令。

如图3.38所示,将127赋值给VW500和VW510,单次赋值,并利用上升沿触发。

如图3.39所示,为了验证VW510这个盒子中127是如何存放的,以及到底是存在了VB510还是存在了VB511,可以监视一下数值,发现127存放在了VB511这个小盒子里。使用SWAP指令以后VW500数据变成32512,但是VW510是127。通过监视发现VW510等于127的时候,将127存到了VB511,结论是VW510的存放顺序是VB510+VB511,VB510属于高位。

图3.37 不同进制转换

图3.38 数据监视1

图3.39 数据监视2

如图3.40所示,使用SWAP指令之前的数据显示VW500为127,VW510也为127。

VW500原来数值为127,单次使用SWAP指令后数值为32512,执行结果分析对比就会得出答案,如图3.41和图3.42所示。

图3.40 数据监视3

图3.41 执行SWAP前

图3.42 执行SWAP后

十进制数据不容易看出互换结果,十六进制数据显示很容易看出字节交换,执行调换指令SWAP以前为7F,也就是00 7F;执行SWAP以后变成了7F 00。

经过程序测试可以发现,在使用指令的过程中对指令的理解和分析必须到位。当对程序指令或者软件自带的块有疑虑的时候,务必进行测试和检验。

3.8 整数运算

整数运算包括加法运算、减法运算、乘法运算和除法运算。与数据比较和传送一样,数据运算都要在同一数据类型进行操作。

图3.43中的加法换成其他算法也是可以的,同一数据类型就像同一种颜色的水,如果混了其他颜色,最后的结果就会使颜色变混乱。数据计算也是一样,如果数据类型不一样是无法做运算的。

图3.43 加法示意图

1.加法运算

加法运算要注意数据类型和运算结果的存放。数据类型不一样,存放的最大数值就不一样。就像一个水杯,水杯做出来以后能装多少水是固定的,加多了就会溢出。如果数据盒子放不下所放的数据值也会使数据溢出并报错。

如图3.44所示,VW10写入32766,VW12写入1,此时进行加法运算,结果存放在VW100中。Word为16位的字,除了首位存放正负号,其他15位存放数据,存放的数值为32768(2的15次方)。这里的32768是指32768个数的位置,按照整数开始计算,从0到32767一共是32768个数,所以正数最大到32767,负数的数值区间是-32768到-1。

图3.44 加法运算1

如图3.45所示,VW10写入32767,VW12写入1,此时进行加法运算,结果存放在VW100中。当VW100存放32768时程序因为数据溢出而报警,因为16位数据宽度的数据存放的正数最大数值是32767,超过此值后会报警。

图3.45 加法运算2

2.减法运算

减法运算要注意数据类型和运算结果的存放,还有正负号的问题。

如图3.46所示,VW20写入1,VW22写入32767,此时将VW20减去VW22的数值存放到VW102中。16位数据的存放数值区间-32766~32767,作为整数运算这一点是不变的。所以计算结果为1-32767=-32766。

图3.46 减法运算1

如图3.47所示,VW20写入1,VW22写入32768,由于正数最大值是32767,所以赋值以后VW22变为-32768。计算结果是1-(-32768)=32769,监视VW102的数值为-32767。VW22已经超出最大值,数据溢出指令就会变红而报警。

图3.47 减法运算2

3.乘法运算

乘法运算要注意数据类型和运算结果的存放,要考虑到最后结果溢出的情况。要根据具体使用情况来确定使用指令和定义数据类型。

如图3.48所示,将VW30和VW32相乘的结果存放到VW104中。

图3.48 乘法运算1

如图3.49所示,将VW30和VW32相乘的结果存放到VW104中。2×32767=65534,由于VW104存放数值区间为-32768到32767,结果溢出而报警。

图3.49 乘法运算2

如图3.50所示,如果换成MUL指令就能实现更大范围的乘法运算了。将VW30和VW32相乘的结果存放到VD108中。而VD108数据宽度是32位,可以存放的数值是-2147483648到2147483647之间。乘法指令MUL默认的就是将运算结果存放在双字数据区中。

图3.50 乘法运算3

4.除法运算

除法运算要注意数据类型和运算结果的存放。主要是如何存放数据运算后的余数。

如图3.51所示为DIV_I指令的使用。VW40写入32767,VW42写入100,此时用VW40除以VW42,结果放在VW120中。32767÷100=327.67,由于DIV_I为整型除运算,则VW120为整型数据,所以只能存放327。

图3.51 除法运算1

如图3.52所示,VW40写入100,VW42写入200,此时用VW40除以VW42,结果放在VW120中。由于进行整数运算是不存在小数的,只要运算结果小于1,结果就是0。

图3.52 除法运算2

除法运算不涉及数据溢出的问题,而会涉及运算结果产生小数的问题。如果产生小数,小数部分都会被舍掉,这样计算出来的实际数据就失真了。如果不想让数据失真就要转换成实数,采用DIV指令来计算。

如图3.53所示为DIV指令的使用。VW40写入32767,VW42写入100,此时用VW40除以VW42,结果放在VD124中。其中VW124存余数,而VW126存商。

图3.53 除法运算3

5.递增和递减运算

如图3.54所示,给VB200赋值1,正常执行INC_B指令后,计算结果加1。指令INC_B每执行一次计算结果加1。

图3.54 递增指令1

接下来实际测试一下此运行过程。如图3.55所示,M10.0写入ON再给M10.0写入OFF,将VB200和VB400全部赋值为1。

图3.55 递增指令2

如图3.56所示,接下来测试INC_B指令,给M10.1写入ON,VB300和VB400都变成2了。如图3.57所示,再次接通M10.1,VB300数值没有变,VB400又加1而变为3。初步判断:INC_B指令的含义是使能接通一次,输入端数值加上1。

为了验证这个推论,再接通一次M10.1,看一下结果,如图3.58所示。如果推论成立:VB300数值会依然不变,而VB400又加1则变为4。证明推论是正确的:INC_B指令使能接通一次,输入端数值加上1。

图3.56 递增指令3

图3.57 递增指令4

图3.58 递增指令5

如图3.59所示,如果将边沿触发去掉以后看一下测试结果。强制M10.0接通并初始化赋值,再断开M10.0。强制M10.1接通以后,VB400的数值就一直在跳变,说明INC_B指令一直在执行,不停地加1,这样就不符合使用需求。所以在使用的INC_B指令过程中,一定要加上边沿触发。

图3.59 递增指令6

本章小结

初学者可以按照上图的程序段边学程序边测试一下结果并记录下来,这样就会发现不一样的结果。学习要深入,更要反复地测试。指令不懂或不熟悉,没有关系,只要知道如何测试和学习,知道如何去应用,学会现学现用,灵学活用就可以了。有的指令并不像我们看到的帮助文件说的那样。帮助文件只是提供一个基础性的理论讲解,深层次的理解需要测试或者应用才能得出正确的结论。 oQsbfChlZwg8BYhZjUr8rv6m7N01n0Wc5Dbrhl1fMyma7XdbE6S7cNBb1ilWVc6t

点击中间区域
呼出菜单
上一章
目录
下一章
×

打开