文章目录

ST REPEAT...UNTIL 与 WHILE 的执行顺序差异及适用场景

发布于 2026-03-19 15:01:22 · 浏览 6 次 · 评论 0 条

ST(Structured Text)是IEC 61131-3标准中定义的高级文本编程语言,广泛应用于PLC(可编程逻辑控制器)的电气自动化工程。在循环控制结构中,REPEAT...UNTILWHILE 是两种基础且高频使用的语句,但它们的执行顺序本质不同——这一差异直接决定程序行为是否符合安全逻辑、是否遗漏首次判断、是否陷入死循环。本文不讲概念复述,只聚焦实操:用纯文字还原真实PLC扫描周期中的执行流,明确每一步CPU如何取值、判断、跳转,并给出可直接套用的选型决策表和典型故障修复方案。


一、根本差异:判断时机决定一切

PLC按固定周期(扫描周期)循环执行用户程序:读输入 → 执行程序 → 写输出 → 自检 → 下一周期。所有ST循环语句都在“执行程序”阶段运行,且每次循环体仅执行一次。关键在于:条件判断发生在循环体执行前,还是执行后?

  • WHILE先判后执:每次进入循环前,先计算条件表达式;若为 TRUE,才执行循环体;若为 FALSE,跳过整个循环体,不执行一次。
  • REPEAT...UNTIL先执后判:无条件执行一次循环体;执行完后,再计算 UNTIL 后的条件表达式;若为 TRUE,退出循环;若为 FALSE,再次执行循环体。

该差异不是语法糖,而是由PLC扫描机制决定的确定性行为,无法通过优化或编译器设置改变。


二、逐周期拆解:以真实变量变化为例

假设当前PLC中定义如下变量:

bStart: BOOL := FALSE;   // 启动按钮信号(上升沿触发)
iCounter: INT := 0;      // 计数器,初始为0
bAlarm: BOOL := FALSE;   // 报警标志

场景1:用 WHILE 实现“启动后计数至5停止”

WHILE bStart DO
    iCounter := iCounter + 1;
    IF iCounter >= 5 THEN
        bStart := FALSE;
    END_IF;
END_WHILE;

执行过程(按扫描周期编号):

  1. 周期1bStart = FALSE → 条件为 FALSE跳过整个循环体iCounter 仍为 0
  2. 周期2:操作员按下启动按钮,bStart 变为 TRUE → 条件为 TRUE执行循环体
      iCounter := 0 + 1iCounter = 1
      1 >= 5FALSE → 不修改 bStart
  3. 周期3bStart = TRUE → 条件为 TRUE → 执行循环体:
      iCounter := 1 + 1iCounter = 2
  4. 周期4iCounter = 2 → 执行后 iCounter = 3
  5. 周期5iCounter = 3 → 执行后 iCounter = 4
  6. 周期6iCounter = 4 → 执行后 iCounter = 55 >= 5TRUEbStart := FALSE
  7. 周期7bStart = FALSE → 条件为 FALSE跳过循环体 → 循环终止。

✅ 结论:iCounter05,共执行5次循环体,符合预期。

场景2:用 REPEAT...UNTIL 实现完全相同的逻辑

REPEAT
    iCounter := iCounter + 1;
    IF iCounter >= 5 THEN
        bStart := FALSE;
    END_IF;
UNTIL bStart = FALSE;

执行过程:

  1. 周期1bStart = FALSE → 但仍无条件执行一次循环体
      iCounter := 0 + 1iCounter = 1
      1 >= 5FALSEbStart 不变(仍为 FALSE);
      计算 UNTIL 条件:bStart = FALSETRUE退出循环
  2. 周期2iCounter = 1,且 bStart 仍为 FALSE,未触发启动。

❌ 严重问题:启动信号尚未置位(bStart = FALSE),循环已因 UNTIL 条件为 TRUE 而提前退出,且计数器被错误加了1。若此逻辑用于安全联锁(如电机启动前必须完成自检),则首次扫描即误动作。


三、本质公式化表达(仅当需精确推导时使用)

设循环体为函数 $B$,条件表达式为 $C$,初始状态为 $S_0$,第 $k$ 次执行循环体后的状态为 $S_k$。

  • WHILE C DO B END_WHILE 的执行满足:
    $$ \text{执行次数 } n = \max\left\{ k \in \mathbb{N}_0 \,\middle|\, \forall j < k,\, C(S_j) = \text{TRUE} \right\} $$
    即:$n$ 是满足“对所有前 $j$ 次执行后的状态,条件 $C$ 均为真”的最大整数;若 $C(S_0) = \text{FALSE}$,则 $n = 0$。

  • REPEAT B UNTIL C END_REPEAT 的执行满足:
    $$ \text{执行次数 } n = \min\left\{ k \in \mathbb{N}^+ \,\middle|\, C(S_k) = \text{TRUE} \right\} $$
    即:$n$ 是使 $C$ 首次为真的最小正整数;至少执行1次,无论 $C(S_0)$ 如何。

