ST怎么写功能块调用:MyFB(IN := Signal, Q => Output);

发布于 2026-03-15 07:29:28 · 浏览 1 次 · 评论 0 条

在结构化文本(ST)编程中,功能块调用是电气自动化项目最基础、最频繁的操作之一。它直接决定逻辑可读性、调试效率与后期维护成本。下面以 MyFB(IN := Signal, Q => Output); 这一典型语句为线索,逐层拆解其语法结构、执行机制、常见错误及工程实践要点。全文不依赖图形,所有概念均通过文字精准定义和实例说明。


一、先明确:什么是功能块(Function Block)?

功能块不是函数,也不是普通变量。它是带记忆的可重用逻辑封装单元,内部拥有自己的输入(IN)、输出(OUT)和静态变量(如内部计时器值、状态标志)。每次调用都独立保存上次执行后的内部状态——这是它与无状态函数(FUNCTION)的本质区别。

例如,一个自保持启停功能块 TON(延时接通定时器),调用两次 TON1TON2,它们各自的 ET(已耗时间)和 Q(输出状态)互不影响。

功能块必须先声明实例名,再调用。不能像函数那样直接写 MyFB(...);必须有 MyFB : MyFBType; 这样的变量声明前置。


二、语句分解:MyFB(IN := Signal, Q => Output);

这条语句共含四个关键成分,按执行顺序和语义层级排列如下:

  1. MyFB
    → 这是已声明的功能块实例名,类型为 MyFBType(由用户自定义或系统库提供)。它不是类型名,而是内存中一个具体对象的“代号”。
    ✅ 正确声明示例(在 VAR 块中):

    MyFB : MyFBType;

    ❌ 错误写法:MyFBType(IN := Signal, Q => Output); —— 类型名不能直接调用。

  2. IN := Signal
    输入参数赋值,使用 :=(赋值运算符)。IN 是功能块 MyFBType 内部定义的输入变量名;Signal 是当前程序上下文中存在的布尔型(BOOL)、整型(INT)或结构体变量。

    • := 表示“把 Signal 的当前值复制给 MyFB.IN”,发生在功能块执行前。
    • 支持任意兼容类型:若 INREAL,则 Signal 可为 REALINT(自动转换),但不可为 STRING(类型不匹配报错)。
  3. Q => Output
    输出参数映射,使用 =>(输出关联运算符)。Q 是功能块内部的输出变量名;Output 是调用者侧的变量名(必须已声明)。

    • => 不是赋值,而是建立“地址绑定”:MyFB.Q 的值在功能块执行完毕后,自动写入 Output 所指向的内存地址
    • Output 必须是可写变量(VAR、VAR_IN_OUT),不能是常量(如 TRUE)或表达式(如 A + B)。
    • Output 是数组元素(如 Flags[3])或结构体成员(如 Motor.Status.Running),只要地址有效,完全合法。
  4. 分号 ;
    → ST 语句结束符,不可省略。缺位将导致编译器报“syntax error near ‘Q’”。


三、完整可运行示例(含声明+调用)

以下是一个最小但真实的 PLC 程序片段(符合 IEC 61131-3 标准),可在 Codesys、TIA Portal、Unity Pro 等主流平台直接验证:

// 在全局或组织块(OB)的 VAR 块中声明
VAR
    StartButton : BOOL := FALSE;
    MotorOn     : BOOL := FALSE;
    MyFB        : SR; // 使用标准置位复位功能块(SR 型)
END_VAR

// 在主程序(如 MAIN 或 Cyclic OB)中调用
MyFB(S := StartButton, R := NOT StartButton, Q => MotorOn);

说明:

  • SR 是 IEC 标准功能块,含输入 S(置位)、R(复位)、输出 Q
  • 此处 S := StartButton 将按钮信号传入;R := NOT StartButton 实现按下即启、松开即停(非自锁);Q => MotorOn 把输出结果存入 MotorOn 变量。
  • 注意:NOT StartButton 是表达式,允许出现在 := 右侧;但 => 右侧只接受左值(l-value),即能被写入的变量。

四、必须避开的 5 类典型错误

