4、FB功能块核心概念:实例、输入输出参数、静态变量、内部变量、调用机制与执行逻辑

在PLC结构化编程体系中,功能块(Function Block,FB)是复用逻辑与封装工艺的核心载体。与函数(FC)不同,FB拥有独立的存储区,能够“记住”上一次调用的状态,这一特性使其在电机控制、阀门调节、温度PID等需要保持历史状态的场景中具有不可替代的价值。理解FB的实例化机制、变量分类与调用执行逻辑,是掌握结构化编程从“会写”走向“会设计”的关键分水岭。本章将围绕FB的六大核心概念展开深度拆解,帮助读者建立从声明到调用的完整认知闭环。

FB功能块核心概念关系与调用执行逻辑 FB 定义(模板/类型) 输入参数 (VAR_INPUT) 输出参数 (VAR_OUTPUT) 静态变量 (VAR) 内部变量 (VAR_TEMP) 实例化 FB 实例(数据副本) 实例A (电机1) 实例B (电机2) 实例C (电机3) 实例D (电机4) 背景数据块 (Instance DB) 每个实例独立占用存储区 调用机制与执行逻辑 ① 扫描到FB调用指令 ② 读取输入参数值 ③ 执行FB内部逻辑(使用静态/内部变量) ④ 更新输出参数 ⑤ 将状态写入背景DB ⑥ 返回调用点,继续扫描 * 同一扫描周期内多次调用,状态依次更新 FB 执行逻辑时序(单次扫描周期内) 扫描开始 扫描结束 读取输入 IN1, IN2... 执行FB内部算法 使用静态/内部变量 更新输出 OUT1, OUT2... 写入背景DB 保存静态变量状态 返回 继续扫描 关键点: • 输入参数在调用开始时一次性读取,执行过程中输入值变化不影响本次调用 • 静态变量在两次调用之间保持值不变,内部变量每次调用重新初始化 • 同一FB的多个实例共享代码逻辑,但各自拥有独立的数据存储区

4.1 实例与实例化机制:从模板到数据副本

4.1.1 核心原理:FB定义与实例的本质区别

FB的定义(类型)相当于一份“图纸”或“模板”,它描述了功能块的输入输出接口、算法逻辑和内部数据结构。而实例则是根据这份模板在PLC内存中创建的具体“数据副本”。每个实例都拥有独立的背景数据块(Instance DB),用于存储该实例的静态变量、输入输出参数的当前值。这意味着,同一个FB类型可以被实例化多次,每次实例化都会分配独立的内存区域,互不干扰。

以电机控制为例,若设备上有4台相同型号的电机,只需编写一个“Motor_Control”FB,然后创建4个实例(如Motor1、Motor2、Motor3、Motor4)。每个实例的启动命令、当前转速、故障状态等数据都存储在自己的背景DB中,但执行的控制逻辑代码是共享的。这种“代码共享、数据独立”的机制,是FB实现高效复用的根本原因。

4.1.2 判断方法:如何确定需要多少个实例

在实际工程中,确定实例数量需遵循以下步骤:

  1. 识别被控对象:统计现场具有相同控制逻辑的设备数量,如阀门、泵、变频器等。
  2. 分析差异性:若设备之间存在参数差异(如不同电机的额定电流不同),可通过输入参数传递差异值,无需创建不同FB。
  3. 评估存储资源:每个实例的背景DB会占用PLC的装载存储区和工作存储区。对于中小型PLC(如S7-1200),需注意DB总大小限制。
  4. 考虑扫描周期:实例数量越多,每个扫描周期内FB被调用的次数越多,CPU执行时间相应增加。需评估CPU的扫描周期是否满足工艺要求。

4.1.3 案例拆解:多轴定位系统的实例化设计

某包装机械需要控制6个伺服轴完成同步定位。工程师设计了一个“Axis_Control”FB,包含使能、目标位置、速度、加速度等输入参数,以及当前位置、到位标志、报警代码等输出参数。通过创建6个实例(Axis1至Axis6),每个实例在背景DB中独立存储各自的设定值和实际值。在OB1中按顺序调用6次该FB,每次传入不同的背景DB和轴参数。这种设计使程序代码量减少约70%,且新增轴时只需复制调用代码并分配新DB即可。

经验提醒:实例名称应具有明确物理意义(如“Mixer_Tank1”而非“FB1_Instance3”),便于HMI组态和故障排查。在TIA Portal中,实例名称会直接显示在调用列表中,良好的命名习惯能显著提升程序可读性。

4.1.4 常见误区与总结

  • 误区1:将FB当FC使用——不创建实例直接调用,导致静态变量无法保持,逻辑混乱。
  • 误区2:实例数量过多——超出PLC存储限制,导致编译失败或下载异常。
  • 误区3:忽略背景DB的保持性设置——在断电保持需求下,需在DB属性中勾选“保持”选项,否则PLC重启后实例数据丢失。

总结:实例化是FB复用的基础,合理规划实例数量与命名规则,是结构化编程的第一步。

