现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

AB PLC自学笔记

2008-12-05 09:24 工业·编程 ⁄ 共 11033字 ⁄ 字号 评论 1 条

以前断断续续的学了一点,但大多是三天打鱼两天晒网;也参加了一次培训,但是短短的课程、大量的产品介绍和难得的上机实验,很快就忘记了学了点啥。翻开以前的学习记录,零散而杂乱,不少要点看上去是那么陌生。也罢,再来一次打鱼又如何?

第一步,安装软件。

手上有去年培训的时候从老师那里搞来的16版本的logix5000,以前也安装过,里面有很好的英文语音教学,当时老师开玩笑说,可以锻炼下听力。安装完logix5000 V16,再安装一个模拟器软件:Emulate,安装过程中告诉我需要rslinx,昏,看来安装次序错鸟。其实在安装logix5000的过程中,最后一些小工具的安装也提示我需要rslinx的,被我忽略了。于是安装rslinx,再安装emulate。最后一步,把网上找来的授权导入。发现用老版授权的话,软件第一次运行会提示你,现在16版本采用所谓的factorytalk管理授权了云云,我不管,反正能用就行。

接下来的问题就是,怎么用这个模拟器?以前用过,但是忘鸟。只记得要选择一个特殊的硬件,还好有份模拟器的使用手册,简单看了下几个插图就回忆起来了,试了下,ok。个人觉得ab的emulate有点别扭,因为用惯了西门子的plcsim,那个不需要选择什么特殊的硬件,原工程就可以很仿真的download下去去模拟运行。而ab的东东,却不能用真正的硬件配置,那么一个实际个工程文件必须修改下controller才能去仿真了???

万事具备,就开始学习软件吧,从何入手呢?先找几个自己感兴趣的问题研究研究吧。先看看变量的定义,ab的独特之处就包括tag是以名称作为关键“索引”,没有西门子那种地址的概念,这样当然简化了开发。那么如何批量的导入/导出变量呢?我用s7的编程习惯是在excel里面编辑好变量表,再导入到程序里面。在logix5k软件里面找了下,果然可以,tools菜单下有import和export,试了下,跟西门子的symbol table一样,都是以csv文件保存的,不过也发现了中文注释偶尔会变“乱码”。记得看过讲关于如何解决ab导出变量表的中文乱码问题,找了下这篇文章,原来乱码其实是unicode码,作者编了个vb小程序,当然也可以在excel里面编写个vba代码,或者有人说用某网页的内码转换去解决也可以。(啥时候看看vba的书?)

接下来再看看16版本新增的add-on instructions,以前粗粗的研究了下,记得是可以编写自己的模块在各个工程间重复使用。于是决定用st编写一个max3函数,就是在三个real数据中找一个最大的。先定义接口变量,ab是在对话框里面定义,不象西门子的scl是完全手工输入变量定义。模块写好以后check没有error,然后在main program中调用,check一下却总是报错。弄了半天,才回忆起来以前碰到过这个事情,应该再定义一个类型为该模块的结构变量,调用模块时填这个结构变量名就行了。然而这样的话,如果要把某个外部io变量或者某个内部变量单独给模块的一个输入端,岂不是要先赋值给这个结构变量的其中一个?太麻烦了吧,也不合情理啊。再看看接口变量的定义,发现有req属性,看看help里面的描述,再测试了下,原来关键就在于req是否勾上了。勾上req以后,就可以用单独的一个tag去填到这个参数去了。下一步就是模块如何在工程之间复用呢?也很简单了,可以导入/导出成一个xml格式的文件,甚至可以用ie打开,毕竟是标准的xml格式嘛。

最后一个问题,是program的理解。以前做的笔记里面,写了默认每个task下面的第一个program是循环执行的,其余program是被调用的,测试下,果然如此。试着去修改program的属性,图标上面有个“1”就表示了该program是被执行的。碰到了调用program的问题,我找了jsr指令,ms一共有三种指令:jsr、sbr和ret,下次再研究吧。

ok,今天到此为止。

先解决上次遗留问题:JSR/SBR/RET三个指令有何区别?

看help里面描述:

The JSR instruction jumps execution to a different routine. The SBR instruction passes data to and executes a routine. The RET instruction returns the results.

从ST来看用法:

