在工控行业混迹了十多年,一直做与PLC相关的项目,就把自己的一些经验做个总结,由于水平有限,有不足之处还望各位多多指教。
我刚接触PLC的时候是拿着一本廖常初老师的关于S7-200的教材入的门,廖老师的书里讲的步进编程的思想对我之后的PLC编程影响很大,这个思想的好处就是一步一步的执行,当进入下一步的时候同时退出上一步,在程序中只有一个活动步,使程序逻辑很清晰,缩小了问题出现的范围,而且在编程之前先画出顺序功能图,如果顺序功能图画的完整,按照功能图做出的程序基本上就没啥问题了。不论大小项目最好画个顺序流程图出来,养成好的习惯能达到事半功倍的效果。以下曾经做过的一个顺序流程图。
这个顺序功能图虽然花了不少时间,当时工期紧半自动都没试,直接投的自动,管道内可是焦炉煤气,同一根管道又进煤气又进空气,不停的切换,真是捏了一把汗,还好程序基本没啥问题。
做程序还要进行规划,将程序分成不同的控制单元,尽量减少单元之间的联系,举个简单的例子,项目中要用到罗茨风机,风机口有气动阀门,要求开风机的时候先开阀门,再起动风机,停止的时候要先停止风机后关闭阀门,我们可以将风机和阀门看做一个整体,将风机的起动和停止作为一个单元,别的程序段只负责起动和停止风机,不管风机起动和停止风机单元内部的逻辑关系。
作为一个合格的编程人员,程序和变量注释一定要写清楚,这是对编程人员最基本的要求,如果你还还在用绝对地址编程,那么需要想想自己是不是该换个工作了。
另外就是做程序不要怕复杂,不要觉得难就不做了,我们做自控的也算个技术活,用户很容易被忽悠,这是我搞工控这些年经常看到的事,用户提出了要求,只要在合理范围之内我们要尽量去满足,当你完成一次次的挑战之后,你会发现曾经的鸿沟不过是个小水渠,做程序就要自己给自己找困难,流行的一句话就是没有困难创造困难也要向前冲。
对以上我总结五点:
1、编程要有正确的方法,也可称为编程的指导方法。
2、养成画逻辑图的好习惯,画图的过程就是程序构思的过程。
3、规划程序结构,将程序规划成不同功能的小单元,减少不同单元之间的联系。
4、养成建立变量名、增加变量和程序段注释的习惯,一是为自己编程方便,二是为别人读你的程序时方便。
5、不断的挑战自己的极限在能够最大的进步,用户的苛刻要求总是成为你不断进步的推力。
今天就说这几条吧,这说不上是技巧,只是一个指导思想。如果有时间在讲解一下PLC编程的技巧。
楼主最近还看过
不能总是光说不练,今天就说一下步进编程的方法,步进编程指令在S7-200plc中有专用的指令,不过我自己也没有用过,记得三菱还是台达只能画步进指令图,转换不成步进程序,只是一个摆设。
在廖常初老师的书里关于步进编程的方法讲了很多,主要思想大概就是:首先要有一个起点,这个起点常常是机器的最初状态,比如气缸在电磁阀没有得电的位置,电机处于停止位置。这个第一步我们就用STEP0表示,当PLC上电或是进入一个工作模式后步进指令位于停止状态,当经过触发后进入下一个状态,当这个状态完成时,再进入下一个状态,中间经过一些状态后,最后回到起点,机器停止下来。这大概就是步进编程的思想。起点、触发、转换、条件触发……转换、回到起点,这只是最简单的单线步进编程,线数越多,程序就相对越复杂。
接下来说说步进指令实现的方法:
方法1:起保停逻辑,类似于电机的起停电路,上一步的作为转换到下一步的必要条件,下一步作为上一步停止的条件。如下图所示
方法二:置位复位逻辑,其原理与方法一相同,只不过换成了置位和复位指令,转换到下一步时需要上一步运行,当转换成功后复位上一步。
方法三:移位指令,与方法一和方法二不同的是,方法一和方法二都是在起始步时,通过触发条件实现自保持或置位,而移位呢是将一个字、字节或双字送入1,也就是将最低位置1,当触发条件到达时,左移移位,使整个字始终保持一个活动步,当然如果有分支这种方法就有点局限性了,不过可是通过多个字或字节来弥补,当到达分支时,将另外一个字送入1,形成两个分支。方法都是人想出来的。
编程的思想确定之后,实现的方法可以有很多种。
回复本条
今天做电力仪表的通讯,走的Modbus协议,采用Prosoft公司的MVI56E-MCMR模块(与ABPLC配套的模块,有些公司不做特殊模块,而委托第三方提供完全兼容的模块,ProSoft Technology就是为AB、施耐德提供这样产品的公司),通过MVI56E-MCMR模块我将电流表的数值读到模块自带的AOI数组中,读到的数据都是存储在这个整型的数组中,我需要将这些数据送入建立的变量中,既然这些仪表要读取的数据都是一样的,我就建个AOI程序块,同时建立一个自定义数据类型,AOI程序的功能是实现将MCMR数组中的数转换成我需要的数据,比如数组中都是整数,有些我需要转存成浮点数,有些需要做一下触发运算,自定义数据类型是为了放转换后的结果。
以上是转换程序,后面有问号的是自定义数据类型中的成员。
以上是自定义数据类型。
本来的程序准备只读数据,只要输入要读仪表在数组中的起始地址,和仪表要存储数据的自定义数据类型的变量名就行了,后来想了想还是把通讯状态字也加进去吧,通讯状态字与仪表数据不在一个连续的区域内,这就要有两个地址,一个仪表数据起始地址,一个通讯状态的地址。
完成上述工作之后,开始建立变量,批量建立变量的方法我曾经在论坛里讲过,http://bbs.gongkong.com/d/201706/718138_1.shtml
变量建完就开始调用程序,填写变量,调用程序的时候,发现一个站点仪表数量太多,有56台,这样要调用56次,觉得太傻,还是想想别的办法。AB1756的PLC与西门子的不同,间接寻址是通过数组实现的,就建立了两个数组,一个是AOI变量的数组,一个是仪表数据存储的数组。为之前建立的变量分配别名,AOI变量的别名是刚才建立的AOI变量数组的元素,数据变量的别名是数据数组的元素。如下图所示,别名在高级语言中常用,就相当于一个变量两个名字,我刚才做的工作就相当于将变量放在一个数组中,接下来的工作就是使用FOR循环指令了,先建立一个Routine子程序,如下图所示
这三行程序中唯一的变量就是PZ_E4_Com_Index,循环的次数,第一行用这个变量获取仪表数据的起始地址,第二行用来获取通讯状态的起始地址。第三行就是进行循环读取仪表数据,通过PZ_E4_Com_Index不断加一,循环读取每块仪表的数据,接下来的工作就是在FOR指令中执行循环程序,调用FOR指令如下图所示,
在FOR指令中输入Routine的名称,循环次数存储变量,循环初始值,结束值,循环的步间隔。好了万事大吉,上机测试没有问题。
跟大家说一下,我是第一次在AB软件中用循环指令,当看到它时我就知道怎么用了,PLC编程都是相通的,只是开发环境换了,深入弄懂一类PLC在学其它的就不难了。
我这也是用AB的PLC做的头一个项目,项目中5台冗余1756,接近四十台1769,电力仪表数据采集也就是一天就干完的活,这类重复性的工作没什么挑战性,难点还是在工艺和逻辑控制方面。
回复本条
项目中某个工段有21台PLC,一台PLC控制公用设备,同时协调其它PLC工作,做一段程序,对20台PLC进行排队执行某一相同操作,我们暂且命名为"过程A",同一时间只能有台PLC进行这个操作,所以要进行排队。
程序思路如下:
1、每台PLC分配一个序号,从1到20,当一台PLC需要执行"过程A"操作时,就要将A的序列号存入堆栈(其实堆栈就是数组操作,复杂的指令都是经过简单的指令组成的一个程序段罢了,就像我们所知道的计算机的基本指令就有0和1一样),当之前有PLC在执行"过程A"时,则进入堆栈队列,当之前PLC执行完后,进行一次出栈,出栈的数据与那个对象的序号相同就让那个对象执行"过程A"。
2、对排入队列的PLC进行排序,找出在堆栈的位置,发给20台PLC,让操作员能够在每台PLC的触摸屏上看到目前所排的位置。
3、当一台PLC刚开始申请了执行"过程A",已进入队列,由于某种原因,操作员取消了本次操作,需要将这台PLC从队列中去除,并将后面的成员向前排一位。
然后开始了解指令的使用,本程序中要用到的几个指令分别是:MOV(将序列号送入堆栈数组)、FFL(入栈指令,将PLC的请求排入队列)、FFU(出栈指令,将栈顶的数据推出,送入存储单元中)、EQU(相等比较指令,比较出栈后的数据与那个PLC的序号相等,NEQ(不相等比较指令,当堆栈数组的数据发生变化时,对堆栈数组执行一次数组的搜索和比较,找到每个PLC在数组中的位置),FSC(数组搜索和比较指令,当数组数据改变时执行一次),OTU(复位FSC指令,使其重新开始搜索),ONS(脉冲触发指令,由于FSC指令需要先复位,才能开始新的搜索,所以用数据变化上升沿作为第一个周期先去复位FSC指令,然后用数据改变的下降沿去进行数据的搜索和比较)
以上是用到的一些基本指令。
发帖时经常遇到帖子违规,被无情删除的情况,告一段落就赶快发一段。
回复本条
以上是我做程序的一段思路,有个很有用的技巧,就是利用数据的变化作为触发下段程序的条件,举个例子吧,比如使用了一个双字作报警的存储,每位代表一个报警变量,当有新的报警时,就触发一次报警器,工人消音后,报警器复位一次,当再有新的报警时再次触发报警器,比较常规的做法是对每个报警做一个上升沿触发,如果我们有32个报警,就要写32行,如果我们利用报警双字的变化和比较指令就可以两行完成,我们将报警变量命名为Alarm_Var,再建一个变量与报警变量使用相同的数据类型,命名为Alarm_Var_Temp,报警器命名为Alertor,第一行我们要做的工作就是比较变量是否有变化,我用伪指令来说明,IF(Alarm_Var>Alarm_Var_Temp) And (Alarm_Var<> Alarm_Var_Temp) Then Alertor=1 End IF,下一行 Alarm_Var_Temp=Alarm_Var,将Alarm_Var的值赋给Alarm_Var_Temp,使两者再次相等。
不知道你是否看明白了。
回复本条