CODESYS 梯形图批量生成

在 CODESYS V3.5 中批量生成重复梯形图(Ladder)梯级的实战参考——无需逐条手写。

CODESYS 梯形图批量生成
AI模型价格对比 | AI工具导航 | ONNX模型库 | Vibe Coding教程 | PLC在线仿真器 | Tripo 3D | Meshy AI | ElevenLabs | KlingAI | ArtSpace | Phot.AI | InVideo

在批量生成梯级(rung)方面,CODESYS V3.5 中的梯形图(LD)编程与 RSLogix 5000 / Studio 5000 的行为并不相同。RSLogix 5000 暴露了一种文本梯级语法(BST XIC BOOL1 NXB XIO BOOL2 BND XIC BOOL3 OTE BOOL4),可以通过剪贴板往返传输,让工程师能把梯形图片段粘贴到 Excel、Word 或 VS Code 中,对标签名列表执行字符串替换,再把结果粘贴回程序(routine)。CODESYS 并不通过剪贴板暴露这种文本表示。从外部编辑器粘贴产生的是一段纯文本片段,而不是结构化的 POU 主体,IDE 会直接拒绝它。

这份参考文档解释了 CODESYS 为实现同一目标(批量生成大量相似的梯级而无需逐条输入)所支持的机制。涵盖的方法包括:PLCopenXML 项目导出、IDE 内 POU 之间的复制/粘贴、Rename 重构工具、功能块(FB)实例化模式、FB 实例上的面向对象方法、用运算盒手工构建循环,以及 CODESYS Git 集成用于源码控制的现状。

下文中的菜单路径针对 CODESYS V3.5 SPxx。TwinCAT 3(Beckhoff)与它共享同一代码库,因此大多数操作可以一一对应。较老的 CODESYS V2.3 项目使用较旧的 3S 导出格式和不同的对话框集合;如果你需要 PLCopenXML 互操作性,请转换到 V3.5。

1. 为什么在 CODESYS 中直接外部复制/粘贴会失败

CODESYS 将每个 POU 主体存储在结构化的项目文档中。梯形图网络的剪贴板载荷是一系列结构化元素,而不是自由文本。当你在梯形图编辑器中选中一个或多个网络并按下 Ctrl+C 时,IDE 会使用类 ID、几何信息、变量引用和隐式类型限定符对所选内容进行序列化。任何接收到该剪贴板流的外部应用程序都会把它解释为一个没有可用文本表示的片段。

从外部程序粘贴回梯形图网络是对称的:接收方的 CODESYS 编辑器期望同样的结构化载荷,并丢弃任何不匹配的内容。你可能从 PLC-5 / SLC 500 / RSLogix 500 中记住的 BST XIC BOOL1 NXB XIO BOOL2 语法是罗克韦尔(Rockwell)的文本表示,专属于 Allen-Bradley 产品线,并不是 IEC 61131-3 标准特性。

操作 RSLogix 5000 / Studio 5000 CODESYS V3.5
将网络复制到外部文本编辑器 可以(通过剪贴板暴露文本语法) 不可以(结构化载荷,非文本)
将整个项目导出为文本 / XML 可以(L5X、L5K) 可以(按 IEC 61131-10 的 PLCopenXML)
跨项目重命名重构 可以(交叉引用、查找/替换) 可以(重命名重构、POU 内查找/替换)

2. PLCopenXML 导出:机器可读之路

PLCopenXML 是用于 IEC 61131-3 程序的 IEC 61131-10 XML 模式。CODESYS V3.5 实现了将项目、库或单个 POU 完整导出为 .xml 文件,该文件可以往返传输回任何兼容的 IDE(TwinCAT 3、Beremiz、PLCopen Tool 或另一个 CODESYS V3.5 安装)。导出菜单位于 Project > Export > PLCopenXML...

  1. 打开 CODESYS 项目。
  2. 选择 Project > Export > PLCopenXML...(或根据安装版本选择 File > Export Project as PLCopenXML)。
  3. 选择目标 .xml 路径。
  4. 在任何文本编辑器或 XML 感知工具中打开该文件。

