> ## Content Index
> Fetch the complete content index at: https://www.hubwiz.com/blog/llms.txt
> Use this file to discover other available public pages before exploring further.

# 梯形图怎么读：Stop 按下之后，端子还多亮一个扫描
- URL: https://www.hubwiz.com/blog/read-plc-ladder-logic-scan-cycle-seal-in-timer/
- Published: 2026-11-09T10:22:14.000Z
- Updated: 2026-11-09T10:22:55.000Z
- Description: 程序说开、HMI 说开，端子还亮着一个扫描。梯形图不是电路图：三个网络、八个扫描，把四层状态分开。
- Author: admin
- Tags: PLC, 梯形图, 扫描周期, 定时器, 工业自动化

一段梯形图里，最容易被看错的不是指令，是**时间**。

`Stop` 采样到 0 的那个扫描，程序已经把输出映像清掉了；但端子上的电还要等到下一个扫描开始时的输出传送才断。也就是说：程序说"停了"和现场真"停了"之间，隔着一个扫描。这不是实现瑕疵，是过程映像的默认更新边界。

下面这段来自英文技术索引 Atlas of Engineering 的《Reading and Testing PLC Ladder Logic》。它只用三个网络——一个起保停、一个接通延时定时器、一个输出赋值——把"输入映像、内部存储、输出映像、物理输出"这四层逐扫描拆开。原文在最后给了一句判断标准：**梯形图是一份可执行的状态转换规格，读得懂它，意味着你能在看在线监视之前就预测出这次变化。**

## 先定输入语义，再选触点

对梯形图的触点来说，"常开"和"常闭"描述的是**逻辑判断**：

| 指令     | 什么时候判为真          | 布尔含义 |
| ------ | ---------------- | ---- |
| 常开触点   | 它对应的位是 1         | x    |
| 常闭触点   | 它对应的位是 0         | ¬x   |
| 普通输出线圈 | 把进入的梯级结果写下去，包括 0 | 赋值   |

