4. 产线控制程序结构设计

PLCnext Control 的程序结构设计,核心不是“把梯形图写出来”,而是先决定用哪些语言、把代码切成哪些程序组织单元(POU)、这些 POU 由哪些任务在什么周期下调用、变量放在什么作用域里。这四件事一旦定错,后期改一条产线节拍往往要动半个项目。本节以一条典型包装产线为例,说明如何把结构设计落到可执行的工程文件上。

一、语言选择:按“控制对象”分工,而不是按个人习惯

PLCnext Engineer 遵循 IEC 61131-3,支持 LD(梯形图)、FBD(功能块图)、ST(结构化文本)、SFC(顺序功能图)、IL(指令表)以及 C++/C# 等高级语言。实际项目中推荐按对象性质分工:

  • LD/FBD:用于安全联锁、急停链、气缸到位、输送线启停等布尔逻辑密集、需要电气人员现场读图的回路。
  • ST:用于节拍计算、配方换算、报警优先级排序、通信数据打包等含算术、循环、字符串处理的逻辑。
  • SFC:用于“上料—定位—压装—检测—下料”这类有明确步序和转移条件的工位流程。
  • C++/C#:用于视觉结果解析、复杂算法、与 MES 的 JSON 交互等标准 IEC 语言不擅长的部分,通过 PLCnext 的 SDK 编译为功能块供 IEC 程序调用。

示例:某压装工位用 SFC 描述 6 个步序,每步的转移条件用 ST 写成布尔表达式,而急停与光栅信号仍用 LD 单独成段,便于安全回路审查。这种“混合语言”是 PLCnext 的常态,不必强求全项目统一。

二、程序组织单元:把“设备”切成可复用的 POU

POU 分为功能(FUN)、功能块(FB)和程序(PRG)。结构设计的关键是:FB 对应可复用设备,PRG 对应产线层级。以包装线为例:

  • FB_Cylinder:封装单作用/双作用气缸的伸出、缩回、到位检测、超时报警,输入为 Cmd_Extend、Sensor_Ext、Sensor_Ret、Timeout,输出为 Done、Fault。
  • FB_Axis:封装伺服轴的使能、回零、绝对定位、状态字解析。
  • FB_Station:调用若干 FB_Cylinder 与 FB_Axis,组成一个工位。
  • PRG_Main:按工位顺序调用 FB_Station 实例,并处理线体级联锁。

每个 FB 实例必须显式命名,例如 fbCyl1_Clamp、fbCyl2_Eject,禁止使用匿名实例,否则在线监控时无法定位到具体气缸。FB 内部只使用 VAR_INPUT、VAR_OUTPUT、VAR_IN_OUT 和 VAR,不直接访问全局变量,保证可移植。

三、任务调度:周期任务与事件任务分开

PLCnext 的任务由资源(Resource)管理,常见配置如下:

任务周期/触发绑定 POU用途
Task_Fast2 msPRG_Safety急停、光栅、安全门
Task_Main10 msPRG_Main工位逻辑、气缸、轴控
Task_Slow100 msPRG_HMIHMI 数据刷新、报警汇总
Task_Event事件触发PRG_Trace故障录波、MES 上传

调度设计要点:快任务只放安全与高速联锁,不放通信和字符串处理;慢任务与快任务之间通过全局变量或 VAR_GLOBAL 交换数据时,必须注意数据一致性——例如 100 ms 任务读取 10 ms 任务写的结构体,应使用双缓冲或标志位,避免读到半更新数据。任务优先级由系统按周期自动排序,周期越短优先级越高,因此不要在 2 ms 任务里调用耗时 FB。

四、变量作用域:局部优先,全局只做“接口”

