ST函数与功能块:FB与FC的区别及实例化调用方法

发布于 2026-03-14 23:31:55 · 浏览 7 次 · 评论 0 条

ST函数与功能块是PLC编程中实现模块化、可复用逻辑的核心构件。它们都使用结构化文本(Structured Text,ST)语言编写,但设计理念、数据管理方式和调用机制存在本质差异。掌握二者区别及正确实例化方法,是避免逻辑错误、提升程序可维护性的关键。


一、核心概念辨析:FC与FB的本质差异

特性 FC(Function Call,函数) FB(Function Block,功能块)
数据存储能力 无内部存储区;每次调用均从输入参数读取,不保留上次状态 自带背景数据块(DB);自动保存静态变量(STATIC)、输出参数(OUTPUT)及内部变量状态
调用前提 可直接调用,无需额外配置 必须先关联一个背景数据块(DB),否则编译报错
变量声明域 仅支持 VAR_INPUT, VAR_OUTPUT, VAR_IN_OUT, VAR(临时变量) 支持 VAR_INPUT, VAR_OUTPUT, VAR_IN_OUT, VAR, VAR_STATIC, VAR_TEMP
执行结果依赖性 纯函数式:相同输入 → 相同输出,无历史依赖 状态相关:输出不仅取决于当前输入,还取决于上一次执行后的 STATIC 变量值(如计数器、延时标志)
典型应用场景 数学计算(如 $sqrt(x^2 + y^2)$)、逻辑判断、信号转换 带记忆的控制单元(如 TON 定时器、CTU 计数器、电机启停控制单元)

⚠️ 关键结论:FB = 可实例化的“有状态对象”;FC = 无状态的“纯计算工具”
这一区别直接决定了:能否用同一个FB实现多个独立设备的并行控制(如3台电机各用1个FB实例),而FC无法做到。


二、ST语言中FC的定义与调用(无状态计算)

1. 定义一个FC:计算两点间欧氏距离

FUNCTION FC10 : REAL
// 输入坐标
VAR_INPUT
  x1 : REAL;
  y1 : REAL;
  x2 : REAL;
  y2 : REAL;
END_VAR
// 内部临时变量(每次调用新建,调用结束即销毁)
VAR
  dx : REAL;
  dy : REAL;
END_VAR

dx := x2 - x1;
dy := y2 - y1;
FC10 := SQRT(dx * dx + dy * dy); // ST标准库函数
  • 函数名 FC10 是标识符,返回值类型为 REAL
  • 所有 VAR 声明的变量均为临时变量(TEMP),生命周期仅限本次执行。
  • VAR_STATIC,无背景数据块依赖

2. 在主程序(如 OB1)中调用FC

PROGRAM OB1
VAR
  dist_A : REAL;
  dist_B : REAL;
END_VAR

// 调用FC10计算两组点的距离(完全独立,互不影响)
dist_A := FC10(0.0, 0.0, 3.0, 4.0);   // 返回5.0
dist_B := FC10(-1.0, 2.0, 1.0, 5.0); // 返回√13 ≈ 3.606
  • 调用语法:变量 := FC编号(实参1, 实参2, ...)
  • 每次调用都是全新计算,不占用DB资源,适合高频、轻量运算。

三、ST语言中FB的定义与实例化(有状态控制)

1. 定义一个FB:带使能控制的脉冲发生器(类似TP定时器简化版)

FUNCTION_BLOCK FB20
// 输入
VAR_INPUT
  IN : BOOL;      // 启动脉冲输入(上升沿触发)
  TON_TIME : TIME; // 脉冲持续时间
END_VAR
// 输出
VAR_OUTPUT
  Q : BOOL;       // 脉冲输出
  ET : TIME;      // 已计时长(运行中更新)
END_VAR
// 静态变量(保留在背景DB中,跨周期保持)
VAR_STATIC
  timer_state : BOOL := FALSE; // 当前是否在计时
  elapsed : TIME := T#0s;      // 已累计时间
  start_time : DATE_AND_TIME;  // 上次触发时刻
END_VAR
// 临时变量(本周期内使用,不保存)
VAR_TEMP
  now : DATE_AND_TIME;
  diff : TIME;
END_VAR