Main routine JSR(routine_1,2,value_1,value_2,float_value_1);

Subroutine SBR(value_a,value_b);

<statements>;

RET(float_a);

理解了,Jsr是调用子程序,sbr和ret是定义子程序的接口。试着写一个子程序,发现SBR和RET中的TAG既可以是Controller TAG也可以是Program Tag,但必须提前定义好,这有点麻烦,在project之间如何能复用呢?岂不是每次都要定义一下接口变量的tag???这难道就是以前ab被人说的不好的地方?不过既然如今有了add-on instructions,那么我想sbr指令可以少用点了。

去baidu了下,找sbr的帖子,果然有人问。

http://www.gongkong.com/Forum/ForumTopic.aspx?Id=2008042415271100001

帖子里面有人提到参数调用可以用中间变量来实现???难道是间接寻址??

接下来,不晓得该研究啥问题好了,脑子有点乱,干脆浏览一下logix5000编程手册:

第6章:别名(Alias)的用处:

可以给一个IO设备指定一个有意义的名称(因为IO设备tag由系统自动生成);-实质就是给外部IO变量命名

可以给数组的一个元素提供一个描述名;

第7章:间接地址

竟然是数组???误认为是间接寻址了。再次强调:ab没有地址的概念,只有tag名。

第8章:缓存IO的概念

由于IO数据刷新与程序执行不同步,因此可以在程序开始前copy一下输入信号标签,程序结束后把输出结果去更新实际的输出信号标签。这点类似于西门子默认的过程映象区的概念,很容易理解,只是ab需要自己做一下,而西门子是默认的。反过来说,ab是立即更新io,而西门子则需要指定一下。

第12章:控制器的串口连接ASCII设备

在controller属性里面可以选择串口采用system protocol还是user protocol,后者可以支持Ascii协议。

第15章:故障处理程序,看来类似于西门子的故障ob

第20章,加密程序。需要安装“rslogix5000源保护软件”?

16版本的Rslogix不需要象手册里面说的那样再安装保护软件,而是直接从tools菜单-security-configure source protection,如果系统找不到密码文件(sk.dat)则要先指定一个,加密完成后退出logix5000,然后把sk.dat文件移走就可以。需要解密的话,就需要指定该文件的位置。加密工程,还可以对整个project加密,似乎没有必要吧。

学的有点乱糟糟的,总结一下前面的成果:

1、软件安装,包括rslogix5000、rslinx和rsemulate

2、工程建立后,定义tag,批量导入和导出,中文乱码解决,tag的别名(alias)的用处,tag的scope要注意;

3、task和program的概念,连续和周期task,主program和subroutine,如何定义和调用subroutine(jsr、sbr、ret)

4、16版本新增的add-on instructions如何定义、导出和导入

5、编写了st和fbd的程序进行测试,有了初步映象

6、缓存io的概念和用法

7、cpu串口的设置,可以用来ascii通讯――有待后面仔细研究

8、程序的加密,某个子程序可以加密,整个project也可以加密

下一步,有几个问题要研究一下:

1、把以前在step7里面写的一些模块用ab来重写一次,熟悉一下基本指令的用法。

2、故障处理程序怎么写?

3、在线修改程序的问题

把以前写的几个西门子scl模块用ab的st语言重写一遍,包括流量开方、小信号切除和累积。发现写起来很轻松,麻烦点的就是ab的add-on instructions里面定义变量是填表格形式的,而西门子都是用文本形式自己输入的。代码就轻松多了,直接从scl里面copy过来,check一下有无错误,大部分语句都可以直接使用,但是在这里发现了几点st和scl的区别:

1、ab的st在某些方面比西门子的scl要严格一点,比如bool量的关键字,ab只支持0、1的赋值,不支持true、false(难道需要做什么设置么???),而西门子的scl是都支持的。又比如西门子的return语句,ab不支持,查了下,return语句是iec61131里面规定的一个标准语句。而在ab里面,找了半天,终于找到一个替代的指令:tnd。

2、西门子的in_out和out区别很大,尤其是用db变量赋值参数的时候,但是我没看出来ab的这两种参数有何区别?

另外,ab的add-on instructions调用时指定的结构变量,有点类似于西门子的fb的背景db。

下一步,写几个包含定时器和较多复杂指令的模块,进一步看看st和scl的区别。

