ST怎么写上升沿检测:使用 R_TRIG 功能块实例化并调用 .CLK 和 .Q

发布于 2026-03-14 23:03:33 · 浏览 3 次 · 评论 0 条

在结构化文本(ST)编程中,上升沿检测是电气自动化控制系统中最基础、最频繁使用的逻辑功能之一。它用于捕捉信号由“0”变为“1”的瞬时变化,常见于启动按钮触发、脉冲计数、状态切换、故障锁定等场景。ST 语言本身不提供内置的 RISING_EDGE 运算符(如某些厂商的 LD/FBD 中有),但通过标准 IEC 61131-3 功能块 R_TRIG(Retriggerable Rising Edge Trigger),可实现稳定、可复位、抗抖动、符合工业规范的上升沿识别。

以下内容全程基于 ST 语言语法,以 Siemens TIA Portal(V18+)、Codesys、3S CoDeSys、B&R Automation Studio 等主流平台通用规则编写,不依赖特定品牌扩展指令,所有代码可直接复制粘贴至 ST 编辑器中使用。


一、理解 R_TRIG 的行为逻辑

R_TRIG 是一个标准功能块(FB),其核心作用是:当 .CLK 输入信号从 FALSE 跳变为 TRUE 时,将 .Q 输出置为 TRUE,且该输出仅维持一个扫描周期(即下一个周期自动清零),除非 .CLK 在该周期内再次为 TRUE 并满足重触发条件

关键特性说明:

  • .CLK:时钟输入端。必须为布尔量(BOOL)。仅当 .CLK 本次为 TRUE 且上一次为 FALSE 时,.Q 才在本周期置位。
  • .Q:上升沿输出端。类型为 BOOL。每个扫描周期开始时自动复位;仅在检测到有效上升沿的当周期为 TRUE。
  • .CLK 的历史状态由 R_TRIG 实例内部隐式保存(无需手动声明静态变量)。
  • 该功能块是“可重触发”(Retriggerable)的:若 .CLK.Q = TRUE 的同一周期内持续为 TRUE 或多次变化,.Q 仍只在首个上升沿响应,不会重复置位——这保证了单次事件的唯一性。

✅ 正确理解:.Q 不是锁存器,不是自保持,也不是延时输出。它是纯粹的“边沿快照”,生命周期严格限定在检测发生的那个 PLC 扫描周期内


二、在 ST 中实例化并调用 R_TRIG 的完整步骤

1. 声明 R_TRIG 实例变量

在程序组织单元(POU)的 VAR 区域(如 FB、FC 或 PRG 的变量声明段)中,声明一个具名的 R_TRIG 功能块实例。不能直接写 R_TRIG(CLK := x);(这是非法的无名调用),必须先命名实例。

VAR
    myRisingEdge : R_TRIG;  // 实例名称为 myRisingEdge,类型为 R_TRIG 标准功能块
    inputSignal : BOOL := FALSE;  // 示例输入信号(如 I0.0 对应的变量)
    edgeDetected : BOOL;          // 接收 .Q 输出的布尔变量
END_VAR

⚠️ 注意:R_TRIG 是功能块(FB),不是函数(FC),因此必须声明为变量,不能像 TON() 那样作为表达式直接调用。

2. 在 ST 主体中调用实例并连接引脚

BEGIN ... END; 之间,使用功能块调用语法.CLK 赋值,并读取 .Q

myRisingEdge(CLK := inputSignal);
edgeDetected := myRisingEdge.Q;

✅ 正确写法解析:

  • myRisingEdge(...) 是对已声明实例的调用;
  • (CLK := inputSignal) 是引脚赋值,语法为 参数名 := 值
  • myRisingEdge.Q 是访问该实例的输出成员,. 是结构体成员访问运算符;
  • 每次调用都会更新内部状态,无需额外初始化或复位指令。