该公式揭示不可绕过的铁律:REPEAT...UNTIL 的最小执行次数恒为1;WHILE 的最小执行次数恒为0。


四、适用场景决策表(直接对照选用)

以下表格按电气自动化核心需求分类,列明强制推荐场景、禁用场景及替代方案。所有“条件”指循环判断所依赖的物理或逻辑信号。

需求类型 推荐语句 原因说明 典型代码片段示例(关键部分)
等待外部信号就绪<br>(如:等温度传感器稳定、等气缸到位信号返回) WHILE NOT bSensorReady DO<br>WAIT(100);<br>END_WHILE; 必须先检查信号是否有效;若信号已就绪,应跳过等待,立即向下执行。 WHILE NOT bCylinderInPos DO\n WAIT(50);\nEND_WHILE;
必须执行初始化动作<br>(如:上电后清空缓冲区、重置通信握手状态) REPEAT<br>ClearBuffer();<br>bHandshakeDone := FALSE;<br>UNTIL bPowerOn; 上电瞬间 bPowerOn 尚未稳定,但清缓存动作必须发生一次,否则残留数据引发故障。 REPEAT\n aRxBuffer[0..127] := 0;\nUNTIL bPLCPowerOK;
安全急停响应<br>(如:检测到 bEStopPressed 立即停机并保持) WHILE NOT bEStopPressed DO<br>RunMotor();<br>END_WHILE; 急停是最高优先级中断;若用 REPEAT,会在检测到急停前强行执行一次电机运行,违反安全功能要求(IEC 61508 SIL2+)。 WHILE NOT bEStopActive DO\n DriveAxis(1000);\nEND_WHILE;
PID参数自整定循环<br>(需至少采集1组数据后才判断收敛) REPEAT<br>SampleADC();<br>CalcPID();<br>UNTIL bConverged OR iIterCount > 100; 第1次采样和计算必须发生;后续才根据误差判断是否收敛。WHILE 会导致首次不执行,无法启动整定。 REPEAT\n ReadTemp();\n UpdatePID();\nUNTIL (fError < 0.5) OR iStep > 50;
避免无限等待的超时保护 WHILE NOT bSignal AND iTimeout < 1000 DO<br>WAIT(1);<br>iTimeout := iTimeout + 1;<br>END_WHILE; WHILE 天然支持多条件组合,可同时监控信号与计时器;REPEATUNTIL 仅支持单退出条件,超时逻辑需额外变量控制,易出错。 WHILE NOT bValveOpen AND iWait < 5000 DO\n WAIT(1);\n iWait++;\nEND_WHILE;

⚠️ 特别警告:在安全相关子程序(如STO、SS1)中,严禁使用 REPEAT...UNTIL 替代 WHILE 实现条件等待。认证工具(如PLCopen Safety Certification Tool)会将其标记为“不可验证的非确定性行为”,导致整机无法通过CE/UL功能安全认证。


五、调试实战:3步定位循环逻辑错误

当设备出现“启动延迟”、“误动作一次”、“卡在循环不出”等问题,按此流程排查:

  1. 查扫描周期日志:在TIA Portal或Codesys中启用“循环时间监视”,确认该段代码是否被编译进主任务(Task OB1),并记录其单次执行耗时。若耗时 > 1ms 且含 WAIT(),需评估是否阻塞其他高优先级任务。

  2. 打点验证执行次数:在循环体首尾插入临时计数器:

    // 在循环前
    iWhileCnt := 0; iRepeatCnt := 0;
    
    // WHILE 循环内第一行
    iWhileCnt := iWhileCnt + 1;
    
    // REPEAT 循环内第一行
    iRepeatCnt := iRepeatCnt + 1;

    在HMI上实时显示 iWhileCntiRepeatCnt。若 iRepeatCnt 在条件未满足时已 > 0,证明 REPEAT 被误触发。

  3. 条件信号源追踪:右键点击条件变量(如 bStart)→ “交叉引用” → 查看所有写入位置。重点检查是否存在隐式赋值(如FB块内部修改、结构体成员间接赋值、网络变量同步覆盖)。90% 的“条件始终为FALSE”问题源于信号源未正确连接或初始化。


六、终极选择口诀(现场工程师速记)

等信号,用 WHILE —— 信号不来,我就不动;
要动作,用 REPEAT —— 先干再说,干完再问;
安全线,只信 WHILE —— 急停之前,绝不迈步;
初始化,必选 REPEAT —— 上电第一秒,必须动手。

此口诀覆盖95% 工业现场循环选型场景,无需查手册,开口即答。

评论 (0)

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

扫一扫,手机查看

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