关于定时器参数的用法,从工控网论坛上找到一篇帖子,写的很详细:

―――――――――――――――――――――――――――――――

RSLgix5000中子程序的内部使用的输入、返回参数称之为“形参”,子程序的调用者提供“实参”,以通过子程序完成某种控制要求。子程序是由“形参”代替“实参”来执行的,对于一般的如BOOL,DINT等的数据类型,可以很容易地实现“实参”对“形参”的赋值。但是,计时器等由于利用了CPU系统的资源,例如“时钟中断”等,因而不能像上述类型数据那样可以用赋值的方式实现。要想使用计时器就必须得声明一个,以便系统能对此计时器进行操作。如果子程序的“形参”可以是普通的计时器,那么对于N个子程序的调用,这个“形参”计时器就必须实现N个计时器的功能,显然对于只能完成一次计时的普通计时器是无法完成的,所以子程序中是不可能有普通计时器作为“形参”的。这样就可以理解为什么RSLgix5000子程序中,不能使用计时器作为“形参”。
但是,众所周知,西门子S7系列plc的Step 7编程软件中的FB,FC功能块,也就是子程序,可以实现计时器作为子程序的“形参”,这如何解释呢?其实,在STEP 7功能块,或者说是子程序中出现的计时器,虽然外形和普通计时器一样,但是根据上面的论述,我们可以确定其并非是普通计时器,而是一个“伪计时器”,真正的计时器应该是声明的那一个,也就是作为“实参”的那一个。由此可见,每当子程序被调用执行的时候,“伪计时器”将作为“实参”的那一个真正的计时器的参数,诸如,计时当前时间,计时时间到等参数读入,然后进行和普通计时器一样的操作。当然也包括将“伪计时器”的启动条件赋值给“实参”计时器,以便使“实参”计时器启动工作。这样就可以实现子程序中的计时器作为“形参”的功能。也是说,它的“形参”计时器是经过特殊设计的,并非普通的计时器。
因此,西门子Step 7中的子程序中的计时器,本质上依然使用了声明过的,子程序外部的普通计时器。对于RSLgix5000来说,要实现子程序中的计时器功能也是一样,使用子程序外部的计时器。

