案例需求回顾
沿用与 FOR 循环实战完全相同的测试场景:
- 一维数组:数组0..10,数据类型为WordSigned(有符号 16 位整型),共 11 个元素;
- 目标:遍历数组全部元素,自动提取数组的最大值与最小值;
- 测试数据:复用之前的验证用例,确保两种循环结构的输出结果一致性。
全局标签配置:

完整 ST 源代码
// 1. 最值基准初始化:必须以数组真实元素为初始值,适配全负数/全正数场景
最大值 := 数组[0];
最小值 := 数组[0];
// 2. WHILE循环变量初始化:从数组起始下标0开始遍历
循环索引 := 0;
// 3. WHILE循环主体:遍历条件为"下标未超过数组最大边界10"
WHILE 循环索引 <= 10 DO
// 4. 更新最大值:当前元素大于暂存最大值时,刷新暂存值
IF 数组[循环索引] > 最大值 THEN
最大值 := 数组[循环索引];
END_IF;
// 5. 【修复】更新最小值:修正赋值变量,将较小值存入最小值寄存器
IF 数组[循环索引] < 最小值 THEN
最小值 := 数组[循环索引];
END_IF;
// 6. 循环变量手动自增:移动变址指针,向循环终止条件靠近
循环索引 := 循环索引 + 1;
END_WHILE;
// 7. 遍历完成后重置索引:便于后续复用该变量,避免其他逻辑受影响
循环索引 := 0;
二、WHILE循环的基本语法
在三菱ST语言中,WHILE循环的语法格式如下:
WHILE <布尔表达式> DO
<执行语句>;
END_WHILE;
它的执行逻辑是:
- 先判断
<布尔表达式>是否为TRUE - 如果为
TRUE,执行DO和END_WHILE之间的语句 - 执行完后,再次回到第1步判断条件
- 如果为
FALSE,直接跳过循环体,执行END_WHILE后面的代码
简单来说就是:条件为真就一直循环,条件为假就退出。
与FOR循环的区别
| 特性 | FOR循环 | WHILE循环 |
|---|---|---|
| 适用场景 | 循环次数已知 | 循环次数未知,依赖条件判断 |
| 循环控制 | 由循环变量自动控制 | 需要手动更新循环条件 |
| 典型用途 | 遍历固定长度的数组 | 等待某个条件成立、持续监控状态 |
对于遍历数组 这种循环次数固定的场景,其实FOR循环更常用。但WHILE循环的优势在于灵活性 ------当循环次数不固定时(比如"一直累加直到超过某个值"),WHILE是更好的选择。
三、代码逐行解析
1. 初始化
最大值 := 数组[1];
最小值 := 数组[1];
index1 := 2;
在开始比较之前,先把第一个元素 同时赋给最大值和最小值作为初始值。然后从第2个元素开始逐一比较。
💡 为什么不把最大值设为0、最小值设为9999?
因为数组元素可能是负数。如果用0作为初始最大值,当所有元素都是负数时,最大值就会错误地变成0。用数组的第一个元素作为初始值是最安全的方式。
2. WHILE循环条件
WHILE index1 <= 10 DO
只要index1小于等于10,循环就继续执行。当index1变成11时,条件为FALSE,循环退出。
3. 比较与更新
IF 最大值 < 数组[index1] THEN
最大值 := 数组[index1];
END_IF;
IF 最小值 > 数组[index1] THEN
最小值 := 数组[index1];
END_IF;
- 找最大值 :如果当前元素比
最大值还大,就更新最大值 - 找最小值 :如果当前元素比
最小值还小,就更新最小值
两个IF语句是独立的,可以同时执行。比如当前元素既是目前最大的又是最小的(数组中只有一个元素时),两个条件可能同时成立。
4. 循环变量递增
index1 := index1 + 1;
这是最关键的一步! 如果没有这行代码,index1永远等于2,条件index1 <= 10永远为TRUE,循环将永远不会结束 ,最终导致看门狗超时,PLC报错停机。
四、WHILE循环的核心注意事项
⚠️ 注意1:必须确保循环能退出(防止死循环)
WHILE循环的退出完全依赖于条件表达式变为FALSE。如果条件永远为TRUE,循环就会无限执行,直到PLC的看门狗超时报警。
常见的死循环陷阱:
- 忘记在循环体内更新循环变量
- 循环变量的更新方向错误(比如应该递增却写成了递减)
- 条件表达式使用了不会改变的外部变量
⚠️ 注意2:循环在一个扫描周期内完成
三菱PLC的WHILE循环是在一个扫描周期内完成的。也就是说,循环体执行多少次,这个扫描周期就会延长多少时间。
如果循环次数过多(比如上万次),可能会导致扫描周期超长,触发看门狗故障。因此:
- 循环次数不宜过多
- 如果确实需要大量循环,考虑在循环体内适当位置复位看门狗定时器 (通过
WDT指令)
⚠️ 注意3:语法细节------DO后面不加分号
在三菱GX Works2/GX Works3的ST语言中,WHILE语句的DO关键字后面不加分号:
WHILE index1 <= 10 DO // ✅ 正确,DO后面没有分号
...
END_WHILE;
WHILE index1 <= 10 DO; // ❌ 错误,DO后面加了分号会导致语法错误
...
END_WHILE;
这与C语言等编程语言的语法不同,初学者容易踩坑。
⚠️ 注意4:循环结束后变量的值
与FOR循环类似,三菱PLC中WHILE循环结束后,循环变量(如index1)不会自动重置 ,而是保持循环结束时的最终值。在上述代码中,循环结束后index1的值是11。
五、代码扩展与优化
扩展1:使用FOR循环实现(更简洁)
对于遍历数组这种固定次数的场景,FOR循环更加简洁:
最大值 := 数组[1];
最小值 := 数组[1];
FOR index1 := 2 TO 10 BY 1 DO
IF 最大值 < 数组[index1] THEN
最大值 := 数组[index1];
END_IF;
IF 最小值 > 数组[index1] THEN
最小值 := 数组[index1];
END_IF;
END_FOR;
FOR循环自动管理循环变量的递增,不需要手动写index1 := index1 + 1,代码更简洁,也从根本上避免了忘记递增导致的死循环。
扩展2:使用EXIT提前退出循环
如果数组元素较多,而我们已经找到了想要的结果,可以用EXIT提前退出循环:
WHILE index1 <= 10 DO
// 如果找到了目标值,提前退出
IF 数组[index1] = 目标值 THEN
EXIT;
END_IF;
index1 := index1 + 1;
END_WHILE;
扩展3:动态数组长度
如果数组长度不是固定的,可以用LOWER_BOUND和UPPER_BOUND函数获取数组的边界:
index1 := LOWER_BOUND(数组, 1); // 获取第1维的下界
WHILE index1 <= UPPER_BOUND(数组, 1) DO // 获取第1维的上界
// 处理逻辑
index1 := index1 + 1;
END_WHILE;
这样即使数组长度发生变化,代码也不需要修改。
六、总结
| 要点 | 说明 |
|---|---|
| 语法格式 | WHILE <条件> DO <语句>; END_WHILE; |
| 执行逻辑 | 条件为TRUE时执行循环体,为FALSE时退出 |
| 适用场景 | 循环次数未知,依赖条件判断 |
| 最大风险 | 忘记更新循环变量导致死循环 |
| 语法陷阱 | DO后面不加分号 |
| 扫描周期 | 循环在一个扫描周期内完成,次数过多会触发看门狗 |
WHILE循环是三菱ST语言中非常灵活的循环控制语句,特别适合循环次数不确定 的场景。但使用时一定要谨慎,确保循环条件最终会变为FALSE,否则就会触发PLC的看门狗报警和停机。