错误类型 错误写法 原因 修正方式
未声明实例 MyFB(IN := Signal);(无 VAR MyFB : MyFBType; 编译器找不到 MyFB 对象 在 VAR 区补全声明
混淆赋值与映射 MyFB(IN => Signal); => 用于输出,IN 是输入,方向反了 改为 IN := Signal
输出目标非法 MyFB(Q => TRUE); TRUE 是常量,无法写入 改为 Q => OutputVar(变量名)
类型强转缺失 MyFB(IN := 123);INREAL123INT 部分平台严格检查,需显式转换 改为 IN := REAL#123IN := 123.0
重复调用同一实例 MyFB(...); 多次出现且无间隔 功能块状态被连续覆盖,逻辑紊乱 每个实例名仅调用一次/周期;需多路逻辑时声明多个实例(如 MyFB1, MyFB2

五、高级技巧:如何处理复杂参数?

1. 结构体输入/输出

MyFBType 定义输入为结构体:

TYPE MyFBType : FUNCTION_BLOCK
    VAR_INPUT
        Config : CONFIG_STRUCT;
    END_VAR
    VAR_OUTPUT
        Result : RESULT_STRUCT;
    END_VAR
END_TYPE

调用时可整体传入:

MyFB(Config := (Kp := 1.5, Ti := 10.0), Result => MyResult);

括号内为结构体字面量,字段名必须与 CONFIG_STRUCT 定义一致。

2. 数组输入

IN 是数组(如 ARRAY[0..2] OF INT),可传入同维数组变量:

MyArray : ARRAY[0..2] OF INT := [1, 2, 3];
MyFB(IN := MyArray);

3. 引用传递(VAR_IN_OUT)

部分功能块设计 VAR_IN_OUT 参数(如数据交换类 FB),此时用 :==> 均可,但语义不同:

  • Data := LocalBuf:把 LocalBuf 值拷入功能块内部副本;
  • Data => LocalBuf:让功能块直接操作 LocalBuf 内存(零拷贝,高效)。
    选择取决于是否需要功能块修改原始数据。

六、执行时序与扫描周期关系

PLC 程序按循环扫描执行:读输入 → 执行程序 → 写输出。
功能块调用 MyFB(...); 的执行时机在此循环的“执行程序”阶段,且严格按代码书写顺序执行

例如:

MyFB1(IN := A, Q => X);
MyFB2(IN := X, Q => Y); // 此处 X 已是 MyFB1 的最新输出

MyFB2 读到的是 MyFB1 本周期计算出的 X,而非上周期旧值。这是 ST 的确定性优势。

注意:若两功能块并行逻辑无依赖,顺序无关;但存在数据链时(如滤波后比较),顺序即逻辑。


七、调试核心:如何确认调用真正生效?

  1. 在线监控:在编程软件中,将光标悬停于 MyFB 上,查看其内部变量(如 IN, Q, 内部Timer.ET)实时值;
  2. 强制赋值测试:手动将 Signal 强制为 TRUE,观察 Output 是否按预期变为 TRUE
  3. 断点单步:在支持调试的平台(如 Codesys)中,在该行设断点,观察调用前后各变量变化;
  4. 日志输出:添加辅助语句 IF MyFB.Q THEN Log('MyFB active'); END_IF; 辅助追踪。

八、命名与工程规范建议

  • 实例名 MyFB 应具业务含义:ConveyorStartFB, TempCtrlPID,避免泛称;
  • 输入/输出参数名(IN, Q)是功能块类型定义的一部分,不得在调用时更改;若需语义提示,可用注释:
    MyFB(IN := ConveyorSensor, Q => ConveyorRunning); // IN=光电开关,Q=运行标志
  • 同一功能块多次使用时,实例名后缀编号(ValveCtrl_1, ValveCtrl_2),禁止用 ValveCtrl1(易与类型名混淆);
  • 所有功能块类型定义应集中存放于专用 POU(Program Organization Unit),如 FBS_LIBRARY,便于复用与版本管理。

九、与其他语言调用方式对比(加深理解)

语言 调用语法 关键差异
ST(本文) MyFB(IN := A, Q => B); 显式区分输入赋值 := 与输出映射 =>;支持结构体字面量
LD(梯形图) 触点驱动功能块符号,连线表示 IN/Q 图形化,但复杂参数(如结构体)难以表达
FBD(功能块图) 方框引脚连线 直观,但大规模网络易混乱,不易版本比对
IL(指令表) CAL MyFB IN:=A Q=>B 接近汇编,已基本淘汰

ST 因其文本可比性、Git 友好、参数显式化,已成为现代自动化项目的首选编程语言。


十、最后验证清单(写完每条调用后快速自查)

  1. MyFB 是否已在 VAR 区声明?类型是否匹配?
  2. ✅ 所有 := 右侧变量是否已声明且类型兼容?
  3. ✅ 所有 => 右侧是否为可写变量(非常量、非表达式)?
  4. ✅ 分号 ; 是否存在?
  5. ✅ 若含结构体/数组,字段名与维度是否与类型定义完全一致?
  6. ✅ 在线下载后,是否通过强制与监控确认逻辑行为符合预期?

通过此清单,99% 的功能块调用问题可在编码阶段拦截。

评论 (0)

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

扫一扫,手机查看

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