RSLgix5000子程序使用计时器的方法
由于在RSLgix5000梯形图子程序中,没有实现“形参”功能的“伪计时器”,所以只能在全局变量中声明的计时器。为了便于在子程序中使用这些计时器,我们将这些计时器放在数组里,这样子程序只需一个数组下标变量,就可以使用这些计时器。但是,很遗憾,在RSLgix5000梯形图中是无法使用数组下标变量的,因此,我们就只能使用ST即结构化文本,一种类似于PASCAL语言的编程工具,它提供完整的数组支持。
举一个例子,如果要实现3个计时器的时间设置工作,对于梯形图来说,即使是使用数组,由于它不能使用数组下标变量,也只能是采用一个一个的赋值方式,即,T[1].PRE = 1000,T[2].PRE = 1000,T[3].PRE = 1000等等。如果子程序也采用一个一个赋值的方式,就没有任何优势,还不如不使用子程序来实现,这样的子程序是毫无意义的(不带“形参”的子程序除外)。如果采用ST结构化文本,由于其数组下标可使用变量,就可以用子程序实现,子程序如下所示。
FOR I := 1 TO 3 BY 1 DO
T[I] := 1000;
END_FOR;
这样就很适合子程序使用,不管是有100个还是1000个计时器,也都只是使用这一个子程序,就可以完成所有计时器的计时时间设置工作。由于梯形图无法完成这样的工作,因此子程序中的计时器数组的使用,只能用ST结构化文本实现。
例如有2个相同控制要求的设备,用子程序来实现,如果每个设备需要使用3个计时器,那么需要声明含有2×3=6个计时器的计时器数组。设备1使用前3个计时器,设备2使用后3个计时器。在子程序中,设置一个DINT型的“形参”作为起始计时器号,例如设备1使用1,即从下标为1的计时器数组开始;设备2使用4,即从下标为4的计时器数组开始。
需要说明的是,在RSLgix5000中,ST结构化文本所用的计时器同梯形图所用计时器不一样,在ST结构化文本中是FBD_TIMER类型,使用时用TONR指令声明。
一个实例
我们以两个水泵的控制为例子进行说明。水泵A的启动输出信号为START_A;出水阀门A的打开输出信号为OPEN_A;水泵A启动反馈为STARTED_A;出水阀门A开到位反馈为OPENED_A;水泵A的启动运行输入信号PUMP_START_A;水泵A启动完成标志PUMP_A_STARTED。水泵B的启动信号为START_B,出水阀门B的打开输出信号为OPEN_B;水泵B启动反馈为STARTED_B;出水阀门B开到位反馈为OPENED_B;水泵B的启动运行输入信号PUMP_START_B;水泵B启动完成标志PUMP_B_STARTED。
控制要求为水泵启动5秒后打开出水阀门,水泵使用3秒的输出脉冲启动,出水阀门使用6秒的输出脉冲打开。这样每个水泵的控制,需要3个计时器。
为节省篇幅,这里省略了水泵停止部分的子程序,有兴趣的读者不妨自己实现。需要注意的是,水泵停止子程序要复位启动子程序中使用的计时器以及启动完成标志,启动子程序要复位停止子程序使用的计时器以及停止完成标志。梯形图主程序如图所示。
其中,TONR_TIMER为含有7个FBD_TIMER类型的计时器数组。计时器TONR_TIMER[0]没有使用。TONR_TIMER[1],TONR_TIMER[2],TONR_TIMER[3]用于水泵A的启动。计时器TONR_TIMER[4],TONR_TIMER[5],TONR_TIMER[6]用于水泵B的启动。JSR为子程序的调用指令。对于水泵A子程序,最后的Input Par为1,表示使用计时器数组中的前3个;水泵B子程序,最后的Input Par为4,是输入“实参”,表示使用计时器数组中的后3个。Return Par是输出的返回“实参”。MOV是赋值指令,Source为数据源。TONR_TIMER[].PRE是相应计时器的时间设定值。上面梯形图中的MOV指令实现的是对这6个计
时器的计时时间的赋值。
启动子程序使用ST结构化文本,其程序如下:
SBR(SBR_STARTED, SBR_OPENED, SBR_NUM);
TONR(TONR_TIMER[SBR_NUM]); //声明3个TONR型的延时开计时器
TONR(TONR_TIMER[SBR_NUM + 1]);
TONR(TONR_TIMER[SBR_NUM + 2]);
TONR_TIMER[SBR_NUM].TimerEnable := 1;//计时器1启动
SBR_START := NOT TONR_TIMER[SBR_NUM].DN;//水泵启动输出信号
TONR_TIMER[SBR_NUM + 1].TimerEnable := SBR_STARTED;//计时器2启动
TONR_TIMER[SBR_NUM + 2].TimerEnable := TONR_TIMER[SBR_NUM + 1].DN;//计时器3启动
SBR_OPEN := NOT TONR_TIMER[SBR_NUM + 2].DN AND TONR_TIMER[SBR_NUM + 1].DN;//出水阀门打开输出信号
SBR_STARTED := SBR_OPENED; //启动完成信号
RET(SBR_STARTED);
其中,SBR为子程序,括号内为输入“形参”,RET为子程序返回指令,返回输出“形参”。DN是计时器计时时间到;TimerEnable是计时器的允许启动。水泵的启动采用了3秒的脉冲信号,出水阀门打开使用了6秒脉冲信号。
当水泵A调用启动子程序时,使用的计时器从计时器数组TONR_TIMER[1]开始;水泵B调用子程序时,则是从TONR_TIMER[4]开始使用。虽然启动子程序是同一个,但使用的计时器是不一样的,这样就完成了在子程序中使用计时器。
结束语
由于在西门子Step 7子程序中已经内置了实现计时器的功能,所以我们也有必要在AB的RSLgix5000子程序中实现计时器功能,更何况需要有计时控制功能的子程序是大量存在的,不实现这一功能,意味着子程序几乎没有什么用处。
虽然本文中的具体实现方法与Step 7肯定是不一样的,但本质是一样的,都是利用了子程序外部的真实的计时器,通过真实的计时器实现计时功能。本文中,由于RSLgix5000无法使用“形参”,所以直接使用了外部真实计时器,而Step 7则是通过“形参”间接地使用了外部真实计时器。
从理论上来说,西门子的Step 7中的子程序,更好地体现了子程序的优势,通过特殊设计的“伪计时器”读取真实计时器的参数值,成功地把根本就不能将计时器作为子程序“形参”这一情况,在直观上得到彻底改变,方便了人们的使用。
而在RSLgix5000子程序中,只能直接使用外部真实的计时器。由于没有计时器作为“实参”和“形参”,所以无法全面体现出子程序的优势(在计算机高级语言的程序设计中,例如“C语言”,在子程序中使用全局变量,被公认为是不好的。但plc程序有自己不同于计算机程序的特点,不必拘泥于此)。但这也未必就是个问题,毕竟没有“伪计时器”功能,也就节省了其可能有的内存及执行时间的开销。如果说有不足的话,那就是使用了ST结构化文本,在只能使用梯形图进行编程的情况下就不适合了。