❌ 常见错误写法(全部无效):

  • R_TRIG(CLK := inputSignal).Q → 无名调用,ST 不支持;
  • R_TRIG(inputSignal) → 缺少参数名,语法错误;
  • myRisingEdge.Q := inputSignal → 方向反了,.Q 是只读输出;
  • 忘记调用 myRisingEdge(...).Q 始终为 FALSE,因未触发状态更新。

3. 完整可运行示例(带注释)

以下是一个独立、可编译的 ST 程序片段(适用于 PRG 或 FB 的 BODY):

PROGRAM Main
VAR
    // 输入信号(模拟按钮、传感器等)
    btnStart : BOOL := FALSE;   // 假设来自输入映射,如 %I0.0
    // R_TRIG 实例
    trigStart : R_TRIG;
    // 上升沿标志(可用于触发后续动作)
    startPulse : BOOL;
    // 其他业务变量
    motorRunning : BOOL := FALSE;
END_VAR

// 主逻辑
trigStart(CLK := btnStart);
startPulse := trigStart.Q;

// 利用上升沿启动电机(单次触发)
IF startPulse THEN
    motorRunning := TRUE;
END_IF;

// 停止逻辑(示例:另一按钮下降沿)
// (此处略,仅说明上升沿用途)

执行过程逐周期说明(假设扫描周期为 2ms):

周期 btnStart trigStart.CLK 当前值 上周期 CLK 是否上升沿? trigStart.Q startPulse
1 FALSE FALSE —(初始) FALSE FALSE
2 TRUE TRUE FALSE ✅ 是 TRUE TRUE
3 TRUE TRUE TRUE FALSE FALSE
4 FALSE FALSE TRUE FALSE FALSE

可见:startPulse 仅在周期 2 为 TRUE,精准捕获跳变瞬间。


三、进阶用法与工程实践要点

▪ 多信号共用同一 R_TRIG 实例?不可行!

每个 R_TRIG 实例维护独立的内部历史状态。若尝试复用同一实例检测多个信号:

trigStart(CLK := btnStart);   // ❌ 覆盖了之前状态
trigStart(CLK := sensorA);    // ❌ 覆盖了 btnStart 的历史

结果:sensorA 的上升沿判断将错误依赖 btnStart 的上周期值,逻辑崩溃。

✅ 正确做法:为每个需检测的信号声明独立实例

VAR
    trigBtnStart : R_TRIG;
    trigSensorA  : R_TRIG;
    trigReset    : R_TRIG;
END_VAR

trigBtnStart(CLK := btnStart);
trigSensorA(CLK := sensorA);
trigReset(CLK := resetBtn);

startPulse := trigBtnStart.Q;
alarmRising := trigSensorA.Q;
resetActive := trigReset.Q;

▪ 如何实现“电平保持型”上升沿(即 Q 锁存直到手动复位)?

R_TRIG 本身不锁存,但可轻松组合 SR 触发器实现:

VAR
    trigStart : R_TRIG;
    startLatch : SR;  // 标准置位复位触发器(SR 功能块)
    btnStart, btnStop : BOOL;
    startHeld : BOOL;
END_VAR

trigStart(CLK := btnStart);
startLatch(S1 := trigStart.Q, R := btnStop);  // S1 置位,R 复位
startHeld := startLatch.Q0;

此时 startHeld 在首次按下 btnStart 后变为 TRUE,并保持,直至 btnStop 为 TRUE。

▪ 抗抖动处理(硬件/软件协同)

机械按钮存在毫秒级抖动(bounce),可能被误判为多次上升沿。R_TRIG 本身不滤波,需前置消抖:

  • ✅ 推荐:在信号采集层(如 PLC 输入模块配置)启用硬件滤波(如 10 ms 滤波时间);
  • ✅ 软件替代:用 TON 定时器做软件消抖(延迟确认):
VAR
    btnRaw : BOOL;
    btnDebounced : BOOL;
    debouncer : TON;
END_VAR