// 主逻辑
now := GET_SYSTEM_TIME(); // 获取当前系统时间

IF IN AND NOT timer_state THEN
  // 检测上升沿:IN由FALSE→TRUE
  timer_state := TRUE;
  start_time := now;
  elapsed := T#0s;
ELSIF timer_state THEN
  // 计算已过时间
  diff := DIFF_TIME(start_time, now);
  elapsed := diff;
  IF elapsed >= TON_TIME THEN
    timer_state := FALSE;
    Q := FALSE;
  ELSE
    Q := TRUE;
  END_IF;
ELSE
  Q := FALSE;
END_IF;

ET := elapsed;
  • VAR_STATIC 区域声明的变量(timer_state, elapsed, start_time不会随每次调用重置,而是持久保存在背景数据块中。
  • QETVAR_OUTPUT,既可被外部读取,其值也参与内部逻辑(但通常不建议在FB内部写入OUTPUT变量)。

2. FB的实例化:必须绑定背景数据块(DB)

在TIA Portal等工程软件中,实例化FB需两步:

  1. 创建背景数据块(DB)

    • 右键项目树中的 FB20 → “创建背景数据块”。
    • 系统自动生成 DB1(或指定名称如 DB_MOTOR1_PULSE),其结构严格匹配 FB20 的接口(含 STATIC 变量)。
  2. 在调用处声明FB实例变量

    PROGRAM OB1
    VAR
      pulse_inst_1 : FB20; // 声明一个FB20类型的变量(即实例)
      pulse_inst_2 : FB20;
      // 注意:此处未指定DB!实际编译时会自动关联默认DB(如DB1、DB2)
      // 更规范做法:显式指定DB(见下文)
    END_VAR

3. 显式绑定DB的调用方式(推荐,清晰可控)

PROGRAM OB1
VAR
  // 方式1:声明时直接指定DB(TIA Portal语法)
  pulse_a : FB20 WITH DB_MOTOR_A; // DB_MOTOR_A 必须已存在且类型匹配FB20
  pulse_b : FB20 WITH DB_MOTOR_B;

  // 方式2:在调用语句中传入DB(兼容老版本/部分平台)
  // (注:此语法因平台而异,主流S7-1500/TIA Portal以方式1为准)
END_VAR

// 执行调用(必须提供所有INPUT参数)
pulse_a(IN := "Start_Button", TON_TIME := T#2s);
pulse_b(IN := "Remote_Start", TON_TIME := T#500ms);

// 读取输出
"Motor_A_Run" := pulse_a.Q;
"Motor_B_Run" := pulse_b.Q;
  • pulse_apulse_b 是两个完全独立的实例,各自拥有专属的 DB_MOTOR_ADB_MOTOR_B,其中的 timer_stateelapsedSTATIC 变量互不干扰。
  • 若错误地让两个实例共用同一个DB(如都绑定 DB1),则它们将共享全部状态——导致逻辑混乱(例如启动 pulse_a 会意外影响 pulse_b 的计时)。

四、FB与FC混用实战:电机启停控制单元

构建一个完整控制单元,包含:启动条件判断(FC)、启停逻辑(FB)、故障处理(FC)。

1. FC:安全条件校验(无状态)

FUNCTION FC30 : BOOL
VAR_INPUT
  e_stop : BOOL;      // 急停信号(TRUE=有效)
  door_open : BOOL;   // 防护门(TRUE=开启)
  temp_high : BOOL;   // 温度超限
END_VAR
FC30 := NOT (e_stop OR door_open OR temp_high); // 全为FALSE才允许运行

2. FB:电机控制器(有状态)

FUNCTION_BLOCK FB40
VAR_INPUT
  START : BOOL;
  STOP : BOOL;
  SAFE_OK : BOOL; // 由FC30提供
END_VAR
VAR_OUTPUT
  RUNNING : BOOL;
  FAULT : BOOL;
END_VAR
VAR_STATIC
  motor_state : BOOL := FALSE;
  fault_latch : BOOL := FALSE;
END_VAR

// 故障清除:STOP按下且SAFE_OK恢复时复位故障
IF STOP AND SAFE_OK THEN
  fault_latch := FALSE;
END_IF;

// 启停逻辑(带互锁)
IF START AND SAFE_OK AND NOT fault_latch THEN
  motor_state := TRUE;
ELSIF STOP OR NOT SAFE_OK THEN
  motor_state := FALSE;
  IF NOT SAFE_OK THEN
    fault_latch := TRUE;
  END_IF;
END_IF;

RUNNING := motor_state;
FAULT := fault_latch;

3. 主程序整合调用

PROGRAM OB1
VAR
  // 实例化两个电机控制器(完全独立)
  motor1_ctrl : FB40 WITH DB_MOTOR1;
  motor2_ctrl : FB40 WITH DB_MOTOR2;

  // 中间变量
  safe1 : BOOL;
  safe2 : BOOL;
END_VAR

// 步骤1:分别校验每台电机的安全条件(调用FC)
safe1 := FC30("E_Stop_1", "Door_1", "Temp_1");
safe2 := FC30("E_Stop_2", "Door_2", "Temp_2");

// 步骤2:将安全结果传入各自FB实例(驱动状态机)
motor1_ctrl(START := "Start_1", STOP := "Stop_1", SAFE_OK := safe1);
motor2_ctrl(START := "Start_2", STOP := "Stop_2", SAFE_OK := safe2);

// 步骤3:输出结果
"Motor1_Running" := motor1_ctrl.RUNNING;
"Motor1_Fault" := motor1_ctrl.FAULT;
"Motor2_Running" := motor2_ctrl.RUNNING;
"Motor2_Fault" := motor2_ctrl.FAULT;
  • FC30 被复用两次,节省代码空间,且无状态冲突风险。
  • FB40 两个实例通过不同DB隔离,一台电机故障(fault_latch = TRUE)绝不影响另一台。
  • ✅ 所有逻辑清晰分层:FC做“瞬时判决”,FB做“状态演进”。

五、常见错误与避坑指南

  1. 误将FB当FC调用
    ❌ 错误写法:result := FB20(IN := TRUE, TON_TIME := T#1s);
    → 编译失败:FB不能作为表达式返回值调用,必须通过实例变量调用。

  2. 忘记为FB分配背景DB
    ❌ 在变量声明 pulse : FB20; 后未创建DB → 下载时PLC报错 Invalid instance DB
    ✅ 解决:右键该变量 → “创建背景数据块”。

  3. 多个FB实例共用同一DB
    inst1 : FB20 WITH DB_COMMON; inst2 : FB20 WITH DB_COMMON;
    inst1 修改 timer_state 会立即覆盖 inst2 的同名变量,造成不可预测行为。

  4. 在FB内部修改OUTPUT变量后再读取
    Q := TRUE; IF Q THEN ... END_IF;
    → ST中OUTPUT变量在调用结束前不保证可读,应改用中间 VARVAR_STATIC 变量。

  5. 混淆VAR_TEMP与VAR_STATIC
    ❌ 将计数器值声明为 VAR_TEMP count : INT; → 每次调用归零,无法计数。
    ✅ 必须用 VAR_STATIC count : INT := 0;


六、性能与资源权衡建议

  • 优先用FC:当逻辑满足以下任一条件:

    • 纯数学/布尔运算;
    • 不需要记忆上一周期值;
    • 被高频调用(如每10ms执行一次的滤波算法);
    • 希望最小化DB数量(节省PLC内存)。
  • 必须用FB:当逻辑涉及以下任一需求:

    • 时间累积(定时器、积分器);
    • 事件计数(启动次数、故障次数);
    • 多状态机(手动/自动/急停模式切换);
    • 需要为同类设备创建多个独立副本(如N台泵、M个阀门)。
  • 资源开销对比(以S7-1500为例)

    • 一个FC调用:约消耗 < 100 字节代码+栈空间;
    • 一个FB实例:除代码外,额外占用DB空间(按 VAR_STATIC 成员总字节数计算)。例如 FB40 约占20字节DB,100个实例即2KB DB内存。

最终选择依据不是“哪个更高级”,而是“哪个最贴合控制对象的本质属性”:无记忆的计算选FC,有记忆的状态机选FB。

评论 (0)

暂无评论,快来抢沙发吧!

扫一扫,手机查看

扫描上方二维码,在手机上查看本文