串联实现与，并联实现或。**一个常闭指令并不能证明它对应的物理开关是常闭的。**指令语义以 [Siemens S7-1200 位逻辑文档](https://docs.tia.siemens.cloud/r/simatic%5Fs7%5F1200%5Fmanual%5Fcollection%5Fenus%5F20/basic-instructions/bit-logic-operations/bit-logic-instructions?ref=hubwiz.com) 为准。

把教学用的输入这样定义：

| 变量     | 为 1 的含义    | 为 0 的含义       |
| ------ | ---------- | ------------- |
| Start  | 采样到启动按钮被按下 | 采样到启动按钮已松开    |
| StopOK | 停止回路处于允许状态 | 有停止请求，或允许条件缺失 |

设想一个物理上是常闭的停止按钮，接线后松开时输入为 1、按下时为 0。于是程序里用一个**逻辑常开的 `StopOK` 触点**来放行。同一个位上用常闭指令，放行的就是相反的状态。这个命名选择让想要的逻辑变得明确。

也要看到反例：一根断线同样能让 `StopOK = 0`；一个跨接在开关两端的短接可以掩盖一次按下。**一个输入既不能诊断所有故障，也不构成安全性能等级。**逻辑极性只是控制设计的一部分。

## 把扫描约定写清楚

这个例子遵循 **Siemens S7-1200 在 V20 文档中描述的默认循环过程映像顺序**：一个周期开始时，控制器先把已有的输出映像传送到配置好的物理输出；然后采集输入，执行循环程序。程序指令在这段执行里更新内存和输出映像。参见 [RUN 模式下扫描周期的处理](https://docs.tia.siemens.cloud/r/simatic%5Fs7%5F1200%5Fmanual%5Fcollection%5Fenus%5F20/plc-concepts/execution-of-the-user-program/processing-the-scan-cycle-in-run-mode?ref=hubwiz.com)。

原文的模拟器刻意只选一个任务、每个扫描各更新一次输入/输出映像、不做立即读外设，它的理想扫描间隔恒定。中断、分布式 I/O 调度、模块时延都在这个模型之外。

对扫描 n，要分开四样东西：

- **输入映像**：本次执行全程使用的 `Start` 与 `StopOK` 采样值。
- **内部存储**：指令执行过程中被读写的值。
- **输出映像 Q\_n**：扫描 n 里程序执行完的结果。
- **扫描 n 期间的物理输出**：本次输入采集之前传送出去的那份更早的映像 Q\_{n−1}。

后面网络的一条指令可以读到**同一个扫描里**前面网络刚写过的内部位。但这不等于一个普通物理输出会在同一时刻变化。不同控制器配置的更新边界不一样——**在把这套时序解释搬过去之前，先确认你手上这台用的是哪一种。**

## 网络 1：把自锁写显式

把 `StopOK` 串在 `Start` 与 `Run` 的并联组合之前，再串一个普通 `Run` 线圈。令 K\_n 为 `StopOK`、S\_n 为 `Start`、R\_n 为新赋值的 `Run` 状态：

```
R_n = K_n ∧ (S_n ∨ R_{n−1})

```

自锁触点读到的是**上一轮**的值，因为在这个例子里没有任何更早的指令写过 `Run`；随后线圈把它替换掉。这就是**自锁（seal-in）**：记忆通过布尔反馈路径保存，而不是靠一条专门的置位指令。

| StopOK | Start | 上一轮 Run | 新 Run | 解释             |
| ------ | ----- | ------- | ----- | -------------- |
| 0      | 任意    | 任意      | 0     | 停止同时封锁两条路径     |
| 1      | 1     | 任意      | 1     | 启动建立 Run       |
| 1      | 0     | 1       | 1     | 自锁分支维持 Run     |
| 1      | 0     | 0       | 0     | 没有启动、也没有已存下的请求 |

停止之所以优先，是因为它在并联分支的**外面**。如果那个并联分支跨过了 `StopOK`，自锁路径就能压过停止。如果去掉反馈触点，`Run` 会跟着按钮走，Start 一松手就消失。

![](https://www.hubwiz.com/blog/content/images/2026/11/ladder-800.jpg)

**逻辑网络，不是接线图。**从左往右读，按 1、2、3 的顺序执行。图中所有触点都在测 1。网络 1 里的 `Run` 触点读的是旧内存；网络 2 和 3 里的 `Run` 触点读的是新值。TON0 **每个扫描都会被算一次**，包括 `Run` 为假的时候。

## 网络 2：每个扫描都要调用接通延时定时器

IEC 风格的 **TON** 是把一个真输出往后延。把 `Run` 接到它的 `IN`，给一个固定的预设 `PT`，把输出 `Q` 拷给 `DelayDone`；已过时间输出是 `ET`。用**专用的定时器实例** `TON0`，免得它的计时状态被别处无意共享。

对 [Siemens 的 TON 指令](https://docs.tia.siemens.cloud/r/en-us/v20/lad-s7-1200-s7-1500/timer-operations-s7-1200-s7-1500/ton-generate-on-delay-s7-1200-s7-1500?ref=hubwiz.com)：`IN` 上升沿开始延时；`PT` 走完且 `IN` 仍为真时 `Q` 变真。`IN` 为假会复位 `Q` 与 `ET`。这个例子每个扫描都调用定时器，所以当停止把 `Run` 清掉时，它能看到那个假输入。

**不要写成"只有 Run 为真时才调用 TON"，然后假设跳过调用等价于输入为假。**定时器有状态，更新它是一次被执行的操作。Siemens 在[定时器工作原理](https://docs.tia.siemens.cloud/r/simatic%5Fs7%5F1200%5Fmanual%5Fcollection%5Fenus%5F20/basic-instructions/timer-operations/timer-operation-iec-timers?ref=hubwiz.com)里说明了它的时基和更新点。

原文的教学模型在第一次为真的调用时记下起始时间戳。之后每次 `Run` 为真的调用：

```
ET_n = min(PT, t_n − t_start)
D_n  = (ET_n ≥ PT)

```

`Run` 为假时把 ET\_n 置 0、D\_n 置 0。这里 D\_n 就是 `DelayDone`。**定时器不是在数扫描次数**：已过时间来自时钟；扫描间隔恒定只是让这个例子的采样时间戳好算。

取 PT = 30 ms、间隔 10 ms。如果第一次为真的调用发生在扫描 1，它的 ET 是 0；扫描 2、3 报 10 和 20 ms；扫描 4 到 30 ms。把第一次为真的调用算成 10 ms，就会**早一个扫描**就使能。

如果 PT 改成 25 ms，调用仍然每 10 ms 一次。第一个达到或超过阈值的调用在起始后 30 ms，所以采样到的 `DelayDone` 相对理想阈值**晚了 5 ms**。这个观测延迟，和随后的输出传送是两件不同的事。

## 网络 3：给输出映像赋值

把 `Run` 和 `DelayDone` 串联，结果赋给一个普通的 `MotorCmd` 输出线圈：

```
Q_n = R_n ∧ D_n

```

显式写上 `Run` 条件，让"使能意图"在图上看得见。网络 3 读到的，是网络 1 和 2 在这个扫描里产生的值。因此**观察到停止的那个扫描，输出映像就已经被清掉**——即便定时器此前已经到时。

每一个这样的位，只保留一个赋值位置。如果两个普通线圈在同一个扫描里写同一个位，后执行的赋值会盖掉先前的。同样，交换网络顺序能让一段梯级作用在过期状态上。**没有执行顺序，一个梯形图页面的视觉连通性不足以作为程序行为的证据。**

## 走一遍完整的启停

把非保持型 `Run`、定时器状态和输出映像初始化为 0。在这条指定的轨迹里，`Start` 只在扫描 1 为真；`StopOK` 在扫描 7 为假、其余为真。时间戳间隔 10 ms，定时器 PT = 30 ms。

| 扫描    | Start | StopOK | 网络 1 之后的 Run | ET (ms) | DelayDone | 输出映像 | 物理输出 |
| ----- | ----- | ------ | ------------ | ------- | --------- | ---- | ---- |
| 0：初始化 | 0     | 1      | 0            | 0       | 0         | 0    | 0    |
| 1     | 1     | 1      | 1            | 0       | 0         | 0    | 0    |
| 2     | 0     | 1      | 1            | 10      | 0         | 0    | 0    |
| 3     | 0     | 1      | 1            | 20      | 0         | 0    | 0    |
| 4     | 0     | 1      | 1            | 30      | 1         | 1    | 0    |
| 5     | 0     | 1      | 1            | 30      | 1         | 1    | 1    |
| 6     | 0     | 1      | 1            | 30      | 1         | 1    | 1    |
| 7     | 0     | 0      | 0            | 0       | 0         | 0    | 1    |
| 8     | 0     | 1      | 0            | 0       | 0         | 0    | 0    |

扫描 2 时 `Start` 已经是假，但 `Run` 保持住了。扫描 4，指令映像变真，端子到扫描 5 才跟上。扫描 7，程序已经响应了停止，但端子还带着扫描开始时传送出去的那份映像；到扫描 8 它才变假。真实的输出模块和执行机构还会再加延迟，**这张表不计算机器停止时间。**

## 原文的实验台：四件要盯的东西

原文配了一个可逐步回放的实验台，默认参数是：扫描间隔 10 ms、接通延时预设 30 ms、第一次停止发生在扫描 7、停止保持 1 个扫描、启动在扫描 1 之后松开（只给一个扫描的脉冲）。它按初始化的内存把十个扫描全算一遍，**不是往运行中的 PLC 注入实时输入**；理想固定间隔是指定的，不是对 CPU 性能的预测。

实验台有两张曲线、四条说明，值得原样保留：

- **01 · Run 存储器与输出状态**：蓝线是网络 1 之后的 `Run`；粉色虚线是网络 3 之后输出映像里的 `MotorCmd`；绿色是在本扫描开始时传送之后的理想输出端子。**一个扫描的差，就是所选映像更新约定的一部分。**
- **02 · TON 调用报告的已过时间**：第一次为真的调用报 0，之后的调用把时钟已过时间和 PT 比较，`IN` 为假的那次扫描复位定时器。阶梯状的轨迹画的是**调用时报告的值**，不是只按扫描数推进的时钟。

四句话总结这段：

1. **用扫描 1、2、4、5、7、8 看。**启动在扫描 1 之后松开，但自锁分支保住了 `Run`；映像在扫描 4 变真、端子在 5；停止在扫描 7 清映像，端子在 8 跟随。
2. **在这套逻辑里停止优先。**`StopOK` 在 `Start`/`Run` 并联分支的外面。它为假时，启动和保持两条路径同时被封；普通 `Run` 线圈写入假，无条件的 TON 调用复位 `ET` 和 `Q`。
3. **按住不放的启动按钮可以再启动。**第四个预设里，停止在扫描 3 清掉 `Run`；扫描 4 `StopOK` 回来时 `Start` 还按着，于是 `Run` 再次置位、定时器从零重来。**要求"必须重新按一次"的话，需要额外的状态和一个明确定义的重启策略。**
4. **模型的选择要说出来。**它按 Siemens V20 帮助里 S7-1200 的默认循环过程映像顺序：输出传送、输入采集、程序执行；忽略网络执行时间；不含直接读外设、中断任务、网络 I/O 调度和模块时延。它不是一个通用 PLC 仿真器，也不是安全功能。

## 测的是转换，不只是稳态

先写预测轨迹，再拿所选程序与模拟器去对照。有用的测试都作用在**存储状态发生变化**的时刻：

| 测试            | 在这个例子里的预期                | 它能暴露的故障               |
| ------------- | ------------------------ | --------------------- |
| 启动只给一个扫描，然后松手 | Run 保持为真直到停止             | 自锁分支缺失或接错             |
| 启动与停止在同一扫描被采样 | Run 保持为假                 | 停止被放到了分支可以绕过的位置       |
| 超时前停止         | ET 与 DelayDone 复位；输出从不使能 | 定时器没有用假输入被调用，或用的是过期结果 |
| 超时后停止         | 映像立刻清；端子在下次传送时跟随         | 把映像状态与端子状态混为一谈        |
| 松手的状态下松开停止    | Run 保持为假                 | 出现意料之外的保持或另处置位        |
| 按住启动时松开停止     | Run 再次置位，计时重新开始          | 假设自锁必然要求重新按一次按钮       |

最后一条行为在这段小布尔程序里是**有意为之**，在真实机器上可能不可接受。如果需求是"必须有一次明确的新启动动作"，那就加一个明确定义的边沿/复位重臂（rearm）或重启许可设计，并且测它。**仅仅把按钮叫"点动"，并不能阻止它被按住或卡住。**

启动测试是另一件事：配置并验证哪些变量保持值、哪些被初始化、输出的替代状态是什么、有哪些启动逻辑会执行。原文的实验台永远从它声明的零状态开始，**它不主张热重启、恢复供电或下载项目会让真实 PLC 的每个变量按同样方式复位。**

## 工程意义

梯形图是一份**可执行的状态转换规格**。一段读得懂的程序，把输入极性、竞争请求的优先级、每个状态位的归属、每次观测的时机都写明。这样别人才可能在看在线监视之前先预测出这次变化。

它同时给故障定位：如果输入映像从来没有记录到一个脉冲，改自锁表达式也救不回一个任务从未观测到的事件（原文另有[丢脉冲案例](https://atlasofengineering.com/automation-and-control-engineering/plc-scan-time-missed-pulse-case-study/?ref=hubwiz.com)，讲输入滤波、采集与任务时序）。如果映像里的指令是对的、执行机构却不响应，那该查输出传送、硬件和物理过程，而不是先怀疑这段梯级写错了。

最后一句边界：**逻辑上的停止优先不是一项安全主张。**普通程序不评估容错、诊断覆盖率、独立停机路径和物理停止包络。那些属于另行设计的安全功能，对应的是另一种证据边界（原文的[安全联锁定期试验](https://atlasofengineering.com/automation-and-control-engineering/safety-interlock-proof-testing-project/?ref=hubwiz.com)讲的是这条线）。

## 附答案的小练习

- **物理按钮是常闭的，为什么程序里用逻辑常开的 `StopOK`？**因为 `StopOK` 为 1 才表示允许运行。指令测的是采样到的位，不是开关的构造。
- **调用间隔 5 ms、PT = 25 ms，扫描 1 启动后映像第一次在哪扫描使能？**扫描 1 + 25/5 = 6，前提是 `Run` 保持为真。按所选更新约定，端子在扫描 7 跟随。
- **非保持型 TON 在停止 20 ms 后还记得吗？**不记得：`IN` 为假的那次调用复位 `ET` 与 `Q`，新的一次 `Run` 从零开始计时。
- **扫描 3 出现一个扫描的停止，而 `Start` 一直被按住，会怎样？**`Run` 在 3 清零、在 4 重新置位，`ET = 0`。在默认的 30 ms / 10 ms 例子里，映像在 7 重新使能、端子在 8 跟随。**这套逻辑并不要求一个新的启动边沿。**

## 把这段逻辑放进真实的博途工程

上面所有结论都建立在一个前提上：**你手上那段程序的执行顺序、映像更新边界、变量极性，和你以为的一致。**原文的实验台是纸面推演；要落到自己工程里，缺的正是"把纸面的东西和工程里实际的东西对齐"这一步——而这恰好是 TIA Portal 工程各自不同的地方：同一个网络在别人电脑上可能是三个 FC 拼起来、可能挂在循环中断里、`Run` 也可能是个 DB 里的静态位而不是 M 位。

[**TiaLink**](https://tia.hubwiz.com/tia-link?ref=hubwiz.com) 就是补这一段的：它通过 TIA Portal Openness 驱动**你本机已经打开的**博途工程，读块、读变量、读硬件组态、编译，并在 PLCSIM Advanced 里跑。按下面五步走，纸面模型就变成有证据的判断：

**第一步，先只读，把差异找出来。**把这三个网络对应的块读出来，对照原文的假设逐项核对：`Run` 是 M 位还是 DB 静态位？`TON0` 是不是每扫描都被调用（有没有被包在条件里）？网络执行顺序和图纸一致吗？这一步用只读方式做，不改工程。想先看"这段梯形图到底长什么样"，[LAD 在线查看](https://tia.hubwiz.com/lad-viewer?ref=hubwiz.com)可以在浏览器里打开块，不必开博途。

**第二步，改之前先看覆盖范围。**要改的标签、要动的网络，先跑一次预览，让工具把"会写入哪些对象"列出来。默认规则是**不覆盖同名对象、不自动保存**——这两条是防止一次 AI 生成把别人上周的修改抹掉。

**第三步，编译只算第一层证据。**编译能证明语法、类型、块引用是对的；它不检查逻辑是否正确，也不检查某个标签是否真的接到了物理通道上。这一步过了就往下走，别停在"0 错误"。

**第四步，在仿真里跑那六个转换测试。**把上面那张表里的六种情形依次灌进去，重点看两个状态：**输出映像**和**物理输出（端子）**在一个扫描里的差。这正是原文整篇在讲的东西——只有把它们分开看，"程序说停了、端子还亮着"才不是一句传说，而是一个可以被复现的时间点。仿真环境用 PLCSIM Advanced，TiaLink 负责启动、下载、按变量表读写。

**第五步，现场之前留回滚点。**改完的逻辑要在真实 CPU 上验证，就先备份当前工程、记下版本与日期，再下载；验证时至少两个人看同一份证据（一个盯映像、一个盯现场）。**任何 F 程序、任何来源不明的块，都不要走这条自动化路径。**

**要做到哪一步、什么时候该停手**，也写清楚：只读查看和一致性核对可以全自动；生成候选代码、改现有块，需要人看 diff 再确认；下载到真实 CPU、切换运行模式、改安全相关逻辑，必须人做决定。这三级的分界线，比工具本身重要。

## 来源

- 原文：[Reading and Testing PLC Ladder Logic](https://atlasofengineering.com/automation-and-control-engineering/reading-and-testing-plc-ladder-logic/?ref=hubwiz.com)（Atlas of Engineering，Automation and Control Engineering 分区）
- 指令语义与扫描周期：[Siemens S7-1200 系统手册 · 位逻辑指令](https://docs.tia.siemens.cloud/r/simatic%5Fs7%5F1200%5Fmanual%5Fcollection%5Fenus%5F20/basic-instructions/bit-logic-operations/bit-logic-instructions?ref=hubwiz.com)、[RUN 模式下扫描周期的处理](https://docs.tia.siemens.cloud/r/simatic%5Fs7%5F1200%5Fmanual%5Fcollection%5Fenus%5F20/plc-concepts/execution-of-the-user-program/processing-the-scan-cycle-in-run-mode?ref=hubwiz.com)、[TON 生成接通延时](https://docs.tia.siemens.cloud/r/en-us/v20/lad-s7-1200-s7-1500/timer-operations-s7-1200-s7-1500/ton-generate-on-delay-s7-1200-s7-1500?ref=hubwiz.com)
- 原文延伸阅读：[丢脉冲案例](https://atlasofengineering.com/automation-and-control-engineering/plc-scan-time-missed-pulse-case-study/?ref=hubwiz.com)、[安全联锁定期试验](https://atlasofengineering.com/automation-and-control-engineering/safety-interlock-proof-testing-project/?ref=hubwiz.com)

## 编者补充

原文只给了纸面推演，没回答"我这段程序到底属于哪种更新边界"。补一张速查表，按它在工程里对一遍，比通读手册快：

| 你要确认的       | 在哪里看                     | 不一致会怎样                 |
| ----------- | ------------------------ | ---------------------- |
| 映像更新边界      | CPU 属性里的循环/过程映像设置        | 端子跟随的扫描数会比原文多或少        |
| 网络执行顺序      | 块内网络编号与调用链（OB → FB → FC） | 同一扫描里读到"上一轮"或"这一轮"的值全变 |
| 定时器是否每扫描都调用 | 包住 TON 的那层条件             | 跳过调用 ≠ 输入为假，计时可能不复位    |
| Run 的存储位置   | M 位 / DB 静态位 / 临时变量      | 临时变量跨扫描不保持，自锁直接失效      |
| 是否挂在循环中断    | OB 编号与循环时间               | 上面的"每扫描一次"根本不成立        |

两条边界：其一，原文那个模拟器**是教学模型**，它自己就写明不含直接读外设、中断任务、网络 I/O 调度和模块时延，别拿它的数字当性能预测。其二，这篇里的所有时序结论都依赖"输出传送→输入采集→程序执行"这个默认顺序；换成别的控制器或改成立即读外设，重新推一遍再下结论。

本文由 汇智网 · Software 2.0 编译整理，转载请注明出处。

> **这是「AI × 工业 / PLC」专题的一部分。**完整地图见：[AI × 工业 / PLC 完全指南](https://www.hubwiz.com/blog/ai-industrial-stack/)