3. 功能块(FB)基础
在PLC结构化编程体系中,功能块(Function Block,FB)是复用逻辑的核心载体。如果说PLC程序是一座建筑,那么FB就是预制好的“结构件”——它自带数据存储能力、拥有明确的输入输出边界、可以被反复实例化调用。理解FB的本质、它与函数(FC)的差异以及接口设计规则,是掌握结构化编程的基石。本章将从定义出发,深入剖析FB与FC的底层区别,并详细拆解FB的接口构成,帮助你在实际项目中做出正确的选择与设计。
3.1 FB的定义与本质特征
功能块(FB)是IEC 61131-3标准中定义的一种程序组织单元(POU),它由两个核心部分组成:算法逻辑和数据存储。算法逻辑描述了输入到输出的映射关系,而数据存储则使得FB能够“记住”历史状态。这种“算法+状态”的组合,让FB成为实现PID控制、电机启停、顺序控制等需要记忆功能的理想载体。
FB的本质特征可以归纳为以下三点:
- 实例化特性:FB是“模板”,必须通过实例化(即分配背景数据块)才能被调用。同一个FB可以创建多个实例,每个实例拥有独立的数据存储空间,互不干扰。
- 状态保持能力:FB内部的静态变量(STAT)在两次调用之间保持值不变。例如,一个计数器FB的当前计数值,在PLC扫描周期结束后不会被清零,而是保留到下一次调用。
- 封装性:FB将算法和数据封装在一起,外部只能通过接口(输入/输出参数)访问,内部实现细节被隐藏。这大大提高了代码的可维护性和安全性。
核心原理:FB的“记忆”能力来源于其关联的背景数据块(Instance DB)。每次调用FB时,PLC会将该FB的静态变量映射到对应的背景DB地址中。因此,即使FB被多次调用,只要使用不同的背景DB,就能实现完全独立的状态跟踪。
3.2 FB与FC(函数)的核心区别
函数(FC)是另一种程序组织单元,它与FB最大的区别在于是否拥有静态数据存储。FC只有输入、输出和临时变量(TEMP),没有静态变量,因此FC是“无状态”的——每次调用都从零开始,不保留任何历史信息。
| 对比维度 | FB(功能块) | FC(函数) |
|---|---|---|
| 数据存储 | 有静态变量(STAT),需背景DB | 无静态变量,仅临时变量(TEMP) |
| 状态保持 | 支持,跨扫描周期保持 | 不支持,调用结束即释放 |
| 实例化 | 需要创建实例(分配背景DB) | 无需实例化,直接调用 |
| 内存占用 | 每个实例占用独立DB空间 | 仅占用临时堆栈空间 |
| 典型应用 | 电机控制、PID、计数器、定时器 | 数学运算、数据转换、逻辑判断 |
| 多实例支持 | 支持,同一FB可创建多个实例 | 不支持,无实例概念 |
判断方法:在项目设计时,可以通过以下问题快速决定使用FB还是FC:
- 该功能是否需要“记住”上一次调用的状态?如果需要,选FB;如果不需要,选FC。
- 该功能是否会被多个设备/工位独立使用,且各自状态不同?如果是,选FB(多实例);如果只是通用计算,选FC。
- 该功能是否包含定时器、计数器等需要保持的元件?如果是,必须选FB。
常见误区:有些工程师习惯将所有逻辑都写成FC,认为FB“太复杂”。但在实际项目中,如果使用FC实现电机控制,每次调用都需要额外定义全局变量来保存状态,不仅代码冗余,而且容易造成变量冲突。正确做法是:有状态需求用FB,无状态需求用FC。
3.3 FB的接口构成:输入、输出与静态变量
FB的接口是它与外部程序交互的唯一通道,设计良好的接口能显著提升FB的通用性和易用性。FB接口主要分为三类:输入参数(IN)、输出参数(OUT)和静态变量(STAT)。此外,还有输入输出参数(IN_OUT)和临时变量(TEMP),但前三种是FB的核心。
3.3.1 输入参数(IN)
输入参数是调用FB时必须提供的数据,它们定义了FB运行的条件。输入参数可以是BOOL、INT、REAL、TIME等任何数据类型。设计输入参数时,应遵循“最小化原则”——只暴露必要的控制信号,避免将内部计算所需的中间量作为输入。
3.3.2 输出参数(OUT)
输出参数是FB运行后返回给调用者的结果。输出参数同样支持所有数据类型。需要注意的是,输出参数在FB内部被赋值后,会立即反映到调用方的变量中。对于需要同时返回多个结果的场景,FB比FC更具优势,因为FC只能通过RET_VAL返回一个值。
3.3.3 静态变量(STAT)
静态变量是FB的“私有记忆”,它们存储在背景DB中,在两次调用之间保持值不变。静态变量不能从外部直接访问,只能通过FB内部的逻辑进行读写。常见的静态变量包括:当前状态值、累计计数、上次运行时间、内部标志位等。
经验提醒:在设计FB接口时,建议将静态变量分为两类:可调参数(如PID的Kp、Ti)和内部状态(如当前运行模式、故障标志)。可调参数应通过输入参数暴露给外部,以便在线修改;内部状态则保留在STAT中,避免外部误操作。
3.4 实战场景:电机控制FB的设计与调用
下面通过一个电机控制FB的设计案例,完整展示FB接口的定义、实现和调用过程。假设我们需要控制一台三相异步电机的启动、停止和故障复位,并需要监控电机的运行时间。
场景约束:现场有3台电机,每台电机独立运行,需要分别记录运行时间。控制柜采用西门子S7-1200 PLC,编程环境为TIA Portal V17。
FB接口设计:
FUNCTION_BLOCK FB_MotorControl
VAR_INPUT
StartCmd : BOOL; // 启动命令
StopCmd : BOOL; // 停止命令
ResetCmd : BOOL; // 故障复位命令
MotorFault : BOOL; // 电机故障反馈(热继电器)
END_VAR
VAR_OUTPUT
MotorRun : BOOL; // 电机运行状态
FaultActive : BOOL; // 故障指示
RunHours : REAL; // 累计运行时间(小时)
END_VAR
VAR
RunTimer : TON; // 运行计时器
TotalTime : REAL; // 累计时间存储
State : INT; // 内部状态:0=停止,1=运行,2=故障
END_VAR
实现逻辑:
// 状态机控制
CASE State OF
0: // 停止状态
MotorRun := FALSE;
IF StartCmd AND NOT MotorFault THEN
State := 1;
END_IF;
1: // 运行状态
MotorRun := TRUE;
RunTimer(IN := TRUE, PT := T#1H);
IF RunTimer.Q THEN
TotalTime := TotalTime + 1.0;
RunTimer(IN := FALSE);
END_IF;
IF StopCmd OR MotorFault THEN
State := 2;
END_IF;
2: // 故障/停止处理
MotorRun := FALSE;
IF MotorFault THEN
FaultActive := TRUE;
END_IF;
IF ResetCmd AND NOT MotorFault THEN
FaultActive := FALSE;
State := 0;
END_IF;
END_CASE;
RunHours := TotalTime;
调用与实例化:在OB1中,为3台电机分别创建实例:
// 实例化三个电机控制FB
FB_MotorControl_Instance_1 : FB_MotorControl;
FB_MotorControl_Instance_2 : FB_MotorControl;
FB_MotorControl_Instance_3 : FB_MotorControl;
// 调用示例(电机1)
FB_MotorControl_Instance_1(
StartCmd := "HMI_Start_1",
StopCmd := "HMI_Stop_1",
ResetCmd := "HMI_Reset_1",
MotorFault := "Motor1_Fault",
MotorRun => "Motor1_Run",
FaultActive => "Motor1_Fault_Lamp",
RunHours => "Motor1_Hours"
);
结果对比:使用FB后,3台电机的控制逻辑完全复用,仅需3个实例DB。相比使用FC,代码量减少约60%,且每台电机的运行时间独立记录,互不干扰。后续若需增加电机数量,只需新增实例并修改调用参数即可。
风险与代价:FB的代价是占用更多的PLC内存(每个实例需要独立的背景DB)。在本例中,3个实例DB约占用120字节,对于S7-1200的容量而言微不足道。但如果实例数量过多(如超过100个),需评估内存占用。
复盘经验:设计FB时,应预留扩展接口。例如,本案例中未考虑电机的电流监控,后续若需增加,只需在FB内部添加输入参数MotorCurrent和输出参数OverCurrent,不影响已有调用代码。这种“开闭原则”是FB设计的核心思想。
3.5 常见误区与总结
在实际项目中,工程师使用FB时常犯以下错误:
- 误区一:FB内使用全局变量。FB的优势在于封装性,如果在FB内部直接读写全局变量(如M区),会破坏封装性,导致调试困难。正确做法是所有数据通过接口传递。
- 误区二:静态变量过多。静态变量越多,背景DB越大,且FB的通用性越差。应尽量将可调参数放在输入接口,静态变量仅保留必要的内部状态。
- 误区三:忽略IN_OUT参数。IN_OUT参数既可作为输入也可作为输出,适合需要“读-改-写”的场景(如累加器)。但IN_OUT参数不能用于常量,调用时必须传入变量。
- 误区四:FB嵌套过深。FB可以调用其他FB,但嵌套层级过多会降低程序可读性,且增加扫描时间。建议嵌套不超过3层。
总结:FB是PLC结构化编程中最强大的复用工具,它通过“算法+数据存储”的组合,实现了有状态逻辑的模块化封装。与FC相比,FB牺牲了少量内存,换来了状态保持和多实例支持。在设计FB时,接口的合理性直接决定了FB的生命周期——好的接口设计能让FB在多个项目中复用,而糟糕的接口设计则会让FB沦为一次性代码。掌握FB的定义、区别和接口设计,是迈向高级PLC工程师的关键一步。