生成的文档在顶层包含:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://www.plcopen.org/xml/tc6_0200">
  <fileHeader companyName="..." productName="CODESYS V3.5" />
  <contentHeader name="MyProject" version="1.0.0">
    <coordinateInfo>
      <pageSize x="1024" y="1024" />
      <fbd><variable /></fbd>
      <ld><variable /></ld>
    </coordinateInfo>
  </contentHeader>
  <types>
    <dataTypes> ... </dataTypes>
    <pous>
      <pou name="MAIN" pouType="program">
        <body>
          <LD>
            <xhtml:p>
              <LD>
                <powerRail />
                <contact refLocalId="0" ...></contact>
                <coil   refLocalId="1" ...></coil>
                <powerRail />
              </LD>
            </xhtml:p>
          </LD>
        </body>
      </pou>
    </pous>
  </types>
  <instances> ... </instances>
</project>

每个梯形图网络都是一个包含 LD 块的 xhtml:p。在块内部,contactcoilinVariableoutVariableblock(用于运算盒 / FB 盒)以及 connectionPointIn / connectionPointOut 元素描述了网络。变量引用使用 refLocalId 编号,这些编号解析到 <interface> 节、实例路径的 addData 条目或全局变量列表。

由于该文件是格式良好的 XML,你可以用一个简单脚本生成 36 个几乎相同的网络。一个最小的 Python 配方:

import re
src = open("Starter.xml").read()
template = re.search(r'(<xhtml:p><LD>.*?</LD></xhtml:p>)', src, re.S).group(1)

def numbered(n, name):
    s = template.replace('BOOL1', name)
    s = re.sub(r'(refLocalId=")\d+(")', lambda m: f'{m.group(1)}{n}{m.group(2)}', s)
    return s

networks = "".join(numbered(i + 1, f"BOOL{i + 1}") for i in range(36))
out = src.replace(template, networks, 1)
open("Starter_36.xml", "w").write(out)

使用 File > Import > PLCopenXML... 导入修改后的文件。CODESYS 在导入时验证模式,并报告任何损坏的引用。这是最接近 RSLogix 5000 文本工作流的方式:因为 XML 是文本,你可以在 Git 中对其进行 diff、分支和合并。

始终导出到新文件,而不是就地覆盖。CODESYS 不允许你重新导入当前正在编辑的文件;导入会创建一个新项目。默认情况下导入是追加式的:目标中已存在的同名 pou 会产生重复名称错误。

3. IDE 内复制/粘贴与跨 POU 复制

在 CODESYS 窗口之间以及同一项目内的 POU 之间,复制和粘贴可以完美工作。要在单个 POU 主体内批量生成相似网络,实用模式是:

  1. 在梯形图编辑器中构建一个使用占位符变量(例如 BOOL1)的网络。
  2. 选中该网络,按 Ctrl+C
  3. 粘贴 35 次到同一个 POU(或 35 次到不同的 POU)。
  4. 使用 Rename 重构工具,只把第一个粘贴的网络中的 BOOL1 改为 BOOL2,再把第二个中的改为 BOOL3,依此类推。

在梯形图编辑器中选中整个网络的方法是点击左侧边距的网络编号;Ctrl+点击 可将网络加入选中集合。多网络复制/粘贴会保留相对的垂直间距。

CODESYS V3.5 不会生成任何"选中网络"的文本格式,能经得起复制进记事本。如果需要把粘贴的文本纳入源码控制,请改用 PLCopenXML 导出。

4. 重构:Rename 与查找/替换

Rename 重构工具位于 Edit > Refactoring > Rename...(在选中的标识符上按默认快捷键 F2)。它会更新项目中对变量、类型、FB 或方法的每一个引用,包括:

  • 接口中的声明
  • 五种 IEC 语言(LD、FBD、IL、ST、SFC)中的读取和写入
  • 监视列表、库和可视化表达式中的引用
  • 通过 {attribute 'linkalways'} 杂注的外部引用

该工具会显示一个预览对话框,列出每一次替换。用它一步把占位符变量重命名为最终名称,而不是使用文本编辑器中的查找/替换——后者还会改写不相关的标记。

要在 POU 之间进行字符串替换,Edit > Find and Replace 会在 Devices 或 POUs 视图中搜索代码的文本表示。在梯形图网络中,搜索命中的是变量标签和内联字符串,而不一定覆盖所有隐式连接。保存前务必在屏幕上核对替换结果。

| 工具 | 范围 | 使用场景 | | --- | --- | --- | | Rename 重构(F2) | 项目中的单个标识符 | 复制/粘贴后重命名占位符 | | 查找/替换 | 当前 POU 内的子串 | 批量导入后的清理 | | 交叉引用(Alt+F12) | 符号的所有读/写 | 验证重命名没有破坏任何内容 | | 在项目中搜索 | 跨所有 POU 的 Grep | 查找标签的所有使用位置 |