―――――――――――――――――――――――――――――――

但是我是要在add-on instructions中使用定时器参数,上述文章就不能完全照搬了。试了下,在add-on instructions的参数定义里面可以直接定义一个定时器数组,当然类型不能是input或者output,从这里我发现了in-out参数的作用,就是可以定义为结构变量、数组变量等复杂型的数据。

然后在程序里面写代码了,我直接从tonr指令的help里面贴了代码过来,居然出错,ft!!!

终于发现help中关于tonr指令的st写法是错的,原文如下:

------------------

TONR_01.Preset := 500;

TONR_O1.Reset := reset;

TONR_01.TimerEnable := limit_switch1;

TONR(TONR_01)

timer_state := TONR_01.DN;

------------------

第一句居然是错的!!!应该是TONR_01.Pre := 500;我这个汗啊!!!

此外,想起来曾经看到资料里面说controllogix的定时器数量只受cpu运算能力的限制。看这种定时器的写法,就是定义一个定时器类型的变量而已,感觉怪怪的,或许是习惯了西门子那种要指定定时器号的做法吧。Ab的变量,不管是普通的数据类型还是特殊的定时器、计数器都是起个名字就行了,方便啊。

接下来,我又想到了研究一下在Add-on instructions中调用另外一个Add-on instructions方法,试了一下也不难:

1、假设在名为Getmin的Add-on instructions中需要调用一个名为Min3的Add-on instructions,则首先在Getmin中定义一个类型为Min3的In_out参数(因为input/output类型的参数不接受结构型变量),例如叫in1;

2、在Getmin中用如下语句调用:Min3(in1);即可

跟以前调用子程序不同的就是,需要指定一个结构变量而已-又让我想起了西门子的fb。

试着写一个稍微复杂点的add-on instructions,logic检查无误,run起来却出错了,提示我这个错误:

(Type 04) Program Fault (can be trapped by a fault routine)

(Code 86) Access violation in user program.

Task: MainTask

Program: MainProgram

因为mainprogram只调用了这一个add-on instructions,检查到最后把所有logix语句都注释掉了还是错,看来是接口参数问题了,最后发现是定义的一个数组类型的in-out参数引起的,只要定义了数组参数就报错,昏!!!去查手册,里面明明说是可以的,而且还给出了例子,why?折腾半天也没结果,我开始怀疑rslogix5000或者是emulate的软件本身了,或许换个高点的版本???可惜一时找不到啊。于是找来手册细细的看下去。

在查阅手册的过程中,发现add-on instructions有不少缺点,比如有不少指令不能用,比如for指令,这让我大吃一惊。For指令不能用的话,循环怎么办?数组的操作呢?我不相信for指令不能用,尝试了下,居然可以啊,咋回事?可惜身边没有一台实际的plc让我测试下,否则前面的数组参数问题也可以得到印证!!!这两天折腾add-on instructions,越来越发觉这个东西做的很不成熟,后面再一一总结罗列出来吧(本来我对ab的东西感觉挺好,觉得是那种比较“高贵”的东东,现在折腾几天下来,却感觉在给工程师进行模块化、标准化的开发环境方面,相对s7来说,ab做的实在是比较差啊―――当然这也跟我刚刚开始学习ab有关系吧,总是带着西门子的眼镜来要求ab的东东)。

一直没有解决前面的add-on instructions的数组参数问题,所以都没心思继续研究雪鞋下去了,这个问题太打击人了。

