跳到正文
Learn-SCL
SCL 示例库/SCL 边沿检测:上升沿与下降沿

SCL 边沿检测:上升沿与下降沿

SCL 上升沿/下降沿怎么写:用一个 Bool 保存上一周期状态,代码只有 3 行;含完整 FB、接口表和云仿真场景。

入门 S7-1200 S7-1500 边沿检测 Bool FB 状态位 1 块 / 29 行 可仿真 TIA 已验证

一句话:SCL 边沿检测用 Rising := Signal AND NOT Prev; Falling := NOT Signal AND Prev; Prev := Signal。Prev 必须是静态变量,而且要在判断之后更新。

导入到我的 TIA 项目

通过 TiaLink 把本示例的 1 个 SCL 块作为“外部源”导入你当前打开的 TIA Portal 项目:自动生成块、编译,并清理外部源。导入后不会自动保存;FB 示例导入后需要你在 OB 里调用。

TiaLink 设置

默认 http://localhost:8080。也可以在本页地址后加 ?tialink= 临时指定。

TiaLink 启动时若设置了 --api-token,这里要填相同的值;只保存在本机浏览器 localStorage,不会上传。

边沿检测是 PLC 程序里最基础、也最容易被写错的一段逻辑:它要回答“这个信号是不是刚刚从 0 变成 1(或从 1 变成 0)”,而不是“它现在是不是 1”。

SCL 边沿检测时序:Signal 上升沿时 Rising 只在一个扫描周期为 1,下降沿时 Falling 同理
Signal 上升沿 → Rising 单周期脉冲;Signal 下降沿 → Falling 单周期脉冲。

概述

这个示例把上一扫描周期的 Signal 保存在静态变量 Prev 里,本周期先比较、再更新:

  • Rising = Signal AND NOT Prev:本周期为 1、上周期为 0,就是上升沿。
  • Falling = NOT Signal AND Prev:本周期为 0、上周期为 1,就是下降沿。

两个输出都只在一个扫描周期内为 1,所以可以直接用来做“按一次加一”“启动一次流程”“记录一次报警”这类一次性动作。

你将学到

  • 为什么边沿检测必须有一个“上一周期状态”变量;
  • 为什么必须先判断边沿,再更新历史值;
  • 一个 FB 如何同时输出上升沿和下降沿;
  • 如何用云仿真验证“边沿只出现一个扫描周期”。

接口与变量

下表由构建器从 SCL 源码的接口声明自动生成;页面上展示的代码就是导入 TIA 的同一份源码。

FB_EdgeDetection FB

区块名称类型说明
输入SignalBool
输出RisingBool
输出FallingBool
静态PrevBool

程序结构

导入顺序以下表为准:被依赖的块/类型先导入;本页已按依赖排好。

  1. FB_EdgeDetection FB 上升沿/下降沿检测 · 29 行 · 2 段

FB_EdgeDetection FB

上升沿/下降沿检测 · 29 行 · 源文件 blocks/FB_EdgeDetection.scl

查看 / 复制完整块源码
FB_EdgeDetection.scl
1FUNCTION_BLOCK "FB_EdgeDetection"
2{ S7_Optimized_Access := 'TRUE' }
3VERSION : 0.1
4   VAR_INPUT
5      Signal : Bool;   // 现场信号(按钮、传感器、运行反馈等)
6   END_VAR
7 
8   VAR_OUTPUT
9      Rising : Bool;   // 上升沿:本周期为 1,且上周期为 0
10      Falling : Bool;  // 下降沿:本周期为 0,且上周期为 1
11   END_VAR
12 
13   VAR
14      Prev : Bool;     // 上一扫描周期的 Signal
15   END_VAR
16 
17BEGIN
18   REGION 边沿判断
19      // 上升沿 = 当前为 1 且上一周期为 0;下降沿相反。
20      #Rising := #Signal AND NOT #Prev;
21      #Falling := NOT #Signal AND #Prev;
22   END_REGION
23 
24   REGION 保存历史状态
25      // 必须放在边沿判断之后:先比较,再更新历史值。
26      #Prev := #Signal;
27   END_REGION
28END_FUNCTION_BLOCK
29 

FB_EdgeDetection / 边沿判断 — 当前值与历史值比较

FB_EdgeDetection.scl · 边沿判断
18   REGION 边沿判断
19      // 上升沿 = 当前为 1 且上一周期为 0;下降沿相反。
20      #Rising := #Signal AND NOT #Prev;
21      #Falling := NOT #Signal AND #Prev;
22   END_REGION