5. 最佳实践:将重复逻辑转换为功能块

如果你正要复制 36 条结构相同的梯级,正确的答案几乎总是:编写一个功能块(FB),然后实例化它 36 次。复制/粘贴批量生成中的重复代码模式是一种代码坏味道:散布在许多梯级中的相同逻辑,比一个 FB 加一个实例数组更难修复、更难测试、也更难进行版本控制。

对于典型的"启动 + 过载 + 运行反馈"梯级,梯形图元素如下:

元素 符号 含义
常开触点(NO)
将输入读取为布尔值
常闭触点(NC) /
OTE 线圈 —( )— 写入布尔输出
OTL / OTU —(L) / —(U)— 置位 / 复位
运算盒 带标签的方框 内联表达式,例如 ADD、EQ
FB 实例盒 带实例名的方框 调用功能块

一条梯级的浓缩形式成为 FB 的主体:

FUNCTION_BLOCK Starter
VAR_INPUT
  bStart        : BOOL;  // momentary start pushbutton
  bStop         : BOOL;  // NC stop pushbutton
  bOverload     : BOOL;  // NC overload contact
  bRunFeedback  : BOOL;  // contactor auxiliary
END_VAR
VAR_OUTPUT
  bRun          : BOOL;  // contactor coil
END_VAR
VAR
  bSeal         : BOOL;  // seal-in (latching) bit
END_VAR

FB 的梯形图主体是一个带自锁(seal-in)分支的网络。每台电机变成一行代码,而不是每个电机一条梯级:

Starter_1(bStart := BOOL_Start1, bStop := BOOL_Stop1,
          bOverload := BOOL_OL1,  bRunFeedback := BOOL_FB1);
Starter_2(bStart := BOOL_Start2, bStop := BOOL_Stop2,
          bOverload := BOOL_OL2,  bRunFeedback := BOOL_FB2);
... 34 more lines ...

用单个 ST 或 LD 网络中的 36 个 FB 实例调用替换 36 条梯级,可以将源码体积缩小一个数量级,消除复制粘贴错误类别,并给你一个修复 bug 的单一位置。

如果 FB 必须保留在梯形图中,实例调用就是梯形图网络中的 block with instance(带实例的块)元素。CODESYS 将它绘制成一个矩形框,左边是 FB 实例名和标准输入引脚,右边是输出引脚。你可以把 36 个这样的框并排放在一个网络中,并一步将全局使能信号连接到所有实例上。

6. FB 实例上的面向对象方法

自 CODESYS V3.5 起,功能块 POU 可以声明 METHOD。方法以 instance.MethodName(arg1, arg2) 的形式调用。这是给每台电机赋予自己的"运行"逻辑、同时用单个方法作用于全部 36 个实例而不写 36 个显式调用的最干净方式。

METHOD Run : BOOL
VAR_INPUT
  bStart : BOOL;
  bStop  : BOOL;
END_VAR
IF bStart AND NOT bStop THEN
  Run := TRUE;
ELSE
  Run := FALSE;
END_IF;

要对数组中的所有实例运行该方法,可以在结构化文本(ST)中使用 FOR 循环,或用运算盒在梯形图中构建等价逻辑(见第 8 节)。梯形图视图本身无法承载 FOR;你需要切换到 ST 动作或单独的 POU 来放置循环体。

FOR i := 1 TO 36 DO
  aStarter[i].bRun := aStarter[i].Run(
      bStart := aStartBtn[i], bStop := aStopBtn[i]);
END_FOR;

7. 在梯形图中构建 FOR 循环

CODESYS 梯形图不提供原生的 FOR 网络元素。CODESYS 工程知识库记录了标准的变通方法:用标准运算盒构建循环。步骤如下:

  1. 使用 MOVE 盒在第一个网络中初始化循环索引 i := 1。循环启动触发器上的上升沿触点使能该盒,使其每个扫描周期只运行一次或仅在跳变时运行。
  2. 将循环体放在第二个网络中,以 ADD 盒结尾来递增 i := i + 1
  3. LT 盒比较 i < 36;通过 JMP 将结果接回循环体顶部的标签,或通过 CAL 盒重新进入第一个网络。
  4. 在完成或遇到停止条件时将 i := 1 复位。