今天想想还是找点其它事情做吧,于是就翻翻下载的《华章AB实验教程》,发现太简单了,跟去年培训的内容基本雷同。

――――――――――――――――――――

实验1:

主要议题:

-认识各模块

-RIUP

-通讯建立

其实就是rslinx的配置和使用。rslinx的优点是配置简单,还能直接扫描出硬件配置,不过版本要注意。

实验2:

主要议题:

-强大的编程能力

-面向未来的投资

所谓“强大的编程能力”,实验教材中体现为:

--io配置后自动生产丰富的信息,包括IO数据、故障信息、时标等等,确实很好很强大

--可以查看在线的数据趋势

所谓“面向未来的投资”,恐怕指的就是logix的固件升级和统一的软件平台吧。

实验3:

主要议题:

-代码重用

-节省开发投资

-系统规模可大可小

其实就是修改controller type,从controllogix改为compactlogix,体现了“面向未来的投资”

实验4:

创建一个项目,控制变频器的频率。这就涉及到了rsnetworx这个网络组态软件。

去年培训做个这个实验,确实很简单、方便。

实验5:

cpu对时,无非是cpu之间的通讯,去年培训也做过了,兴趣不大,跳过。

实验6、7:

rsview的,也没有兴趣。

有网友给我出了个题目,虽然我是ab新手,但是正好可以操练一番。

――――――――――――――――――――――――――

请教比较简单的addon的制作方法,比如定义一个简单的运算,我输入123456,输出是654321的规定,这样我用234对应432。该如何实现,

――――――――――――――――――――――――――――――――――――

第一感觉就是字符串颠倒,但是记得add-on里面的输入输出参数只能定义为int/sint/dint/real之类的简单类型,那么看来要转换数据类型了。于是打开logix5000软件里面的instruction help,找到了ASCII Conversion Instructions,里面有个dtos指令看来就是我需要的,把dint转换为string。于是定义了一个local参数,string类型,发现string参数有个len的“属性”(姑且这么叫吧,没看到相关资料的权威叫法),于是猜想就是该字符串的长度,于是在程序里面直接把该“属性”赋值给输出参数,测试一下,果然就是啊。接下来看看如何把字符串分解然后颠倒过来,本来想当然的要去找字符串函数(vb的思路),结果看了下string数据的结构,还有一个data数组,看来就是存储字符的,大喜,这下更easy了。用st写吧,定义的参数如下:

输入――IN1(DINT)

输出――OUT1(DINT)

LOCAL――TEMP_STR1,TEMP_STR2(STRING)/I,STR_LEN(INT)

开始代码是如此写的:

DTOS(IN1,TEMP_STR1);

STR_LEN:=TEMP_STR1.LEN;

IF STR_LEN>1 THEN

FOR I:=1 TO STR_LEN BY 1 DO

TEMP_STR2.DATA[I-1]:=TEMP_STR1.DATA[STR_LEN-I];

END_FOR;

STOD(TEMP_STR2,OUT1);

ELSE

OUT1:=IN1;

END_IF;

发现输出一直为0,很郁闷。开始怀疑for是否执行了,因为看手册里面说add-on不支持for指令,虽然前面曾经模拟过程序,表明for是可以执行的。后来又怀疑开始相信的len“属性”,发现都没问题。最后,我突然想到TEMP_STR2的len属性,发现居然是0!!!my god!再加一句话给TEMP_STR2的len赋值就ok了,最后代码如下:

DTOS(IN1,TEMP_STR1);//输入数据转换为字符串

STR_LEN:=TEMP_STR1.LEN;//取得字符串长度

TEMP_STR2.LEN:=STR_LEN;//转换后的字符串长度

IF STR_LEN>1 THEN//转换字符串

FOR I:=0 TO STR_LEN-1 BY 1 DO

TEMP_STR2.DATA[I]:=TEMP_STR1.DATA[STR_LEN-I-1];

END_FOR;

STOD(TEMP_STR2,OUT1);

ELSE

OUT1:=IN1;

END_IF;

目前有 1 条留言    访客:1 条, 博主:0 条

  1. TT 2012年03月26日 8:42 上午  @回复  Δ1楼 回复

    不用梯形图,LOGIX就废了80%

给我留言

留言无头像?