4.2 输入输出参数:接口设计与数据交互

4.2.1 核心原理:参数的类型与传递方式

FB的输入参数(VAR_INPUT)和输出参数(VAR_OUTPUT)构成了与外部程序交互的接口。输入参数在调用时由调用者提供值,输出参数在FB执行完毕后将结果返回给调用者。此外,还有输入输出参数(VAR_IN_OUT),它允许FB直接读写调用者的变量,适用于需要修改外部数据的场景。

参数传递遵循“值传递”原则:输入参数在调用开始时被复制到FB的局部存储区,FB内部对输入参数的修改不会影响调用者的原始变量。而VAR_IN_OUT参数传递的是变量的地址,FB内部对该参数的修改会直接反映到调用者的变量上。

4.2.2 设计方法:参数接口的规范化设计

参数类别命名建议数据类型选择典型应用
输入参数i_前缀(如 i_StartCmd)Bool、Int、Real、Time启动命令、设定值、使能信号
输出参数o_前缀(如 o_CurrentSpeed)Bool、Int、Real、Word状态反馈、实际值、报警代码
输入输出参数io_前缀(如 io_ErrorCode)任意类型累计值、故障字、模式切换

设计原则:接口应尽量精简,避免过多参数导致调用复杂。对于超过5个输入参数的FB,建议使用UDT(用户自定义类型)将相关参数打包,提高可维护性。

4.2.3 实战场景:PID温控FB的参数封装

设计一个“PID_TempCtrl”FB,输入参数包括:i_Setpoint(设定温度)、i_ActualTemp(实际温度)、i_Kp、i_Ki、i_Kd(PID系数)、i_SampleTime(采样周期);输出参数包括:o_Output(控制输出)、o_Error(偏差)、o_Status(运行状态)。通过VAR_IN_OUT参数io_IntegralAcc传递积分累计值,使FB在多次调用间保持积分状态。这种设计使FB既可用于不同温区,又可通过调整PID参数适应不同热惯性对象。

经验提醒:对于需要掉电保持的参数(如累计运行时间),应使用静态变量而非内部变量,并在背景DB中设置保持属性。

4.2.4 常见误区与总结

  • 误区1:滥用VAR_IN_OUT——频繁使用VAR_IN_OUT会降低程序可读性,且不利于FB的独立测试。
  • 误区2:参数类型不匹配——调用时传入错误数据类型,导致编译错误或运行时数据转换异常。
  • 误区3:忽略参数的初始值——未设置输入参数默认值,在HMI未赋值时可能导致FB误动作。

总结:输入输出参数是FB与外部世界的“桥梁”,规范化的接口设计能大幅提升FB的通用性和可维护性。

4.3 静态变量与内部变量:状态保持与临时存储

4.3.1 核心原理:两类变量的本质区别

静态变量(VAR)存储在背景DB中,在FB多次调用之间保持值不变。它们用于记录FB的“记忆”,如当前状态、累计值、上次输出值等。内部变量(VAR_TEMP)存储在PLC的局部数据堆栈(L堆栈)中,仅在FB本次调用期间有效,调用结束后即被释放。内部变量用于存储临时计算结果,如循环计数器、中间运算值等。

理解这一区别至关重要:若将需要保持的数据错误地声明为VAR_TEMP,则每次调用FB时该变量都会被重新初始化,导致逻辑错误。反之,若将临时变量声明为VAR,则会无谓占用背景DB空间,且可能因上次调用的残留值引发意外行为。

4.3.2 判断方法:如何选择变量类型

判断条件选择变量类型原因
数据需要在两次调用间保持静态变量(VAR)存储在背景DB,断电保持(可选)
数据仅本次调用使用,无需保持内部变量(VAR_TEMP)节省DB空间,提高执行效率
数据需要被多个FB实例共享全局DB变量静态变量仅对单个实例可见
数据需要掉电保持静态变量+DB保持属性确保PLC重启后数据不丢失

4.3.3 案例拆解:电机软启动FB的变量设计

设计“Motor_SoftStart”FB,实现电机斜坡启动功能。需要保持的变量包括:当前输出频率(静态变量)、启动时间累计值(静态变量)、启动完成标志(静态变量)。临时变量包括:频率增量(VAR_TEMP)、循环计数(VAR_TEMP)。若将频率增量误声明为静态变量,则每次调用时增量会累积,导致输出频率异常跳变。正确设计后,FB在每次扫描周期内计算一次增量,并更新静态变量中的当前频率,实现平滑启动。

风险提示:在OB100(启动组织块)中调用FB时,需注意静态变量的初始值设置。若未在FB声明中指定初始值,则背景DB中的初始值默认为0,可能导致启动瞬间输出异常。

