4. 程序块架构设计规范

在TIA Portal中,程序块不是“能跑就行”的代码容器,而是产线程序可维护性的骨架。OB、FB、FC、DB四类块各有明确的职责边界,一旦混用,后期改一条工艺参数就可能牵动十几个块。本节从职责划分入手,逐步落到模块化原则、接口定义和调用层级设计,并给出可直接参照的示例。

一、四类块的职责边界

OB(组织块)是CPU与程序的接口,负责“什么时候调用谁”。它不写工艺逻辑,只做三件事:调用功能块、处理启动/中断/错误响应、做必要的模式分发。例如OB1循环调用主控FB,OB100负责上电初始化,OB82/OB86处理诊断中断。把工艺计算写进OB,会导致扫描周期不可控,且无法被多次复用。

FB(功能块)是带“记忆”的逻辑单元,必须配合背景DB使用。它适合描述有状态的对象:一台电机、一个PID回路、一个工位流程。FB的静态变量保存在背景DB中,调用多少次就有多少份独立状态,这是它区别于FC的核心价值。

FC(功能块)是无记忆的逻辑单元,没有背景DB,输出只由当前输入决定。它适合做纯计算、数据转换、条件判断、字符串处理等。若在FC里使用临时变量保存“上一次的值”,下次调用就会丢失,这是常见错误。

DB(数据块)分全局DB和背景DB。全局DB存放跨块共享的配方、参数、HMI交互数据;背景DB由FB调用时自动生成,存放该实例的私有状态。原则是:能被多个块读写的共享数据放全局DB,只属于某个实例的状态放背景DB。

OB / FB / FC / DB 职责与调用层级示意 OB 层:调度与响应(不写工艺逻辑) OB100 启动初始化 OB1 主循环 OB82/86 诊断 OB35 周期中断 FB 层:有状态对象(配背景DB,可多实例) FB_Motor 启停/故障/运行计时 FB_Station 工位步序/互锁 FB_PID 闭环调节 FB_LineCtrl 整线模式管理 FC 层:无状态计算(无背景DB,输出仅由输入决定) FC_Scale 量程换算 FC_Alarm 报警判断 FC_Convert 数据转换 FC_CRC 校验 DB 层:数据存储 全局DB:配方/参数/HMI交互 背景DB:FB实例私有状态 背景DB随FB调用自动生成 调用方向:OB → FB → FC;DB 被 FB/FC 读写,不主动调用

二、模块化编程原则

模块化的目标不是“块越多越好”,而是让每个块只承担一个可命名的职责。判断标准很简单:如果给这个块写一句注释需要用到“并且”,说明它该拆了。例如“电机控制并且报警处理”应拆成FB_Motor和FC_Alarm。

具体落地时遵循四条原则:

  • 单一职责:一个FB只描述一类设备或一个工位,不跨工艺段。
  • 高内聚低耦合:块内部逻辑自洽,块之间只通过接口传递数据,不直接访问对方的背景DB。
  • 可复用:同一型号电机调用同一个FB,通过不同背景DB区分实例,而不是复制粘贴十份代码。
  • 可测试:每个FB能单独在OB1中调用并观察输入输出,不依赖其他块的隐式状态。

三、接口定义规范

接口是块与外界唯一的契约。TIA Portal中FB/FC的接口区分为Input、Output、InOut、Static、Temp、Constant。规范做法是:

  • Input:只读的配置与命令,如启动按钮、设定值、使能。
  • Output:只写的状态与结果,如运行中、故障、实际值。
  • InOut:需要读写的共享数据,如HMI可改的配方参数。慎用,因为它会破坏封装。
  • Static:仅FB可用,保存实例状态,如步序号、计时器、边沿标志。
  • Temp:本次调用内的临时变量,每次调用前必须赋值,不能依赖上次的值。

命名上建议采用“前缀_含义”的方式,例如i_xStart表示输入布尔启动,q_rSpeed表示输出实数速度,s_iStep表示静态整数步序。这样在调用时一眼能看出方向与类型,减少接错线。

接口一旦发布,修改要谨慎。增删接口会导致所有调用点报错,建议在版本管理中记录接口变更,并在FB注释中写明“接口版本V1.2”。

四、块调用层级设计

调用层级决定程序的“深度”。推荐三层结构:

  1. 调度层(OB):OB1只调用一个FB_LineCtrl,OB100调用初始化FC。
  2. 协调层(FB_LineCtrl):管理整线模式、调用各工位FB,处理工位间互锁。
  3. 设备层(FB_Station / FB_Motor):描述具体工位步序和单机设备逻辑,内部可调用FC做计算。

层级不宜超过四层。过深会导致在线监控时难以追踪,且背景DB嵌套过深会增加内存占用。每层之间的数据传递应通过接口,而不是跨层直接读写全局DB。

五、示例:一个工位的块结构

假设某产线有一个“压装工位”,包含压装气缸、位移传感器和压力传感器。合理的块划分如下:

OB1
 └─ FB_LineCtrl (背景DB: DB_LineCtrl)
     ├─ FB_Station_Press (背景DB: DB_Press)
     │   ├─ FB_Motor (背景DB: DB_PressMotor)   // 压装电机
     │   ├─ FC_Scale (无背景DB)                 // 位移/压力量程换算
     │   └─ FC_Alarm (无背景DB)                 // 超压/超位移判断
     └─ FB_Station_Conveyor (背景DB: DB_Conveyor)
         └─ FB_Motor (背景DB: DB_ConvMotor)

全局DB: DB_Recipe (配方), DB_HMI (HMI交互)

其中FB_Station_Press的接口可定义为:Input接收i_xStart、i_rTargetPos、i_rMaxForce;Output输出q_xDone、q_xFault、q_rActForce;Static保存s_iStep、s_tTimeout。FC_Scale接收原始模拟量i_iRaw和量程上下限,返回工程值q_rEng,内部只做线性换算,不保存任何状态。

这样划分后,若要增加第二个压装工位,只需再调用一次FB_Station_Press并分配新的背景DB,无需改动OB1和FB_LineCtrl的内部逻辑。这就是模块化与接口规范带来的直接收益。

常见错误:在FC中使用临时变量保存“上次扫描值”做边沿检测。临时变量在每次调用时可能被覆盖,边沿检测必须放在FB的Static变量中,或使用TIA Portal提供的R_TRIG/F_TRIG指令并分配背景DB。

最后强调一点:块架构设计不是一次性的,它应随工艺变化而演进。建议在项目初期就确定命名规则、接口模板和层级深度,并在版本管理中记录每次架构调整的原因,这样后续维护者才能理解“为什么这样分块”,而不是只看到一堆背景DB。