PLCnext 的变量作用域分为:POU 局部变量、程序局部变量、全局变量(VAR_GLOBAL)、以及带 RETAIN/PERSISTENT 的保持变量。推荐原则:

  • 设备内部状态一律用 FB 局部变量,外部只能通过输入输出引脚访问。
  • 跨工位共享的“线体状态”“当前配方号”“报警字”放在全局变量区,并集中在一个 GVL_Line 中声明,禁止散落。
  • 需要断电保持的计数器、配方索引使用 VAR_GLOBAL RETAIN;需要跨固件升级保留的用 PERSISTENT。
  • HMI 与 MES 只读写全局变量或专用接口 FB,不直接访问 FB 内部。
判断标准:如果一个变量只被一个 FB 使用,它就不应该出现在全局变量表里。全局变量表越长,程序越难维护。

五、模块化编程规范:命名、注释与版本

规范不是形式,而是让三个月后的自己能看懂。建议约定:

  • FB 命名:FB_设备类型,如 FB_Cylinder;实例命名:fbCyl_工位_功能,如 fbCyl_St2_Clamp。
  • 变量命名:输入 i_、输出 o_、局部 l_、全局 g_、保持 r_。
  • 每个 FB 头部写清功能、作者、版本、修改日期和调用示例。
  • 版本用 V1.0 形式,接口变更必须升版本并记录在 FB 注释中。

下面给出一个可直接参考的 FB 接口示例(ST 语言):

FUNCTION_BLOCK FB_Cylinder
VAR_INPUT
    i_Cmd_Extend : BOOL;   // 伸出命令
    i_Cmd_Retract: BOOL;   // 缩回命令
    i_Sensor_Ext : BOOL;   // 伸出到位
    i_Sensor_Ret : BOOL;   // 缩回到位
    i_Timeout    : TIME := T#3S;
END_VAR
VAR_OUTPUT
    o_Done  : BOOL;
    o_Fault : BOOL;
END_VAR
VAR
    l_Timer : TON;
    l_State : INT;
END_VAR
// 状态机:0=Idle,1=Extending,2=Extended,3=Retracting,4=Fault

该 FB 被 FB_Station 调用时,只需连接输入输出,不关心内部状态机。若某气缸需要 5 s 超时,只改实例参数 i_Timeout := T#5S,不改 FB 本体。

六、结构设计检查闭环

完成上述设计后,用三个问题自检:第一,每个 FB 是否只依赖自己的输入输出,能否直接复制到另一个项目?第二,快任务里是否出现了通信、字符串或大循环?第三,全局变量表是否只保留了真正跨模块的接口?若答案是否定的,先调整结构再写逻辑。结构对了,后续加一个工位只是新增一个 FB 实例和一段调用,而不是重写整条产线。

PLCnext 产线程序结构:任务—POU—变量作用域关系 任务调度(Resource) Task_Fast · 2 ms PRG_Safety 急停 / 光栅 / 安全门 Task_Main · 10 ms PRG_Main 工位逻辑 / 气缸 / 轴控 Task_Slow · 100 ms PRG_HMI HMI 刷新 / 报警汇总 Task_Event · 事件 PRG_Trace 故障录波 / MES 上传 周期越短 → 优先级越高 快任务不放通信/字符串 程序组织单元(POU) PRG_Main 按工位顺序调用 FB_Station 实例 FB_Station 组合气缸/轴 FB,工位级流程 FB_Cylinder 伸出/缩回/到位 FB_Axis 使能/回零/定位 SFC 步序 + ST 转移条件 上料→定位→压装→检测→下料 LD 安全联锁段 急停链 / 光栅 / 门锁 FB 可复用 · 实例显式命名 禁止匿名实例 变量作用域 FB 局部变量 VAR / VAR_INPUT 设备内部状态 GVL_Line 全局 线体状态 / 配方号 报警字 RETAIN / PERSISTENT 计数器 / 配方索引 断电保持 HMI / MES 接口 只读写全局或接口 FB 不访问 FB 内部 局部优先 · 全局只做接口 全局表越短越好

把这张关系图落到工程里,就是:任务决定“什么时候跑”,POU 决定“跑什么”,变量作用域决定“数据给谁看”。三者对齐后,产线程序才具备可复用、可调试、可扩展的结构基础。