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结构化文本,在只能使用梯形图进行编程的情况下就不适合了。
|