目的:根据当前 Signal 和上一周期的 Prev 判断上升沿/下降沿。

条件 → 动作:Signal=1 且 Prev=0 → Rising=1;Signal=0 且 Prev=1 → Falling=1;其他情况两个输出都为 0。

为什么:边沿不是信号电平,而是电平的变化。只比较当前值无法知道“刚刚变化”。

注意:两个输出都是单扫描周期脉冲;如果后续逻辑需要保持,必须自己用 S/R 或自锁。

FB_EdgeDetection / 保存历史状态 — 把当前值留到下一周期

FB_EdgeDetection.scl · 保存历史状态
24   REGION 保存历史状态
25      // 必须放在边沿判断之后:先比较,再更新历史值。
26      #Prev := #Signal;
27   END_REGION

目的:让下一个扫描周期还能知道“上一周期是什么”。

条件 → 动作:每个扫描周期无条件执行 Prev := Signal。

为什么:Prev 是 FB 的静态变量,掉电保持/扫描间保持;如果放在 VAR_TEMP,每个周期都会丢失,边沿就永远检测不到。

注意:这一行必须放在边沿判断之后。如果先更新 Prev,本周期比较时 Prev 已经等于 Signal,两个边沿都会丢失。

仿真验证:让 Agent 写场景并执行(不需要博途)

推荐:让 Agent 自己设计场景

不需要你手写 scenario。把下面的提示词复制给已连接 PLC 云仿真 MCP 的 AI 助手(Claude Code / Cursor / VS Code 等),它会阅读源码、自己设计正常/边界/异常场景,并调用 scl_run_scenario 执行;新用户有 100 次免费调用。

  1. 复制提示词(包含完整 SCL 源码和任务说明)。
  2. 粘贴给已配置 sim MCP 的 Agent,让它先 scl_validate,再执行自己写的 scl_run_scenario。
  3. 看 Agent 返回的 PASS/FAIL、输入/期望/实际;需要精确复现时,再对照下方本站回归基线。
AGENT PROMPT
你已连接 PLC 云仿真 MCP(sim-cloud)……

任务:阅读下面的 SCL 示例,自己设计 3 个场景并用 scl_run_scenario 执行:
1) 正常路径
2) 边界/临界值
3) 异常、互锁或超时
每个场景请给出输入、期望、实际结果和 PASS/FAIL,并说明场景设计理由。
不要照抄现成场景。

示例:SCL 边沿检测:上升沿与下降沿
// 复制后包含完整 SCL 源码和 MCP 参数说明

页面上只显示提示词开头;复制的内容包含全部块源码和 MCP 参数说明。

查看本站回归基线(固定场景,不是让你手写)

下面是本站构建时跑过的固定场景和预期输出,用来做回归对比或精确复现;不是要求你手写 scenario。推荐先让 Agent 自己写场景,再和这份基线对照。

EXPECTED
PASS  上升沿只出现一个扫描周期 (5 step(s), 5 scan(s))
RESULT: ALL PASS (5 scan(s))
BASELINE JSON
{
  "sources": [
    {
      "name": "blocks/FB_EdgeDetection.scl",
      "source": "FUNCTION_BLOCK \"FB_EdgeDetection\"\n{ S7_Optimized_Access := 'TRUE' }\nVERSION : 0.1\n   VAR_INPUT\n      Signal : Bool;   // 现场信号(按钮、传感器、运行反馈等)\n   END_VAR\n\n   VAR_OUTPUT\n      Rising : Bool;   // 上升沿:本周期为 1,且上周期为 0\n      Falling : Bool;  // 下降沿:本周期为 0,且上周期为 1\n   END_VAR\n\n   VAR\n      Prev : Bool;     // 上一扫描周期的 Signal\n   END_VAR\n\nBEGIN\n   REGION 边沿判断\n      // 上升沿 = 当前为 1 且上一周期为 0;下降沿相反。\n      #Rising := #Signal AND NOT #Prev;\n      #Falling := NOT #Signal AND #Prev;\n   END_REGION\n\n   REGION 保存历史状态\n      // 必须放在边沿判断之后:先比较,再更新历史值。\n      #Prev := #Signal;\n   END_REGION\nEND_FUNCTION_BLOCK\n"
    }
  ],
  "scenario": {
    "docs": [
      "blocks/FB_EdgeDetection.scl"
    ],
    "block": "FB_EdgeDetection",
    "tickMs": 10,
    "always": [
      "!(Rising && Falling)"
    ],
    "scenarios": [
      {
        "name": "上升沿只出现一个扫描周期",
        "steps": [
          {
            "set": {
              "Signal": false
            },
            "expect": {
              "Rising": false,
              "Falling": false
            }
          },
          {
            "set": {
              "Signal": true
            },
            "expect": {
              "Rising": true,
              "Falling": false
            }
          },
          {
            "set": {
              "Signal": true
            },
            "expect": {
              "Rising": false,
              "Falling": false
            }
          },
          {
            "set": {
              "Signal": false
            },
            "expect": {
              "Rising": false,
              "Falling": true
            }
          },
          {
            "set": {
              "Signal": false
            },
            "expect": {
              "Rising": false,
              "Falling": false
            }
          }
        ]
      }
    ]
  }
}

