
用户自定义指令RSLogix5000引入了可重用代码对象的概念,称为用户自定义指令。借助用户自定义指令可将最常用的逻辑封装成可重用指令集,这些指令集与Logix控制器中内置的指令非常相似。由于可在项目......
用户自定义指令
RSLogix5000引入了可重用代码对象的概念,称为用户自定义指令。借助用户自定义指令可将最常用的逻辑封装成可重用指令集,这些指令集与Logix控制器中内置的指令非常相似。由于可在项目中轻松地重用常用指令集,因而可节省时间;同时,又由于无论谁来实施项目,常用的算法都将按同样的方式工作,因而还有助于促进项目的一致性。
用户自定义指令可通过RSLogix5000中标配的梯形图、功能块图和结构化文本编辑器来创建。用户自定义指令创建完成后,您无需进行任何额外操作,即可在任意RSLogix5000编辑器中使用。此外,由于提供了上下文视图,使您能够查看指令在具体使用实例下的逻辑,用户自定义指令的在线故障处理工作也变得更为简单。同时,用户还可为指令自定义帮助信息,从而更便于指令用户获取所需帮助并成功使用指令。
最后,您可使用RSLogix5000源代码保护功能将使用您指令的某用户的访问权限设为只读,也可禁止指令用户访问该指令所使用的内部逻辑或局部标签。这样可以防止意外更改您的指令,也能保护您的知识产权。
启动RSLogix5000。
创建一个新项目,如下图所示:
单击“确定”(OK)接受新项目。
创建一个新的“用户自定义指令”1、创建新指令的工作流程包括:
预先设计/参数–这里的每一步都需要做很多工作
指令框架–为指令逻辑选择的语言
预扫描/后扫描行为–特殊情况需要
支持指令的标签结构–参数与局部标签。显而易见的是,这里所做的选择将影响用户自定义指令的外观
访问和检验要求–牢记不同语言环境的差异。
在本实验中,您将创建一个适用于工厂中所有泵的用户自定义指令。由于工厂中有多个泵,您需要一个可以重复使用的简单用户自定义指令。
输入应为:Start_PB(Bool)
Stop_PB(Bool)
Pump_Running(Bool)
输出应为:Run_Motor(Bool)
Pump_Start_Fault(Bool)
2、右键单击“用户自定义指令”(Add-OnInstructions)文件夹并选择“新建用户自定义指令”(NewAdd-OnInstruction)。
3、按下图所示填写“新建用户自定义指令”(NewAdd-OnInstruction)对话框,然后单击“确定”(OK)。
随后将显示许多新内容:名为Pump_Control的新用户自定义指令文件夹(其中包含参数和局部变量、逻辑)和一个新的附加定义数据类型。
注:一旦指定一种类型(梯形图、FBD或ST),之后便无法将定义更改为其它类型。如果要更改定义中的类型,则必须重新开始。
4、由于我们在上一窗口中选中了“打开定义”(OpenDefinition),将自动打开下面的对话框。
“常规”(General)选项卡中包含指令创建时首先输入的项目。
“版本注释”(RevisionNote)表格中的版本信息支持各种形式,并且完全由用户更新和使用;没有采用任何自动版本跟踪机制。
此窗口底部有几个项目,它们对用户始终可用。“逻辑”(Logic)按钮可直接打开此指令的逻辑例程。
“数据类型尺寸”(DataTypeSize)则动态显示指令数据将占用的总存储空间(以字节为单位)。
如果我们未选中“打开定义”(OpenDefinition),将不会打开该对话框。此时,我们应右键单击“Pump_Control”并选择“打开定义”(OpenDefinition)。
5、单击“参数”(Parameters)选项卡。
“EnableIn”和“EnableOut”参数为预定义参数,它们会默认添加到每一个用户自定义指令中。“EnableIn”受每种语言环境特有的因素影响,可用于执行特定的功能。这是一个高级主题,已超出本实验的范围。有关其它详细信息,请参见附录B。“EnableOut”通常会遵循“EnableIn”的状态,但可由用户编程操作。
“参数”(Parameters)选项卡是此用户自定义指令特有参数的标签数据库编辑器窗口,其中包括下列定义特定的字段:“用途”(Usage)、“默认值”(Default)、“要求”(Req)和“可见”(Vis)。
“用途”(Usage)允许用户将参数指定为:
“输入”(Input)指令的输入(基本类型)
“输出”(Output)指令的输出(基本类型)
“读写”(InOut)通过“引用”传递给到该指令的参数(可以是任意数据类型,包括UDT、数组等)
“默认值”(Default)允许用户为关联参数指定默认值。默认值是首次创建用于调用指令的实例标签时赋予参数的值。
“要求”(Req)-如为参数选中“要求”(Required),则用户要在例程中使用实例指令时必须输入一个标签或与此参数建立一个FB连接。这种调节机制定义了之后将进行的语言检验行为。选中“要求”(Required)的参数在默认情况下也会中“可见”(Visible)。
“可见”(Vis)-如果为参数选中“可见”(Visible),则在例程中使用该指令时,它将默认为可见。根据指令实例所采用数据类型和语言(LD、FB、ST)的不同,使用此调节机制将产生不同的
结果。
“描述”(Description)字段非常重要,因为这里使用的任何信息都将“传递”给用户程序中的所有指令实例。描述将自文档化指令用途、单位等信息。
6、输入如下所示的参数和规范:
单击空白的“名称”(Name)字段并输入新的参数名。单击“用途”(Usage)字段并使用下拉菜单进行选择。
用途“读写”(InOut)指示该指令通过“引用”传递数据。这相当于向指令传递一个“指向数据的指针”,而不是传递“数据的值”。使用数组、预定义结构或UDT作为用户自定义指令的输入时,应采用这种方式。
单击“数据类型”(DataType),然后单击省略号并选择数据类型。
根据需要,单击“默认值”(Default)并进行修改。根据需要选中“要求”(Req)或“可见”(Vis)。根据需要,添加描述。配置完所有字段后,按下Enter键或单击“应用”(Apply)按钮。
7、单击“确定”(OK)接受所做更改。
8、双击“逻辑”(Logic)按钮打开Pump_Control的空白梯形图逻辑例程。
用户自定义指令定义中的逻辑例程与使用右上角“数据背景”(DataContext)下拉菜单添加件选择的语言类型的任何例程都完全相同(后面将详细介绍)。
向逻辑例程中添加逻辑遵循的规则和惯例与在控制器中的任意位置编辑标准例程时遵循的规则和惯例相同。
9、向例程中添加以下逻辑梯级。注:此梯级的所有标签都已创建。
10、再添加一个逻辑梯级并添加定时器,如下图所示。
11、按下图所示填写对话框:
“局部标签”是仅限指令使用的标签,而不是仅限指令用户使用的标签。因此,当指令已在例程中实际使用时,数据结构中将不会显示这些标签。典型用途是用作用户自定义指令的内部指令标签,或用作某些运算中需要保留的中间值。这些标签只能在指令定义中查看。
12、单击“确定”(OK)关闭此对话框。
13、按下图所示完成梯级。
14、按下图所示再添加一个梯级。
15、保存项目。
16、右键单击Pump_Control文件夹(或逻辑例程),然后单击“打开定义”(OpenDefinition)。
或
17、单击“帮助”(Help)选项卡。
18、滚动浏览指令帮助预览。
19、关闭定义编辑器窗口并检验控制器。
使用新指令新指令可用于任何梯形图逻辑、功能块或结构化文本语言(包括SFC操作中的ST)。指令的外观符合所处的环境。在“参数”(Parameter)定义中进行的参数属性选择决定了在每种语言中的输入、检验和显示行为。
之前创建的用户自定义指令可从任意常规指令编辑机制访问:
指令工具栏中有一个“用户自定义指令”(Add-On)选项卡,其中列有项目中当前可用的所有用户自定义指令。
20、打开MainProgram的MainRoutine。
21、使用工具栏或指令名称向空白梯级中添加一个泵控制指令。
22、右键单击第一个问号(?)并选择“新建标签”(NewTag)。
23、按下图所示完成“新建标签”(NewTag)对话框,然后单击“确定”(OK)。
24、向指令中输入下面两个标签引用,如下所示。
25、逻辑梯级应如下所示:
26、检验RLL例程。
27、单击“属性”(Properties)按钮查看Pump_Control指令的参数。
28、单击“确定”(OK)关闭窗口。
接下来,我们将在FBD例程中使用刚创建的用户自定义指令。
29、在MainProgram下创建一个功能块例程,并命名为FB1。
30、在工作表中加入一个泵控制指令。
31、此时,检验例程。请注意报告的错误。另请注意,为便于识别,错误以蓝色文本显示。
之前定义该指令时,我们指定Start_PB和Stop_PB输入为必需。因此,需要在输入引脚的小块上进行连接。
32、向工作表中添加两个输入引用块,并将其连接到输入连接器上。
33、在与指令的Start_PB相连的IREF上双击“?”,并从下拉菜单中选择Pump_1_Start_PB。
34、将Pump_1_Stop_PB分配到其它输入引用。
35、再次检验例程。
36、单击“属性”(Properties)按钮展开指令的参数。
37、单击“确定”(OK)关闭窗口。
38、为该块配置一个输出引用,然后配置一个新标签并进行检验。
接下来,我们将在结构化文本例程中使用我们的新指令。
39、在MainRoutine下创建一个新的结构化文本例程,并将其命名为ST1。
40、双击ST1打开工作表。
41、从工具栏中添加Pump_Control指令,或者右键单击工作表,单击“添加ST元素”(AddSTElement)并从菜单中选择,还可直接键入。
42、右键单击Pump_Control指令并从下拉菜单中选择“参数列表”(ArgumentList)。
43、按下图所示完成参数列表:
44、单击“应用”(Apply)和“确定”(OK)。
45、右键单击结构化文本语句,选择“新建标签”(NewTag)并创建新标签Pump_1_Text。
46、单击“确定”(OK)关闭对话框。
47、在最后以分号(;)结束结构化文本语句。语句下方将显示一条下划线,表示存在语法错误。
48、展开控制器范围内的Pump_1_Text标签并查看标签结构。
49、检验ST例程。
50、向MainRoutine中添加以下梯级。
注:需要为TON创建新标签“free_timer”。
51、检验控制器并“保存”(Save)。
52、使用RSWho并从ETHIP向下展开到您的ENBT(IP地址在模块画面中提供,也列在您PC监视器的正面),从而将该项目下载到控制器中。将控制器置于运行模式。
53、双击“程序标签”(ProgramTags)打开标签数据库。
54、单击“范围”(Scope)下拉框查看可用标签范围列表。
55、展开“用户自定义指令”(Add-OnInstructions)文件夹并选择Pump_Control范围。
56、可看到“数据背景”(DataContext)下拉选择菜单。(如果“数据背景”(DataContext)灰显,则单击“监视器”(Monitor)选项卡。)
57、单击数据背景选择箭头,查看泵控制指令的可用背景列表。
58、选择除定义外的其它项。请注意,详细注释将列出相应指令在所选例程中的使用位置。
59、通过更改控制器范围的标签或更改梯形图指令的相应位来启动泵。
60、查看MainRoutine和FB1例程中执行的逻辑。请注意,该逻辑已设置为既包含正常运行情况也包含泵故障情况。应每隔5秒显示一个泵运行故障pump_running_fault。
61、打开MainRoutine,右键单击指令,并从下拉菜单中选择“打开指令逻辑”(OpenInstructionLogic)以打开RLL指令的逻辑。
62、将显示该指令一个特定实例的运行逻辑。
63、转到“数据背景”(DataContext)下拉菜单查看可用实例。
64、保存项目并断开与控制器的连接。
65、创建一个带有以下定义的新用户自定义指令。
66、单击“确定”(OK)接受更改。
67、将Pump_Control指令置于Nested_Pump_Control逻辑的梯级中。
68、右键单击问号并选择“新建局部标签”(NewLocalTag)。
69、在字段名中输入Basic_Pump_Contol。确保按下图所示完成对话框中的其余
部分。
单击“确定”(OK)接受新标签。
70、我们需要向块中添加输入选择。按下图所示添加两个输入。
注:创建两个新参数(不是新局部标签):New_Start_PB和New_Stop_PB。
通过这种方式,可像在“定义参数”(DefinitionParameters)中轻松创建一样,从逻辑编辑器中“动态”创建新参数。
71、创建以下输入和输出参数:
参数的顺序可通过类似UDT的方式使用“向上”和“向下”按钮更改。在将指令实例调整得更为紧凑时,此功能非常实用。
72、单击“确定”(OK)接受这些更改。
73、双击新指令的逻辑并添加以下两个梯级。
74、检验逻辑例程。
75、在MainProgram下创建一个新例程,并将其命名为Nested_Logic。
76、打开新例程并添加我们创建的新指令。
77、与之前一样,新指令需要一个支持标签。右键单击Nested_Pump_Control旁边的“?”并选择“新建标签”(NewTag),向指令添加Pump_1_Nested。将新标签命名为Pump_1_Nested。
78、右键单击“?”并选择新标签,向标签数据库中添加两个新输入标签Water_Level和Tank_Pressure。按如下所示进行命名。
79、向主例程中添加一个JSR。
80、检验例程。
81、下载项目并转为运行模式。
82、打开标签数据库并通过更改标签值来测试逻辑。
通过修改标签值来触发输出;Pump_1_Water_Level=1应开启排水,Pump_1_Tank_Pressure100时应生成超压报警。
83、将项目转为离线。
84、右键单击Pump_Control用户自定义指令并选择“导出用户自定义指令”(ExportAdd-OnInstructions)。
85、选择HOT2006文件夹作为目标位置并单击“导出”(Export)。
86、关闭用户自定义指令项目。
87、为控制器创建一个新的RSLogix5000项目,如下所示。
88、右键单击“用户自定义指令”(Add-OnInstructions)文件夹并选择“导入用户自定义指令”(ImportAdd-OnInstruction)。
89、选择恰当的文件,然后单击“导入”(Import)。
90、用户自定义指令导入完成。
91、按之前的方式,将该指令添加到MainRoutine下。
92、按之前的方式将逻辑添加到MainRoutine中,但由于我们将泵控制直接置于主例程之下,因此无需JSR梯级。
93、按如下所示,创建三个标签。
94、下载项目并确认指令按预期方式工作。
95、保存项目。
OEM例程保护目前,原始设备制造商(OEM)都在极力寻求能够使自己的程序不被复制和散布的方式,这种愿望比以往任何时候都更强烈。对于为SLC500编写程序的OEM,他们可以通过启用一个状态位的方式禁止硬盘上没有确切文件副本的用户查看梯形图程序。
从RSLogix5000版本8开始,用户可以保护为Logix系列控制器编写的项目,使其免受未经授权的访问。RSLogix5000中的OEM保护在例程级别发挥作用。即,源代码受密钥保护;密钥对于项目中的各个例程可以是唯一的。
从RSLogix5000版本11开始,源代码保护实用工具真正作为RSLogix5000的一部分进行安装,因此用户可以在RSLogix5000内部直接访问该实用工具,而不必通过单独的程序。
版本11的另一项新功能是可以选择将受保护的例程设为仅能查看不能编辑。在版本11之前,例程受到保护后不提供仅查看选项。
在本实验中,我们将使用随RSLogix5000光盘提供的免费源代码保护实用工具创建一个例程保护密钥文件。
打开您的用户自定义指令项目。
依次单击“工具”(Tools)、“安全”(Security)、“配置源代码保护”(ConfigureSourceProtection),如下所示。
3、出现以下提示时单击“是”(Yes)。
4、由于您的计算机还没有源代码密钥文件,系统会提示您选择创建该文件后的存储位置。单击省略号()来为源代码密钥文件选择一个位置。
5、选择HOT2006文件夹,然后单击“确定”(OK)。
6、单击“确定”(OK)接受该路径。
7、单击“是”(Yes)创建新的文件。
8、突出显示Pump_Control例程。我们要将此指定为秘密代码,不让任何其他人
查看。
9、单击“保护”(Protect)按钮。()
10、输入名称“secretaoi”作为源代码密钥的文件名,然后单击“确定”(OK)。
11、突出显示Nested_Pump_Control例程。我们希望能够查看此例程,但不能进行编辑。
12、再次单击“保护”(Protect)按钮。
13、我们将为此例程使用另一个源代码密钥,使得将来能够只取消其中一个例程的保护,同时保留对另一例程的保护。如果需要,我们可以对两个例程使用同一源代码密钥。键入源代码密钥的名称“view_only_aoi”,不包括引号。
14、单击允许查看的复选框。
15、单击“确定”(OK)。画面应如下所示:
16、关闭源代码保护配置窗口。
17、将项目另存为Add_On_Instructions_Protected。
18、关闭RSLogix5000。
19、打开RSLogix5000Add_On_Instructions_Protected,然后确认您可以查看这两个用户自定义指令的逻辑和指令定义。
通过源代码密钥添加保护后,为何还能够查看这些例程呢?源代码密钥仍然在我们定义的位置,因此密钥都在它们对应的位置,您拥有许可。一旦我们从指定位置移除源代码密钥,保护便会生效。
20、完全关闭RSLogix5000,不是只关闭项目。
21、右键单击包含源代码密钥的文件,即HOT2006文件夹下的。
22、单击“打开方式…”(Openwith…)。
23、如果弹出以下警告,请单击“打开方式…”(OpenWith…)按钮。
24、选择用写字板打开文件,单击“确定”(OK)。将出现以下画面:
因为源代码密钥在此位置,所以对于这些密钥在项目中对应的例程,我们拥有完全访问权。让我们看一下这是如何实现的。
从文件中删除secretaoi。
关闭并保存该文件,出现以下提示时单击“是”(Yes):
打开RSLogix5000。
打开项目Add_On_Instructions_Protected。
请注意,Pump_Control例程前已经没有“+”了。
双击Pump_Control。将打开指令定义对话框,但该对话框会灰显,并且左下角会提示“源代码不可用”(SourceNotAvailable)。
双击嵌套泵控制用户自定义例程。您会看到指令定义未灰显。
双击Nested_Pump_Control逻辑。您仍可以查看和访问该逻辑。
关闭RSLogix5000。
回到文件并删除view_only_aoi。保存文件。
再次打开RSLogix5000Add_On_Instructions_Protected项目。请注意,Nested_Pump_control例程前面仍有“+”,并没有像在保密的Pump_control例程中一样消失。
双击Nested_Pump_Control。将打开指令定义对话框,不过是灰显的。
双击Nested_Pump_Control逻辑。这次,您还是能查看该逻辑,但却没有权限进行更改。
RSLogix源代码保护工具的演示到此为止。
附录A–扫描模式
指令定义中的“扫描模式”(ScanModes)选项卡用于启用和编程以下三种专门扫描情形的例程:Prescan、Postscan和EnableInFalse。
Prescan例程:
Prescan例程在控制器从“编程”转到“运行”模式时执行。需要在指令执行前将内部变量初始化为特定的已知/预定义状态时,适合使用此例程。例如,在PID指令首次执行前将其设置为手动模式并且输出为0%。
要创建一个Prescan例程,在“扫描模式”(ScanModes)选项卡中单击“新建…”(New…)按钮。
用户可使用“类型”(Type)下拉列表选择要在编写例程时使用的语言(梯形图、功能块或结构化文本)。
选择语言并添加可选描述后,单击“确定”(OK)将向用户自定义指令的定义中添加一个“Prescan”例程,该例程可像任何其它例程一样进行编辑。
在控制器预扫描过程中,每个指令实例的逻辑例程都将在预扫描模式下扫描一次。如果在指令定义中添加了“Prescan”例程并且已启用,则“Prescan”例程将在逻辑例程预扫描后立即在正常模式下扫描。
Postscan例程:
Postscan例程将作为SFC步的后扫描结果执行(如果SFC已配置为“自动复位”(AutomaticReset))。如果将用户自定义指令用作SFC某一操作中的指令,则当该操作的步进行后扫描后,将执行Postscan例程。非常适用于在步执行完毕后自动复位内部状态或断开指令输出的情形。
要创建一个Postscan例程,在“扫描模式”(ScanModes)选项卡中单击“新建…”(New…)按钮。
用户可使用“类型”(Type)下拉列表选择要在编写例程时使用的语言(梯形图、功能块或结构化文本)。
选择语言并添加可选描述后,单击“确定”(OK)将向用户自定义指令的定义中添加一个“Postscan”例程,该例程可像任何其它例程一样进行编辑。
在后扫描过程中,指令实例的逻辑例程将在后扫描模式下扫描一次。如果在指令定义中添加了“Postscan”例程并且已启用,则“Postscan”例程将在逻辑例程的后扫描后立即在正常模式下扫描。
EnableInFalse例程:
对于“EnableInFalse”例程,无论采用何种语言,只要“EnableIn”参数为假(0)便会执行。主要用于在RLL程序中作为输出指令来构成“扫描错误”逻辑。“扫描错误”的常见用途是在之前的梯级条件为假时将OTE设置为断开。与此相类似,用户自定义指令也允许用户通过“EnableInFalse”功能自定义该机制。
要创建一个EnableInFalse例程,在“扫描模式”(ScanModes)选项卡中单击“新建…”(New…)按钮。
用户可使用“类型”(Type)下拉列表选择要在编写例程时使用的语言(梯形图、功能块或结构化文本)。
选择语言并添加可选描述后,单击“确定”(OK)将向用户自定义指令的定义中添加一个“EnableInFalse”例程,该例程可像任何其它例程一样进行编辑。
如果指令的“EnableIn”为假(0),逻辑例程将不会执行并且“EnableOut”将设为假(0)。如果在指令定义中添加了“EnableInFalse”例程并且已启用,也将执行“EnableInFalse”例程。
附录B–EnableIn/EnableOut每个用户自定义指令默认情况下都有“EnableIn”和“EnableOut”参数,这两个参数都具有符合不同语言环境(梯形图逻辑、功能块图、结构化文本)的特性。
执行基本逻辑例程时,“EnableIn”参数在任何语言环境中都为真(1)。一般来说,“EnableIn”参数不应被指令定义中的基本逻辑例程引用。
默认情况下,“EnableOut”会遵循“EnableIn”的状态,但是用户逻辑可以强制该参数的状态。
梯形图逻辑
在梯形图逻辑环境下,“EnableIn”参数反映了输入指令的梯级状态。例如:如果指令前的梯级状态为真(1),则“EnableIn”为真,并且将执行指令的基本逻辑例程。类似地,如果指令前的梯级状态为假(0),则“EnableIn”为假,并且将不会执行基本逻辑例程。
功能块
在功能块环境下,用户可以通过引脚连接来操作“EnableIn”参数。如果没有连接,则当指令开始执行时“EnableIn”参数会被设置为“真”(1),并会执行指令的基本逻辑例程。如果参数上的连接为“假”(0),则不会执行指令的基本逻辑例程。写入EnableIn参数的其它引用(例如,一个LLDOTU,或一个结构化文本赋值)不会影响该参数的状态。只有此参数输入引脚上的连接才能将其强制为“假”(0)。
结构化文本
在结构化文本环境中,默认情况下“EnableIn”参数始终设置为“真”(1)。用户无法对结构化文本中“EnableIn”参数的状态造成影响。