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。
二、模块化编程原则
模块化的目标不是“块越多越好”,而是让每个块只承担一个可命名的职责。判断标准很简单:如果给这个块写一句注释需要用到“并且”,说明它该拆了。例如“电机控制并且报警处理”应拆成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表示静态整数步序。这样在调用时一眼能看出方向与类型,减少接错线。
四、块调用层级设计
调用层级决定程序的“深度”。推荐三层结构:
- 调度层(OB):OB1只调用一个FB_LineCtrl,OB100调用初始化FC。
- 协调层(FB_LineCtrl):管理整线模式、调用各工位FB,处理工位间互锁。
- 设备层(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的内部逻辑。这就是模块化与接口规范带来的直接收益。
最后强调一点:块架构设计不是一次性的,它应随工艺变化而演进。建议在项目初期就确定命名规则、接口模板和层级深度,并在版本管理中记录每次架构调整的原因,这样后续维护者才能理解“为什么这样分块”,而不是只看到一堆背景DB。