打开 PLC 云仿真

关键 SCL 语法

写法 含义
#Signal 访问 FB 的局部变量/参数
AND / NOT 逻辑与 / 逻辑非
:= 赋值
VAR FB 的静态变量,扫描间保持
REGION ... END_REGION 给代码分段,方便阅读和讲解

常见坑

  • 把 Prev 写成 VAR_TEMP:临时变量每个周期重建,边沿检测失效。
  • 先更新 Prev 再判断:本周期比较的是“自己和自己”,永远检测不到边沿。
  • 用边沿输出直接驱动长时间动作:边沿只有一个周期,必须自锁或置位。
  • 在 OB 里用全局 M 点做 Prev:可以工作,但多个调用点会互相干扰;FB 静态变量更安全。

变体与扩展

  • 需要“上升沿 + 下降沿”两个独立 FC 时,可以把两段逻辑拆成 FC_EdgePos / FC_EdgeNeg,用 IN_OUT 传入历史位;本页为了仿真合并成一个 FB。
  • 需要检测“信号变化”而不区分方向时,可以用 Signal XOR Prev。
  • 对安全相关信号,边沿检测不能替代安全功能;安全逻辑应使用 F-CPU / 安全程序。

常见问题

SCL 上升沿为什么要保存上一周期的信号?

边沿是“本周期为 1、上周期为 0”的变化,不是电平本身。必须把上一周期的 Signal 存到静态变量 Prev,再在判断之后更新;Prev 放 VAR_TEMP 或先更新再判断,都会让 Rising 永远为 FALSE。

手写边沿和 R_TRIG 哪个好?

两者等价:R_TRIG 把 Prev 封装在实例里,适合标准库;手写三行更透明,方便在云仿真里逐扫描看变量。多调用点不要共用一个 Prev,否则会互相干扰。

验证状态

项目结果日期证据
本地仿真场景PASS(5 scans)2026-11-01页面下方 `scl_run_scenario` 请求可复现
PLC 云仿真PASS2026-11-01`scl_run_scenario`(托管 MCP)
TIA 导入编译PASS(0 error / 0 warning)2026-11-01本地 SCL 仿真与 PLC 云仿真(scl_run_scenario)场景通过;TIA Portal V19 + TiaLink 1.4.0.0 批量导入 PLC_2,编译 0 错误 / 0 警告,已保存。

本地仿真引擎验证语法、结构和逐扫描行为;TIA 编译验证在 Windows + TIA Portal + TiaLink 上完成。两者不能互相替代。

来源与许可

本页示例改编自 github.com/lopez-dev/Siemens-SCL-Source-Files 的 EdgeDetection/EdgeDetection.scl,原作者 Daniel Cáceres López,以 MIT 许可发布。中文注释、接口调整、仿真场景与页面讲解由 Learn-SCL 编写。

原文件是两个 FC(EdgeDetectionPos / EdgeDetectionNeg);本站合并为一个 FB,便于逐扫描仿真和导入。

示例源码以 MIT 许可发布(上游仓库);中文讲解与页面内容版权归汇智网(Hubwiz)。官方参考:Siemens TIA Portal。

把这个示例带进你的工程

TiaLink

把 TIA Portal 接到你的智能体:导入、编译、读回核对、PLCSIM 仿真。本地运行,工程数据不出厂。

了解 TiaLink →

PLC 云仿真

不装博途,把 SCL 放到云端逐扫描执行:校验、仿真、场景验收。新用户 100 次免费。

打开云仿真 →

Learn-LAD

同一个团队的梯形图示例库:逐网络讲解、变量表、TiaLink 一键导入。

浏览 LAD 示例 →