debouncer(IN := btnRaw, PT := T#20ms);
btnDebounced := debouncer.Q;  // 仅当 btnRaw 持续 20ms 为 TRUE 后才输出 TRUE

// 再送入 R_TRIG
trigStart(CLK := btnDebounced);

四、与其他上升沿实现方式对比(表格)

以下对比 ST 中常见上升沿方案的可靠性与适用性:

方法 语法示例 是否标准 IEC 61131-3 抗扫描周期依赖 可复位性 推荐指数 说明
R_TRIG 实例 trig(CLK := x); y := trig.Q; ✅ 全平台兼容 ✅ 自动跨周期记忆 ✅ 单周期自动复位 ⭐⭐⭐⭐⭐ 工业首选,语义清晰,无歧义
XOR + D 寄存器 y := x XOR x_prev; x_prev := x; ✅ 通用 ✅ 需手动保存上周期值 ✅ 可控 ⭐⭐⭐☆ 需额外变量,易出错;x_prev 必须为 VAR RETAINVAR_GLOBAL
NOT + AND 组合 y := (NOT x_prev) AND x; x_prev := x; ✅ 通用 ✅ 同上 ✅ 可控 ⭐⭐⭐ 逻辑等效,但不如 R_TRIG 直观
厂商专用指令(如 Siemens P_TRIG trig(CLK := x); y := trig.Q; ❌ 仅 Siemens ⭐⭐⭐⭐ 行为同 R_TRIG,但非跨平台,不推荐用于可移植项目

注:P_TRIGR_TRIG 在 Siemens 中几乎等价(P_TRIG 不可重触发,R_TRIG 可重触发),但在其他平台无定义,故统一使用 R_TRIG 保障兼容性。


五、典型错误排查清单

遇到 R_TRIG 不工作?按顺序检查:

  1. ✅ 实例是否已声明VAR 区)?
  2. ✅ 是否在每次循环中都调用了该实例?(漏调用 → .Q 永远 FALSE)
  3. .CLK 输入是否为 BOOL 类型?若传入 INT 或指针,编译报错或行为未定义;
  4. .Q 是否被后续逻辑覆盖或屏蔽?例如 edgeDetected := FALSE; 写在调用之后;
  5. ✅ 输入信号是否真实变化?用监控表观察 btnStart 波形,确认有明确 0→1 跳变;
  6. ✅ 是否在函数(FC)中误用R_TRIG 是 FB,只能在 FB 或 PRG 中声明,不能在 FC 中声明(FC 无实例存储空间);

六、完整工程模板(可直接复用)

// 文件:RisingEdgeHandler.st
// 功能:封装标准化上升沿检测,支持多通道、带使能控制
FUNCTION_BLOCK RisingEdgeDetector
VAR_INPUT
    Enable : BOOL := TRUE;     // 全局使能,禁用时忽略输入
    CLK : BOOL;               // 待检测信号
END_VAR
VAR_OUTPUT
    Q : BOOL;                 // 上升沿脉冲(1 扫描周期)
END_VAR
VAR
    internalTrig : R_TRIG;
    filteredCLK : BOOL;
END_VAR

// 使能过滤
filteredCLK := CLK AND Enable;

// 执行上升沿检测
internalTrig(CLK := filteredCLK);
Q := internalTrig.Q;

调用方式:

// 在主程序中
VAR
    detectorStart : RisingEdgeDetector;
    btnStart : BOOL;
    startPulse : BOOL;
END_VAR

detectorStart(Enable := TRUE, CLK := btnStart);
startPulse := detectorStart.Q;

此封装解耦了检测逻辑与业务逻辑,支持批量实例化与集中管理。


R_TRIG 的本质价值,在于将“边沿”这一时序概念,封装为可预测、可复用、可测试的确定性组件。它不隐藏状态,不引入隐式行为,完全符合结构化编程的透明性原则。只要严格遵循“声明 → 调用 → 读取”的三步链路,即可在任意符合 IEC 61131-3 的 PLC 平台上,稳定、高效、跨平台地实现上升沿检测。

评论 (0)

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

扫一扫,手机查看

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