所需的结构元素都可以在梯形图工具箱中找到:

  • 触点:常开 —| |—、常闭 —|/|—、上升沿 —|P|—、下降沿 —|N|—
  • 线圈:—( )—、取反 —(/)—、置位 —(S)—、复位 —(R)—
  • 运算盒:MOVEADDSUBMULDIVMODGTGEEQLELTNEANDORXORNOTSELMUXLIMIT
  • 跳转:JMP,带目标标签
  • 返回:RET,提前离开 POU

一个梯形图形式的最小模式:

Network 1 (initialize, on first scan):
  —[P]_bCycleStart—[MOVE 1 -> i]—

Network 2 (loop body, top of loop):
  label: LOOP_TOP
  —[i < 36]—[CALL aStarter[i].Run]—
  —[ADD 1 -> i]—
  —[JMP LOOP_TOP]—   (jumps unconditionally back to label)

在 CODESYS 梯形图中 JMP 线圈是无条件的。循环守卫由另一个网络强制执行,当 i >= 36 时用 JMP 跳出到 LOOP_END 标签:

Network 3 (exit condition, runs in parallel):
  —[i >= 36]—[JMP LOOP_END]—

Network 4 (the rest of the program):
  label: LOOP_END
  ... non-loop logic ...

这种风格冗长且容易出错;对于任何真实世界扫描中循环超过少量元素的情况,更推荐在方法或动作中使用 ST,并只调用该方法一次。CODESYS Forge 工程讨论帖"How to write a for loop in ladder?" 描述了同样的模式,是手工构建循环的权威参考。

8. Git 集成与外部 Diff/Merge

CODESYS Git 插件通过 CODESYS Store 分发,为 IDE 添加了提交、分支、合并和 diff 操作的 Git 窗格。它进行 diff 的文本表示是 PLCopenXML 导出,而不是 IDE 的实时状态。对于不安装该插件的团队,推荐的工作流是:

  1. 将项目维护为一个目录,其中包含签入 Git 的 .project.library 和 PLCopenXML .xml 文件。
  2. 在每次提交前使用 Project > Export > PLCopenXML 生成干净的文字快照。
  3. 使用标准 Git 工具对该快照进行 diff 和合并。
  4. 拉取队友的变更时重新导入 XML。

即使没有任何源码变更,CODESYS 项目的 PLCopenXML 导出在不同导出之间也不是字节完全相同的。元素顺序、ID 分配和时间戳字符串都可能变化。如果你想要稳定的合并,请配置 Git clean/smudge 过滤器或"忽略空白与重排"的 diff 驱动。大多数团队只在有意的源码编辑时才提交,并接受这种变动。

对于 TwinCAT 3 用户:TwinCAT 3 XAE(eXtended Automation Engineering)环境构建在 CODESYS V3.5 之上,相同的 PLCopenXML 导出在 TwinCAT > PLC > Export PLCopenXML 下可用。TwinCAT 添加了一个供应商特定的 <vendor> 元素,但除此之外都是合规的。从 TwinCAT 3 导出的梯形图网络可以导入 CODESYS V3.5,反之亦然,前提是梯形图引用的供应商库在目标 IDE 中可用。

9. 推荐工作流:生成 36 条重复梯级

把这些技术综合起来,下面是在 CODESYS V3.5 中不逐条输入即可生成 36 条几乎相同的启动器梯级的现场验证工作流。

9.1 在三种策略之间选择

策略 最佳适用场景 工作量 可维护性
一个 FB,36 个实例调用 所有梯级共享相同的逻辑形态,只是标签名不同 最低 最好
PLCopenXML 脚本变换 你需要纯梯形图网络,且不含 FB 调用 中等 良好(Git 中的 XML diff)
复制/粘贴 + Rename 重构 你只需要 5-10 条梯级,且每台电机的逻辑确实不同 对大规模 N 而言很高 最差

9.2 分步:FB 实例化

  1. 在 Devices 树中右键点击设备,选择 Add Object > POU...,命名为 Starter,类型为 Function Block,实现语言为 Ladder
  2. 定义第 5 节中展示的 VAR_INPUT / VAR_OUTPUT / VAR 段。
  3. Starter 内部构建一个实现自锁启动器逻辑的梯形图网络。
  4. MAIN(或任何消费方 POU)中声明实例数组:aStarter : ARRAY[1..36] OF Starter;
  5. 在单个梯形图网络中放置 36 个实例盒(或写 36 行 ST 代码),并将每个调用接到各自的标签组。
  6. 编译、登录、下载,并根据接线图验证接触器时序。

