返回
SCL PLC 编程教程第五篇 循环语句:FOR、WHILE、REPEAT 在 PLC 里到底怎么用,哪些场景最有价值
前面几篇,我们已经把 SCL 的基础地基搭起来了:
第一篇讲了 SCL 是什么,它适合做什么。
第二篇认识了编程界面和最基础的程序结构。
第三篇把变量、数据类型、地址概念理清了。
第四篇又把 IF、ELSIF、ELSE、CASE 这些条件判断讲透了。
到了这里,很多人会开始有一个新需求:
有些逻辑,不是只对一个变量做一次判断,而是要对一整组数据反复处理。
比如:
一次性清除 50 个报警位
批量初始化一组参数
遍历 20 个传感器状态
检查数组里有没有异常值
统计一批信号中有几个成立
求一组采样值的平均值
在一串数据里查找某个目标
这时候,如果你还完全用一条一条赋值、一条一条判断的方式来写,当然也能写,但会越来越笨重。
于是,循环就派上用场了。
所以你可以先把循环理解成一句非常实在的话:
循环,就是让程序按你设定的规则,把同一类处理重复执行多次。
听起来很简单,但它的价值非常大。
尤其在 SCL 里,循环是让程序从“单点判断”走向“批量处理”的一个关键台阶。
一、先把最重要的一句话记住:PLC 里的循环,不是拿来“等时间过去”的
这一点必须先讲,而且要讲得非常明确。
很多刚学循环的人,会不自觉地把编程里的循环理解成:
“让程序一直反复执行,直到过一会儿再继续。”
这种理解在一些普通软件编程场景里,可能还勉强能联想到某些等待机制。
但在 PLC 里,如果你用这种思路理解循环,很容易出事。
在 PLC 程序中,尤其是在主扫描逻辑里,循环最常见的本质是:
在一次扫描周期内,快速地把一批重复处理做完。
也就是说,FOR、WHILE、REPEAT 通常都不是“拖时间”的工具。
它们更像是“批量处理工具”。
比如你写:
FOR i := 1 TO 10 DO
Alarm[i] := FALSE;
END_FOR;
这不是说 PLC 会一个周期清一个报警,清十个周期。
而是说:在这一次程序执行中,它很快就把 1 到 10 号报警位都处理完了。
所以你一定要把这个观念刻进脑子里:
PLC 里的循环,主要是为了批量处理数据,不是为了做延时。
延时要用定时器、时间逻辑、状态机,不要拿循环硬等。
这点后面我还会反复提醒,因为这是循环部分最容易踩的大坑之一。
二、为什么 PLC 工程师需要学循环
有些人会问:
“我平时写梯形图也没怎么用循环,项目不也做了吗?”
这话没错。
不是所有 PLC 项目都必须大量使用循环。
但一旦你遇到下面这些场景,循环会明显提高程序的条理性和效率。
1. 处理成组数据时更自然
例如:
32 路报警位
16 路输入状态
20 个温度点
一组配方参数
一段历史缓存区
如果你逐条写:
Alarm[1] := FALSE;
Alarm[2] := FALSE;
Alarm[3] := FALSE;
...
Alarm[32] := FALSE;
当然可以,但很笨重,也不利于修改。
如果用循环,逻辑马上就收紧了。
2. 更适合写“规则一致”的逻辑
例如你要检查 20 个模拟量中有没有超限值。
每一路判断规则都一样:只要大于上限就报警。
这时候,循环就特别合适。
3. 更容易和数组、结构化数据配合
SCL 一旦进入数组、数据表、批量参数处理的阶段,循环几乎是天然搭档。
不学循环,你后面很多内容会写得很别扭。
4. 代码更紧凑,维护成本更低
不是说代码越少越高级,而是同一类重复处理,应该尽量写得更有结构。
循环在这方面非常有价值。
所以从工程成长角度看,循环不是“可有可无的高级技巧”,而是你进入批量数据处理、模块化处理之后很重要的能力。
三、SCL 里常见的三类循环
SCL 中最常见的循环结构主要有三类:
FOR
WHILE
REPEAT
它们都能实现“重复执行”,但适合的场景不完全一样。
你可以先粗略这样理解:
FOR
适合已知重复次数的场景。
例如:
从 1 到 10 依次处理
遍历数组 1 到 20
清零某一段固定长度数据
统计一组固定数量的信号
WHILE
适合在某个条件成立时一直继续执行的场景。
例如:
当索引还没到边界时继续找
当还没找到目标且还在有效范围内时继续扫描
但要特别小心,WHILE 如果条件控制不好,很容易出现死循环风险。
REPEAT
适合先执行一次,再判断是否继续的场景。
它和 WHILE 的差别在于:
WHILE 是先判断,再执行;
REPEAT 是先执行,再判断。
在 PLC 项目里,REPEAT 没有 FOR 那么常用,但在某些“至少执行一次”的逻辑里也有价值。
四、FOR 循环是什么,为什么它最适合 PLC 初学者先掌握
如果说三类循环里,哪一种最值得 PLC 工程师优先吃透,那通常就是 FOR。
因为它最直观、最安全、工程上也最常用。
FOR 的核心思路非常简单:
让某个计数变量按设定范围一步一步变化,并在每一步执行相同逻辑。
最基础的写法是:
FOR i := 起始值 TO 结束值 DO
语句;
END_FOR;
例如:
FOR i := 1 TO 10 DO
Alarm[i] := FALSE;
END_FOR;
这段代码的意思是:
让 i 从 1 变化到 10;
每变化一次,就把对应的 Alarm[i] 清零。
你可以把 FOR 理解成一个“自动编号器”。
程序不用你一个一个写 1、2、3、4,而是自动按范围帮你跑一遍。
这就是 FOR 的本质。
五、FOR 循环里最重要的角色:索引变量
FOR 循环里一定会有一个很重要的变量,通常叫:
i
j
k
Index
AlarmNo
ChannelNo
它的作用就是在每一轮循环里,表示“当前轮到第几个”。
例如:
FOR i := 1 TO 8 DO
InputOK[i] := TRUE;
END_FOR;
在这段程序里:
第一轮时 i = 1
第二轮时 i = 2
第三轮时 i = 3
一直到 i = 8
所以 InputOK[i] 实际上就会依次变成:
InputOK[1]
InputOK[2]
InputOK[3]
...
InputOK[8]
这就是为什么 FOR 特别适合数组处理。
初学者要注意一点:
这个索引变量不是随便写着玩的,它必须和你的数组范围、数据结构范围一致。
否则很容易出现越界、错位或者逻辑不对的情况。
六、FOR 在 PLC 里最典型的几个场景
1. 批量清零或初始化
这是 FOR 最基础、也最常见的用途之一。
例如系统复位时,要把 20 个报警标志全部清掉:
IF ResetPB THEN
FOR i := 1 TO 20 DO
Alarm[i] := FALSE;
END_FOR;
END_IF;
这种写法比一条一条清楚很多。
2. 批量判断
例如检查 10 路温度是否有超上限:
FOR i := 1 TO 10 DO
IF TempPV[i] > TempHighLimit[i] THEN
TempHighAlarm[i] := TRUE;
ELSE
TempHighAlarm[i] := FALSE;
END_IF;
END_FOR;
这就很像实际工程逻辑了。
你会发现,一旦规则一致,FOR 就能自然地把同类处理批量展开。
3. 统计数量
例如统计 16 路输入中,有多少路为 TRUE:
ActiveCount := 0;
FOR i := 1 TO 16 DO
IF SensorOK[i] THEN
ActiveCount := ActiveCount + 1;
END_IF;
END_FOR;
这个场景非常实用。
很多计数、统计、汇总逻辑,都可以这么做。
4. 查找第一个满足条件的位置
例如在一组产品槽位中,找第一个空位:
FirstEmptyPos := 0;
FOR i := 1 TO 12 DO
IF NOT SlotUsed[i] THEN
FirstEmptyPos := i;
END_IF;
END_FOR;
不过这里要注意,这段代码会一直扫到最后。
如果你只是想找第一个空位,后面我们还会讲更细的优化思路。
5. 求和、求平均值
例如对 8 个采样值求平均:
SumValue := 0.0;
FOR i := 1 TO 8 DO
SumValue := SumValue + SampleValue[i];
END_FOR;
AverageValue := SumValue / 8.0;
这种数据处理在模拟量、采样平滑、统计分析中都很常见。
七、FOR 虽然好用,但有两个工程问题必须警惕
第一个问题:循环次数不能无脑放大
很多人刚学会循环,会有一种冲动:
既然能循环,那我直接从 1 到 10000,甚至更多,不就行了?
理论上某些场景可能可以,
但 PLC 不是普通办公电脑程序,它的扫描周期、实时性都要考虑。
如果你在主循环里做一个非常大的 FOR,每一轮里面又有大量计算、比较、字符串处理、通信解析,那就可能带来这些后果:
扫描周期明显变长
响应变慢
程序抖动
某些动作延后
极端情况下影响设备实时性
所以 FOR 不是不能大,而是要有概念:
循环次数乘以循环体复杂度,才是真正决定负担的关键。
也就是说,不只是看你循环几次,还要看每次里面做了多重的工作。
第二个问题:不要把 FOR 当延时器
例如有人会想:
“我让 FOR 从 1 跑到 50000,不就能等一会儿了吗?”
这非常不建议。
因为:
这样做的时间并不稳定
和 PLC 性能、程序负载有关
不同设备、不同程序状态下效果都可能不一样
会浪费扫描资源
本质上是错误使用循环
真正需要延时,请用:
TON
TOF
TP
时间比较
状态机加时间条件
不要拿 FOR 做假延时。
这在工程里是一个很不好的习惯。
八、WHILE 是什么,它和 FOR 最大的区别在哪儿
WHILE 的基本思路是:
只要条件成立,就继续执行。
基础写法如下:
WHILE 条件 DO
语句;
END_WHILE;
例如思路上:
当索引还没超过上限时,就继续检查数组内容。
WHILE 和 FOR 最大的区别在于:
FOR 是“次数基本已知”
比如从 1 到 20,很明确。
WHILE 是“是否继续,由条件决定”
比如只要没找到目标且索引还在范围内,就继续。
所以 WHILE 更灵活,但也更危险。
为什么危险?
因为 FOR 至少天然有一个明确边界,而 WHILE 如果条件一直成立,就可能一直循环下去。
这就是 PLC 工程里使用 WHILE 必须格外谨慎的原因。
九、WHILE 在 PLC 里适合什么场景
虽然 WHILE 需要小心,但不是不能用。
它在某些场景下还是有价值的。
1. 条件驱动的查找
例如你想从数组头开始找某个目标,只要没找到并且索引还没越界,就继续:
i := 1;
Found := FALSE;
WHILE (i <= 20) AND (NOT Found) DO
IF ProductCode[i] = TargetCode THEN
Found := TRUE;
FoundPos := i;
ELSE
i := i + 1;
END_IF;
END_WHILE;
这个例子就很典型。
它不是固定跑满 20 次,而是满足条件就继续,不满足就停。
也就是说,如果第 3 个位置就找到了,那就可以提前结束。
这比某些“无脑从头扫到尾”的逻辑更有效率。
2. 根据变化条件逐步推进
有些逻辑不是严格已知次数,而是“只要条件成立就继续推进”,这种时候 WHILE 会比较自然。
但这种场景在 PLC 主控逻辑里没有 FOR 那么常见。
多数标准批量处理,FOR 往往已经够用了。
所以从工程习惯来说:
如果 FOR 能解决,很多时候优先考虑 FOR;
只有当“继续条件”比“固定次数”更自然时,再考虑 WHILE。
十、WHILE 最危险的地方:死循环
这必须单独讲,而且要讲得透。
所谓死循环,就是循环条件始终满足,程序一直出不来。
这在 PLC 里是非常危险的。
例如下面这种思路就有风险:
i := 1;
WHILE i <= 10 DO
Alarm[i] := FALSE;
END_WHILE;
这里的问题是:
你没有让 i 发生变化。
那程序会一直看到 i <= 10 成立,于是永远不停。
这就是典型死循环。
所以你以后写 WHILE 时,必须养成一个近乎机械的检查习惯:
第一,循环条件是什么
比如 i <= 20
第二,循环体里谁在推动条件变化
比如 i := i + 1
第三,是否一定存在退出路径
比如找到目标会退出,或者 i 增加到边界后退出
如果这三件事不清楚,WHILE 就不要轻易写。
一句很实在的话:
WHILE 最怕的,不是写复杂,而是忘了让条件走向结束。
十一、REPEAT 是什么,它和 WHILE 有什么差别
REPEAT 的核心特点是:
先执行一次,再判断要不要继续。
基础写法通常是:
REPEAT
语句;
UNTIL 条件
END_REPEAT;
这和 WHILE 的区别是:
WHILE:先判断条件,再决定要不要进循环
REPEAT:先执行循环体,再判断是否满足结束条件
所以 REPEAT 适合这种逻辑:
不管怎样,先做一轮,然后根据结果决定是否继续。
这类场景在 PLC 中不是最主流,但在某些需要“至少执行一次”的处理中会用到。
十二、REPEAT 适合哪些场景
举一个容易理解的思路:
假设你有一组数据,想从头开始检查,直到找到第一个不合格项。
而检查动作本身至少要先做一次。
这类逻辑理论上可以用 REPEAT。
不过在 PLC 实际工程中,REPEAT 的使用频率通常低于 FOR 和 WHILE。
原因很简单:
大多数批量处理,FOR 更直观
大多数条件驱动处理,WHILE 更常见
REPEAT 虽然有它的价值,但工程师用得相对少一些
所以从学习顺序来说:
先把 FOR 吃透,再理解 WHILE,最后把 REPEAT 当作补充。
这是更符合 PLC 工程实践的路径。
十三、循环和数组为什么几乎是天然搭档
这一点后面你学数组时会更强烈感受到,但现在先建立直觉很重要。
数组的本质就是:
把一组同类型数据按编号放在一起。
例如:
Alarm[1..20]
TempPV[1..8]
SensorOK[1..16]
RecipeValue[1..50]
而循环的本质就是:
按编号一轮一轮处理。
所以数组和循环一结合,就非常自然。
例如:
FOR i := 1 TO 20 DO
IF AlarmTrig[i] THEN
AlarmAct[i] := TRUE;
END_IF;
END_FOR;
这种写法的感觉,和你逐条写 20 段判断完全不同。
它更像是在表达一个统一规则:
“对这 20 个对象,都执行同样的判断。”
这就是结构化编程的味道。
十四、循环里能不能套 IF,IF 里能不能再套循环
当然可以。
而且在工程里很常见。
例如:
FOR i := 1 TO 10 DO
IF TempPV[i] > TempHighLimit[i] THEN
TempHighAlarm[i] := TRUE;
ELSE
TempHighAlarm[i] := FALSE;
END_IF;
END_FOR;
这里就是循环里套判断。
反过来,也可能是先满足某个条件,再进入循环:
IF ResetPB THEN
FOR i := 1 TO 20 DO
AlarmAct[i] := FALSE;
END_FOR;
END_IF;
这也很常见。
甚至某些复杂场景里,还会有双层循环。
比如二维数据处理、行列扫描等。
不过这里要注意一个工程原则:
结构可以嵌套,但嵌套越深,越要警惕可读性和扫描负担。
不是不能写,而是要心里有数。
十五、一个非常实用的工程示例:报警批量复位
我们来看一个典型 PLC 场景。
系统里有 32 路报警位,按下复位按钮后,需要把这些报警活动位全部清掉。
用 SCL 可以写成:
IF ResetPB THEN
FOR i := 1 TO 32 DO
AlarmAct[i] := FALSE;
END_FOR;
END_IF;
这段程序的好处很明显:
第一,逻辑一眼就懂。
第二,以后如果报警数量从 32 改成 40,修改很方便。
第三,不容易写漏。
第四,比一条一条赋值更整洁。
这就是循环的工程价值。
不是炫技,而是让重复逻辑更有结构。
十六、一个更接近现场的数据处理示例:查找第一个故障通道
假设有 16 路设备状态信号,你想找到第一个故障通道编号,便于 HMI 显示。
可以这样写:
FirstFaultNo := 0;
FOR i := 1 TO 16 DO
IF NOT DeviceOK[i] THEN
FirstFaultNo := i;
END_IF;
END_FOR;
不过这里有一个细节。
这段程序最后得到的,不一定是“第一个故障”,而可能是“最后一个故障位置”,因为它会一直扫到末尾,后面又把前面的结果覆盖了。
如果你真想找第一个故障位置,写法就要更有意识。
比如可以加一个条件限制:
FirstFaultNo := 0;
FOR i := 1 TO 16 DO
IF (FirstFaultNo = 0) AND (NOT DeviceOK[i]) THEN
FirstFaultNo := i;
END_IF;
END_FOR;
这时候一旦第一个故障位置被记录,后面就不会再覆盖。
这个例子特别值得你体会。
因为它说明了:
循环只是工具,结果对不对,关键还是逻辑细节。
十七、循环最适合做“规则统一”的事情,不适合做“每一步都完全不同”的事情
比如你要处理 20 路温度,每一路判断规则一样:
大于上限报警,小于下限报警。
这就很适合循环。
但如果你有 10 个步骤,而每一步的动作、时序、条件、跳转规则都完全不同,那就不一定适合用循环一把梭。
这种时候,往往 CASE、状态机更合适。
所以你要建立一个判断标准:
当对象很多,但处理规则一致时
优先考虑循环。
当步骤很多,但每一步逻辑差异很大时
更可能适合状态分支,而不是纯循环。
这能帮助你避免“为了用循环而用循环”。
十八、PLC 里使用循环时,为什么要特别有“边界意识”
边界意识是写循环时非常核心的工程习惯。
比如你的数组是 Alarm[1..20],那循环就应该非常明确地控制在 1 到 20 之间。
如果你不小心写成:
FOR i := 1 TO 25 DO
那后面 21 到 25 的访问就可能有风险。
同样,如果你的数据是从 0 开始编号,而你却按 1 开始扫,也会错位。
所以每次写循环,你都应该先想清楚:
起始下标是多少
结束下标是多少
数组定义范围是什么
有没有可能越界
有没有可能漏掉最后一个元素
这个习惯特别重要。
因为循环一旦写错,不是只错一个点,而是可能一口气把一批处理都带偏。
十九、循环会不会影响 PLC 扫描周期
会。
但不是说一写循环就一定有问题,而是要看:
循环次数
循环体复杂度
执行频率
CPU 性能
是否在主循环中高频执行
例如:
一个每扫都执行的 5000 次 FOR,里面还做字符串处理、复杂运算、通信解析,那当然要警惕。
但一个每次复位时才执行一次、只清 20 个 BOOL 位的 FOR,通常就很轻。
所以正确态度不是“害怕循环”,而是:
对循环的开销有概念。
工程上要学会区分:
高频执行逻辑
条件触发逻辑
大批量处理逻辑
可分批执行逻辑
这样你才会越来越成熟,而不是一听循环就怕,或者一会循环就乱用。
二十、初学者写循环时最常见的几个错误
第一,拿循环做延时
这是前面已经强调过的大坑。
一定不要这么用。
第二,循环条件没有退出机制
尤其是 WHILE,最容易死循环。
第三,下标范围写错
数组定义是 1 到 10,你却扫到 11 或者从 0 开始。
第四,循环里修改了不该修改的东西
比如本来只是想找目标,结果把控制状态在每轮都反复覆盖。
第五,结果变量没有先初始化
例如求和前不先清零,统计前不先归零,查找位置前不先设默认值。
这会导致逻辑看起来能跑,但结果越来越怪。
第六,没想清楚是要“找到第一个”还是“统计全部”还是“处理全部”
这三种需求虽然都可能用循环,但写法思路不一样。
这个区分非常重要。
二十一、一个很实用的学习建议:学循环时,不要一开始就追求复杂嵌套
很多人一学会 FOR,就想立刻上:
双层循环
条件嵌套
字符串数组处理
动态查找
大型数据表遍历
这当然不是以后不能学,而是现在没必要太快。
你现在最重要的是先练熟这几类最基础的循环任务:
清零一组数据
检查一组状态
统计成立数量
求和求平均
查找第一个满足条件的位置
只要这几类思路顺了,你对循环就真正有感觉了。
后面再往复杂方向走,会稳很多。
二十二、一个你以后会越来越常用的思路:循环不是“为了省代码”,而是“为了表达一类处理规则”
这句话特别值得记住。
很多人一开始学循环,会觉得它的好处只是“代码变短了”。
但那只是表面。
循环真正的价值,是它在表达一种规则:
这一组对象,都要接受同样的处理。
比如:
这 16 路输入都要做状态检查
这 20 路报警都要判断触发
这 8 个采样点都要参与平均值计算
这 32 个标志位都要在复位时清零
当你用循环写出来时,程序本身就在说:
“这不是零散的 32 条语句,而是一条统一规则作用于 32 个对象。”
这就是结构化思维。
这也正是 SCL 相比单纯图形堆砌更有优势的地方之一。
二十三、这一篇最后,给你一个很实在的工程判断标准
以后只要你在项目里遇到某段逻辑,脑子里可以先问自己这几个问题:
第一,这是不是对一组对象做同样的处理
如果是,循环往往值得考虑。
第二,这组对象数量是否明确
如果数量明确,优先考虑 FOR。
第三,是否存在“只要条件成立就继续”的需求
如果有,再考虑 WHILE。
第四,这段循环是否可能带来明显的扫描负担
如果有,先评估,再决定是否拆分、优化或改写。
第五,我是不是误把循环当成了延时工具
如果是,立即停下来,换成定时器或时间逻辑。
只要你养成这几个判断习惯,循环就会从“有点怕的东西”,变成“很顺手的工具”。
小结
这一篇你最应该记住这些核心点:
循环的本质,是按规则重复执行同类处理。
在 PLC 里,循环主要是批量处理工具,不是延时工具。
FOR 适合已知次数的重复处理,是 PLC 工程里最常用、也最适合先掌握的循环。
WHILE 适合条件驱动的继续执行,但必须特别注意退出条件,否则容易死循环。
REPEAT 是先执行后判断,适合至少要执行一次的场景,但使用频率通常低于 FOR。
循环和数组几乎是天然搭档,特别适合批量判断、初始化、统计、查找、求和等任务。
使用循环时,必须有边界意识、扫描周期意识和退出机制意识。
真正好的循环,不只是代码短,而是能清楚表达“同一类规则作用于一组对象”。
下载资料前请先绑定手机号码