程序结构基础:主程序(OB1)、子程序(FC/FB)与组织块(OB)的概念与分工
各位同学,今天我们来聊聊PLC程序的结构基础。说实话,很多新手工程师写程序,上来就是一把梭——所有逻辑全塞在一个块里。结果呢?调试的时候想死,维护的时候更想死。我早期也干过这种事,后来被一个德国老工程师狠狠教育了一顿,才明白程序结构的重要性。
PLC的程序结构,说白了就是怎么把一堆逻辑代码,有组织、有纪律地放好。就像你收拾工具箱,螺丝刀放一起,扳手放一起,用的时候随手就能拿到。程序也是一样,结构清晰了,后面改起来才不头疼。
一、主程序OB1——程序的“心脏”
OB1是什么?它是PLC的“主循环”。PLC上电后,CPU会一遍又一遍地执行OB1里的代码。你想想看,就像你的心跳一样,不停地在跳。OB1就是程序的心跳。
OB1里放什么?我个人习惯,只放“调用指令”。什么意思?就是OB1本身不写具体的控制逻辑,它只负责叫别人干活。比如:
// OB1 主程序
CALL "电机控制" // 调用电机控制子程序
CALL "报警处理" // 调用报警处理子程序
CALL "数据记录" // 调用数据记录子程序
嗯,这里要注意:OB1的执行顺序是从上到下,一行一行跑。所以如果你有优先级要求,把重要的调用放在前面。我在项目中遇到过,有人把急停逻辑放在子程序里,结果OB1里调用顺序靠后,急停响应慢了半拍。后来改到OB1最前面直接写,问题就解决了。
二、子程序FC与FB——程序的“手脚”
FC和FB,都是子程序。但它们的区别,很多人搞不清楚。我简单说一下:
| 特性 | FC(函数) | FB(功能块) |
|---|---|---|
| 有没有“记忆” | 没有,每次调用都是全新的 | 有,内部数据会保持 |
| 典型用途 | 数学计算、逻辑判断 | 电机控制、阀门控制、PID调节 |
| 背景数据块 | 不需要 | 需要(DB块) |
| 多次调用 | 可以,但数据不共享 | 可以,每个实例独立 |
为什么会这样?因为FB自带一个“背景数据块”,相当于给它配了一个小本本,每次运行完,数据都记在本子上。下次再调用,还能翻到上次的记录。FC就不行,它是个“健忘症”,每次调用都是白纸一张。
举个例子。你写一个电机启动程序,用FB来做:
// FB1 "电机控制"
// 输入:启动按钮、停止按钮
// 输出:接触器
// 内部变量:运行状态(保持)
NETWORK 1
A "启动按钮" // 检测启动
S "运行状态" // 置位运行标志
NETWORK 2
A "停止按钮" // 检测停止
R "运行状态" // 复位运行标志
NETWORK 3
A "运行状态" // 根据状态输出
= "接触器"
你看,这个FB里有个“运行状态”,它不会因为程序跑完一圈就消失。下次再来,它还记得电机是开着还是关着。这就是FB的“记忆”能力。
三、组织块OB——程序的“闹钟”和“保安”
OB除了OB1,还有很多种。它们就像你手机里的闹钟,到了时间就响,或者出了紧急情况就报警。常见的OB有:
- OB1:主循环,前面说过了
- OB35:循环中断,比如每100ms执行一次,适合做PID调节
- OB40~OB47:硬件中断,比如某个输入信号跳变时触发
- OB82:诊断中断,硬件出故障时自动调用
- OB100:启动组织块,PLC上电时只执行一次
我曾经在一个项目中,客户要求设备断电重启后,所有电机必须处于停止状态。我就在OB100里写了一段初始化代码,把所有输出复位。这样不管断电前是什么状态,重启后都是安全的。
四、它们怎么配合?——一个完整的例子
说了这么多,我们来看一个完整的程序结构。假设你要控制一个传送带系统:
// OB1 主循环
CALL "传送带控制" // FB,控制传送带启停
CALL "速度计算" // FC,计算当前速度
CALL "报警管理" // FB,管理报警状态
// OB35 每100ms执行一次
CALL "PID_速度调节" // FB,调节电机速度
// OB100 启动时执行一次
CALL "系统初始化" // FC,复位所有输出
你看,OB1负责日常调度,OB35负责定时任务,OB100负责初始化。每个子程序各司其职,互不干扰。这就是模块化编程的思维。
最后说一句,程序结构这东西,刚开始可能觉得麻烦。但等你真正遇到一个几千行的项目,你就知道结构清晰有多重要了。嗯,今天就到这里,下节课我们讲变量声明和数据类型,到时候见。