4.3.4 常见误区与总结

  • 误区1:所有变量都用静态变量——导致背景DB臃肿,且临时变量残留值可能引发逻辑错误。
  • 误区2:忽视VAR_TEMP的初始化——虽然VAR_TEMP在调用时自动分配,但其初始值不确定,需在FB内部显式赋值。
  • 误区3:静态变量命名与内部变量混淆——建议在命名时添加前缀(如s_表示静态,t_表示临时),提高代码可读性。

总结:正确区分静态变量与内部变量,是FB设计的基本功。合理使用两类变量,既能保证状态保持,又能优化存储资源。

4.4 调用机制与执行逻辑:扫描周期内的行为

4.4.1 核心原理:FB在扫描周期中的执行位置

PLC采用循环扫描的工作方式,每个扫描周期依次执行:读取输入映像区、执行用户程序、写入输出映像区、执行系统自诊断。FB的调用发生在“执行用户程序”阶段。当CPU扫描到FB调用指令时,会执行以下步骤:

  1. 将输入参数的值从调用点复制到FB的输入存储区。
  2. 从背景DB中加载静态变量的当前值。
  3. 执行FB内部的算法逻辑,使用输入参数、静态变量和内部变量进行计算。
  4. 将输出参数的值写入调用点指定的变量。
  5. 将更新后的静态变量值写回背景DB。

这一过程在单个扫描周期内完成,且FB的调用是“顺序执行”的——即在一个扫描周期内,若同一FB被多次调用,则每次调用都会完整执行上述步骤,且后一次调用可以看到前一次调用对静态变量的更新。

4.4.2 判断方法:调用位置与执行顺序的影响

FB的调用位置会影响其执行时机和数据可见性。例如,在OB1中先调用“Motor_Control”FB,再调用“Status_Report”FB,则后者可以看到前者更新后的输出值。若调用顺序相反,则Status_Report看到的是上一次扫描周期的旧值。因此,在设计中需明确FB之间的数据依赖关系,合理安排调用顺序。

此外,FB可以在不同组织块中调用(如OB1主循环、OB35定时中断、OB100启动),不同OB中的调用时机不同,需注意数据一致性问题。例如,在OB35中调用高速计数FB,在OB1中调用显示FB,两者之间可能存在数据不同步。

4.4.3 实战场景:多FB协同工作的调用链设计

某反应釜控制系统包含三个FB:FB_TempCtrl(温度控制)、FB_StirrerCtrl(搅拌控制)、FB_AlarmMgr(报警管理)。在OB1中按以下顺序调用:

// OB1 主程序片段
CALL FB_TempCtrl, "TempCtrl_DB"
    i_Setpoint := 85.0
    i_ActualTemp := "Temp_Sensor_AI"
    o_HeaterOut := "Heater_AO"
    o_Status := "TempCtrl_Status"

CALL FB_StirrerCtrl, "Stirrer_DB"
    i_StartCmd := "Stirrer_Start"
    i_SpeedSet := 1200
    o_SpeedAct := "Stirrer_Speed"
    o_Running := "Stirrer_Run"

CALL FB_AlarmMgr, "Alarm_DB"
    i_TempStatus := "TempCtrl_Status"
    i_StirrerStatus := "Stirrer_Run"
    o_AlarmCode := "Process_Alarm"

该调用链确保温度控制先执行,搅拌控制其次,报警管理最后,使报警逻辑能够基于最新的设备状态进行判断。若将报警管理放在最前,则可能因读取到旧状态而漏报或误报。

经验提醒:在TIA Portal中,可以使用“调用树”视图查看FB的调用层级关系。合理组织调用层级(如OB1→FB_设备控制→FB_子功能),有助于实现模块化设计。

4.4.4 常见误区与总结

  • 误区1:在多个OB中重复调用同一FB实例——可能导致数据竞争,需使用互斥机制或确保调用时机不重叠。
  • 误区2:忽略FB执行时间——复杂FB(如浮点运算、字符串处理)会延长扫描周期,需评估CPU性能。
  • 误区3:在FB内部调用自身(递归)——PLC不支持递归调用,会导致编译错误或运行时故障。

总结:理解FB的调用机制与执行逻辑,是确保程序时序正确、数据一致的基础。合理规划调用顺序和位置,能有效避免隐性逻辑错误。

4.5 综合复盘:FB设计的关键决策点

本章围绕FB的六大核心概念展开,从实例化机制到调用执行逻辑,构建了完整的知识框架。在实际项目中,FB设计的关键决策点可归纳为:

决策点关键问题推荐做法
实例规划需要多少个实例?命名是否清晰?按物理对象命名,评估存储与扫描周期
接口设计参数是否精简?类型是否合理?使用前缀规范,必要时用UDT打包
变量分类哪些数据需要保持?哪些是临时的?静态变量用于状态保持,VAR_TEMP用于临时计算
调用策略调用顺序是否满足数据依赖?按数据流方向排列调用,避免时序冲突

掌握这些核心概念后,读者应能够独立设计出结构清晰、复用性高、易于维护的FB程序。下一阶段的学习将聚焦于FB的封装技巧与跨项目复用方法,进一步释放结构化编程的生产力。