3. 结构化编程思想
在西门子PLC项目中,程序规模一旦超过几百行,若仍把所有逻辑堆在OB1里,调试和维护就会变得非常困难。结构化编程的核心,就是把一个复杂的控制任务拆解成若干职责明确、边界清晰的程序单元,再通过标准接口把它们组合起来。它并不是某种具体指令,而是一种组织程序的方法论,最终体现在模块化、分层设计、接口定义以及高内聚低耦合这四个方面。
一、核心原理:四个关键词的工程含义
模块化是指按设备、功能或工艺段把程序切分为独立的FC、FB或OB块。例如一台输送机可以封装成一个FB,内部包含启动、停止、故障、联锁等逻辑,外部只需调用并传入参数。
分层设计是指把程序划分为设备层、单元层、协调层等不同抽象级别。底层负责具体执行器动作,中层负责单台设备或工位控制,上层负责产线节拍与模式调度。上层不直接操作I/O,而是调用下层接口。
接口定义是指每个块对外暴露的输入、输出、输入输出和静态变量。接口一旦确定,调用者只依赖接口,不依赖内部实现。在西门子TIA Portal中,FB的接口区就是这种契约的载体。
高内聚低耦合是衡量拆分质量的标准。高内聚要求一个块内部只做一件事,相关逻辑集中在一起;低耦合要求块与块之间尽量少直接访问对方的内部变量,而是通过参数和返回值交互。
二、方法流程:从工艺到程序结构的落地步骤
- 梳理工艺对象:列出设备、工位、模式、联锁和报警,形成对象清单。
- 划分层级:确定哪些属于设备层FB,哪些属于单元层FC/FB,哪些属于协调层OB。
- 定义接口:为每个FB确定输入参数(如启动命令、故障复位)、输出参数(如运行状态、故障代码)和静态变量(如定时器、状态机步号)。
- 实现内部逻辑:在FB内部完成状态机、联锁和报警处理,避免直接读写全局DB。
- 在OB中调用:按扫描周期和调用条件组织块调用,形成清晰的执行顺序。
- 验证与重构:通过仿真或在线监控验证接口行为,发现耦合过紧时重新拆分。
下面是一个典型的FB接口定义示例,展示了一个电机控制块对外暴露的参数:
FUNCTION_BLOCK "FB_Motor"
VAR_INPUT
StartCmd : Bool; // 启动命令
StopCmd : Bool; // 停止命令
FaultReset : Bool; // 故障复位
Interlock : Bool; // 联锁允许
END_VAR
VAR_OUTPUT
RunState : Bool; // 运行状态
FaultCode : Int; // 故障代码
END_VAR
VAR
Step : Int; // 状态机步号
RunTimer : TON; // 运行延时
END_VAR
BEGIN
// 内部状态机与联锁逻辑
END_FUNCTION_BLOCK
三、结构化思想在PLC程序中的可视化体现
下图展示了分层调用关系与接口边界:协调层OB负责模式调度,单元层FB负责工位逻辑,设备层FB负责执行器动作。每一层只通过接口向下调用,避免跨层直接访问I/O或内部变量。
四、案例场景:一条装配线的结构化改造
假设一条装配线有三个工位,每个工位有电机、气缸和传感器。改造前,所有逻辑写在OB1中,使用大量M点和全局DB,导致修改一个工位会影响其他工位。改造后,按以下结构组织:
| 层级 | 程序块 | 职责 | 接口示例 |
|---|---|---|---|
| 协调层 | OB1 | 模式选择、调用三个工位FB | Mode、StartAll、StopAll |
| 单元层 | FB_Station1/2/3 | 工位节拍、联锁、报警汇总 | Start、Stop、Status、Fault |
| 设备层 | FB_Motor、FB_Valve、FB_Cylinder | 执行器动作与状态反馈 | Cmd、Interlock、Run、Fault |
改造后,新增一个工位只需复制单元层FB并修改接口参数,不需要改动其他工位逻辑。调试时也可以单独调用某个FB进行仿真,显著降低排错难度。
五、常见误区与复盘
误区一:把“分块”等同于“结构化”。如果块之间仍然通过全局DB随意读写,只是把代码搬了家,耦合度并没有降低。
误区二:接口定义过于宽泛。一个FB暴露几十个参数,调用者难以理解,反而增加出错概率。接口应尽量精简,只暴露必要信息。
误区三:分层过多导致调用链过长。三层左右通常足够,过度分层会让程序难以跟踪,增加扫描周期和调试成本。
复盘时可以用三个问题检验结构质量:每个FB是否只做一件事?调用者是否只依赖接口而不关心内部实现?修改一个FB是否会影响其他FB?如果答案都是肯定的,说明结构化编程思想已经真正落地。