循环 (REPEAT...UNTIL...END_REPEAT
):
核心概念:
-
至少执行一次: 这是
REPEAT...UNTIL
循环最核心的特点。无论UNTIL
后面的条件初始值如何,循环体内的代码都会先执行至少一次。执行完一次后,才会去检查退出条件。 -
条件为真时退出: 循环会一直执行,直到
UNTIL
后面的条件表达式计算结果为TRUE
。一旦条件为TRUE
,循环立即终止,程序继续执行END_REPEAT
之后的语句。 -
语法结构:
REPEAT // 这里是循环体 (需要重复执行的代码块) // 可以包含任意有效的 SCL 语句 (赋值、IF、CASE、调用函数/功能块等) // ... // 通常在这个循环体内会有改变退出条件状态的语句 UNTIL <退出条件表达式> // 当此表达式计算结果为 TRUE 时,循环结束 END_REPEAT;
与 WHILE...DO
循环的关键区别:
特性 | REPEAT...UNTIL | WHILE...DO |
---|---|---|
执行顺序 | 先执行循环体,后检查条件 | 先检查条件,后决定是否执行循环体 |
最少执行次数 | 至少 1 次 | 可能 0 次 (如果条件初始就不满足) |
退出条件 | 条件为 TRUE 时退出 | 条件为 FALSE 时退出 |
适用场景 | 需要至少执行一次操作,再根据结果判断 | 需要先判断条件是否允许再执行操作 |
为什么在 PLC 编程中 REPEAT...UNTIL
很有用?
在工业控制中,有很多场景要求必须先执行一次操作,然后才能根据设备的反馈或状态决定是否需要继续执行。例如:
-
初始化硬件: 必须先发送一次初始化命令,然后才能检查初始化是否完成。
-
读取不稳定信号: 必须先尝试读取一次传感器,然后才能判断读数是否有效或是否需要重试。
-
执行直到达到目标: 先执行一次动作(如移动一小步),然后检查是否到达目标位置。
-
通信请求/响应: 先发送一次请求,然后等待响应或超时。
详细使用说明 & 示例:
示例 1:读取传感器直到成功或超时 (基于你之前的代码)
VAR DataReady : BOOL; // 标志:传感器数据是否就绪 (TRUE/FALSE) TimeoutReached : BOOL; // 标志:是否超时 (TRUE/FALSE) StartTime : TIME; // 记录循环开始的时间 CurrentTime : TIME; // 当前时间 TimeoutDuration : TIME := T#5S; // 超时时间设定为 5 秒 END_VAR // 初始化标志 DataReady := FALSE; TimeoutReached := FALSE; StartTime := T#0S; // 通常在实际应用中,StartTime 会在进入循环前获取,见下面 // 获取循环开始时的 PLC 时间 (假设这是第一次获取时间点) StartTime := TIME(); // 获取当前 PLC 时间 REPEAT // 1. 尝试读取传感器 (假设 ReadSensor 函数返回 BOOL: TRUE=数据有效就绪, FALSE=未就绪或无效) DataReady := ReadSensor(); // 2. 检查是否超时 (重要:每次循环都更新并检查) CurrentTime := TIME(); // 获取当前时间 TimeoutReached := (CurrentTime - StartTime) >= TimeoutDuration; // 计算耗时是否 >= 5秒 // 3. (可选) 可以在循环体内添加一些延迟或等待,避免过于频繁读取占用过多CPU // 例如:WAIT TIME(MS=10); // 等待 10 毫秒 (注意:WAIT 指令会阻塞,谨慎使用,可能影响扫描周期) // 更常见的是让循环自然执行,依靠 PLC 扫描周期来控制频率。 UNTIL DataReady OR TimeoutReached // 退出条件:数据准备好 OR 超时到达 END_REPEAT; // 循环结束后,根据 DataReady 和 TimeoutReached 的状态进行后续处理 IF DataReady THEN // 处理有效的传感器数据 ProcessSensorData(); ELSIF TimeoutReached THEN // 处理超时错误 HandleTimeoutError(); END_IF;
5. 一个完整的 SCL 函数示例 (FC)
假设我们要创建一个函数 CalculateAverage
,计算一个 REAL
数组前 N 个元素的平均值。
-
创建 FC:
-
类型:函数 (FC)
-
语言:SCL
-
名称:
CalculateAverage
-
-
定义接口:
FUNCTION CalculateAverage : REAL // 函数返回值类型为 REAL VAR_INPUT DataArray : ARRAY[1..100] OF REAL; // 输入数组 (假设最大100个元素) NumElements : INT; // 输入要计算平均值的元素个数 (1-100) END_VAR VAR_TEMP i : INT; // 循环计数器 Sum : REAL := 0.0; // 累加和,初始化为0 END_VAR
-
编写函数体:
// 检查输入有效性 (避免除零或越界) IF (NumElements <= 0) OR (NumElements > 100) THEN CalculateAverage := 0.0; // 输入无效,返回0 RETURN; // 提前退出函数 END_IF; // 累加数组元素 FOR i := 1 TO NumElements DO Sum := Sum + DataArray[i]; END_FOR; // 计算并返回平均值 CalculateAverage := Sum / NumElements;
-
使用函数: 这个 FC 可以在其他 LAD、FBD、SCL 块中被调用,就像调用标准库函数一样。在 LAD/FBD 中,它显示为一个可拖拽的指令框;在 SCL 中直接写
Result := CalculateAverage(MyArray, 10);
。
6. 编译、下载与调试
-
编译: 在项目树中选中你的 PLC 设备,点击工具栏上的“编译”按钮(或右键选择编译)。TIA Portal 会检查所有块的语法和逻辑错误。务必解决所有编译错误!
-
下载到 PLC: 确保 PLC 在线。选中 PLC 设备,点击“下载到设备”按钮。选择需要下载的块(通常全选),并确认。
-
在线监控与调试:
-
打开你的 SCL 块。
-
点击工具栏上的“在线”按钮(或右键块选择“监控”)。
-
SCL 编辑器会进入在线视图。你可以:
-
看到变量的当前值(显示在代码行右侧或通过光标悬停查看)。
-
看到程序执行的当前行(高亮显示)。
-
强制 (Force) 或 写入 (Write) 变量的值进行测试。
-
设置断点(在代码行号左侧点击):当程序执行到断点时会暂停,方便你检查变量状态和调用堆栈。
-
单步执行(Step Over, Step Into, Step Out):仔细跟踪程序流程。
-
-
7. 学习资源与最佳实践
-
官方文档: TIA Portal 内置的帮助系统 (
F1
) 是学习 SCL 语法和功能的宝库。搜索“SCL”或具体关键字。 -
示例项目: 西门子官网和 TIA Portal 安装目录下通常有示例项目。
-
最佳实践:
-
命名规范: 使用清晰、一致的变量和块命名(如
bStart
,rTemperature
,iCounter
,fbMotorControl
)。 -
注释: 为复杂的逻辑、算法、接口含义添加清晰注释。
-
模块化: 将功能分解成小的、可重用的 FC/FB。
-
错误处理: 始终检查输入的有效性、边界条件和可能的错误状态。
-
代码格式化: 使用缩进、空行使代码结构清晰易读(TIA Portal 有自动格式化功能
Ctrl+I
)。 -
避免全局变量: 尽量通过块接口传递数据,提高可移植性和可测试性。
-
结语
恭喜你!通过这篇教程,你已经掌握了在 TIA Portal 中创建和使用 SCL 块的基础知识:从创建块、理解基本语法和数据类型,到运用关键的控制结构(IF, CASE, FOR, WHILE)和编写一个简单的函数。
SCL 是处理西门子 PLC 中复杂逻辑和算法的利器。虽然入门需要一点文本编程的思维转换,但一旦掌握,你会发现它在效率和表达能力上的巨大优势。多加练习,参考官方文档,你很快就能熟练运用 SCL 来解决更高级的自动化任务了!