9.3 分步:PLCopenXML 变换

  1. 在梯形图中构建第一条启动器网络,使用占位符标签名 BOOL1BOOL2BOOL3BOOL4
  2. Project > Export > PLCopenXML,保存为 starter_template.xml
  3. 运行一个脚本(Python、PowerShell、XSLT),将第一个 <xhtml:p><LD>...</LD></xhtml:p> 复制 35 次,并把占位符替换为 BOOL5BOOL6、... BOOL40
  4. File > Import > PLCopenXML 导入修改后的文件。解决任何重复名称警告。
  5. 编译、登录、下载。

9.4 分步:复制/粘贴 + Rename

  1. 用单个占位符 BOOL1 构建第一条网络。
  2. 选中该网络(点击左侧边距),在同一个 POU 内 Ctrl+CCtrl+V 35 次。
  3. 点击第二个网络中的 BOOL1 标记,按 F2,输入 BOOL2。在预览对话框中确认。对网络 3 到 36 重复此操作。
  4. 交叉引用每个重命名后的标签,确认它在读和写上各只出现一次。

10. 验证、交叉引用与回归

无论你使用哪种方法,都要运行同一套验证。在 CODESYS V3.5 中:

  1. Build > Compile。在批量生成梯级组的首次启动期间,把每个警告都当作错误对待。
  2. View > Cross Reference (Alt+F12) 检查每个标签。每个标签的读取和写入次数应与梯形图意图一致(通常输出线圈一次写入,输入触点零次写入)。
  3. 在线:Debug > Login,强制每个输入为单个布尔值,并观察相应输出的跳变。监视列表通过 View > Watch 进入,或者把标签添加到可视化中观察值的变化。
  4. 如果项目有单元测试框架,运行它。CODESYS Test Manager(单独授权的产品)对已部署程序执行 ST 测试 POU,并记录通过/失败。
故障类别 症状 可能原因 修复
编译时符号重复 "Identifier 'BOOL1' is not unique" 粘贴的网络在触点中重命名了,但对应的线圈没有 运行交叉引用,跳转到重复处,手动重命名
插入隐式 FB 调用 "FB instance 'Starter_1' was not declared" PLCopenXML 脚本写了实例名,但忘记为实例声明添加 addData 条目 在 XML 的 POU 块中添加实例
循环永不终止 首次扫描时 PLC 看门狗故障 CODESYS 梯形图中的 JMP 是无条件的,循环守卫所在的并行网络在 JMP 运行前没有跳出 把循环体移入 ST 动作并调用它;切勿在 LD 中使用无条件 JMP 做控制流

不要期望 IDE 会解析从外部文本编辑器粘贴的梯形图网络。它不会。请使用 PLCopenXML 或 FB。只有实现 IEC 61131-10 的工具之间才保证往返传输;CODESYS 就是其中之一。

11. 现场验证的注意事项

  • 跨版本导入。 从 CODESYS V3.5 SP16 导出的 PLCopenXML 文件可以静默导入 V3.5 SP19,但从 V3.5 SP19 导出的文件可能包含较旧服务包无法理解的属性。项目团队应使用相同的服务包级别以避免此问题。
  • 库绑定。 如果网络引用了库 FB(例如标准库中的 TON),XML 导出会记录库版本。导入到没有该库版本的项目会产生黄色警告(而非错误),网络会显示红色"缺失"指示。请先安装该库。
  • 可视化绑定。 如果批量生成的梯级被可视化元素引用,可视化会以 GUID 存储该引用。在 POU 内复制/粘贴后无需重新绑定,但 POU 被重命名时则需要。
  • 加密。 使用 Project > Properties > Security 加密的库 POU 不会以人类可读形式导出到 PLCopenXML 文件中。XML 包含一个带有加密载荷的占位符元素。只要目标 IDE 有密码,就能编译项目;目标不需要源码。
  • 隐式 VAR 声明。 当你粘贴一个带引用变量的触点的网络时,CODESYS 不会像某些其他 IDE 那样在 POU 接口中自动声明该变量。你必须在 VAR 段或全局变量列表中声明每个变量,否则编译会因"Undeclared identifier"失败。

原文链接: CODESYS Ladder Logic Bulk Generation: PLCopenXML Export, FB Methods, and Loop Construction

汇智网翻译整理,转载请标明出处