ST(Structured Text)是IEC 61131-3标准中定义的高级文本编程语言,广泛应用于PLC(可编程逻辑控制器)的电气自动化工程。在循环控制结构中,REPEAT...UNTIL 和 WHILE 是两种基础且高频使用的语句,但它们的执行顺序本质不同——这一差异直接决定程序行为是否符合安全逻辑、是否遗漏首次判断、是否陷入死循环。本文不讲概念复述,只聚焦实操:用纯文字还原真实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:
bStart = FALSE→ 条件为FALSE→ 跳过整个循环体 →iCounter仍为0。 - 周期2:操作员按下启动按钮,
bStart变为TRUE→ 条件为TRUE→ 执行循环体:
iCounter := 0 + 1→iCounter = 1;
1 >= 5为FALSE→ 不修改bStart。 - 周期3:
bStart = TRUE→ 条件为TRUE→ 执行循环体:
iCounter := 1 + 1→iCounter = 2。 - 周期4:
iCounter = 2→ 执行后iCounter = 3。 - 周期5:
iCounter = 3→ 执行后iCounter = 4。 - 周期6:
iCounter = 4→ 执行后iCounter = 5→5 >= 5为TRUE→bStart := FALSE。 - 周期7:
bStart = FALSE→ 条件为FALSE→ 跳过循环体 → 循环终止。
✅ 结论:iCounter 从 0 到 5,共执行5次循环体,符合预期。
场景2:用 REPEAT...UNTIL 实现完全相同的逻辑
REPEAT
iCounter := iCounter + 1;
IF iCounter >= 5 THEN
bStart := FALSE;
END_IF;
UNTIL bStart = FALSE;
执行过程:
- 周期1:
bStart = FALSE→ 但仍无条件执行一次循环体:
iCounter := 0 + 1→iCounter = 1;
1 >= 5为FALSE→bStart不变(仍为FALSE);
计算UNTIL条件:bStart = FALSE→TRUE→ 退出循环。 - 周期2:
iCounter = 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 天然支持多条件组合,可同时监控信号与计时器;REPEAT 的 UNTIL 仅支持单退出条件,超时逻辑需额外变量控制,易出错。 |
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步定位循环逻辑错误
当设备出现“启动延迟”、“误动作一次”、“卡在循环不出”等问题,按此流程排查:
-
查扫描周期日志:在TIA Portal或Codesys中启用“循环时间监视”,确认该段代码是否被编译进主任务(Task OB1),并记录其单次执行耗时。若耗时 > 1ms 且含
WAIT(),需评估是否阻塞其他高优先级任务。 -
打点验证执行次数:在循环体首尾插入临时计数器:
// 在循环前 iWhileCnt := 0; iRepeatCnt := 0; // WHILE 循环内第一行 iWhileCnt := iWhileCnt + 1; // REPEAT 循环内第一行 iRepeatCnt := iRepeatCnt + 1;在HMI上实时显示
iWhileCnt和iRepeatCnt。若iRepeatCnt在条件未满足时已 > 0,证明REPEAT被误触发。 -
条件信号源追踪:右键点击条件变量(如
bStart)→ “交叉引用” → 查看所有写入位置。重点检查是否存在隐式赋值(如FB块内部修改、结构体成员间接赋值、网络变量同步覆盖)。90% 的“条件始终为FALSE”问题源于信号源未正确连接或初始化。
六、终极选择口诀(现场工程师速记)
等信号,用
WHILE—— 信号不来,我就不动;
要动作,用REPEAT—— 先干再说,干完再问;
安全线,只信WHILE—— 急停之前,绝不迈步;
初始化,必选REPEAT—— 上电第一秒,必须动手。
此口诀覆盖95% 工业现场循环选型场景,无需查手册,开口即答。

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