在工业自动化场景中,经常需要处理来自扫码枪、RFID 阅读器或上位机下发的字符串数据。这些数据通常包含多个信息段,例如“批次号 - 日期 - 流水号”,需要通过分隔符将其拆解为独立的变量以便后续逻辑处理。西门子 S7-1200/1500 PLC 虽内置了部分字符串指令,但并未直接提供类似高级语言的“Split”函数。本文将手把手教你使用 SCL 语言编写一个通用的字符串分割功能块。
准备工作
在开始编写代码前,请确认你的开发环境满足以下基本条件。这能避免后续出现指令不支持或编译报错的问题。
- 软件版本:确保安装的 TIA Portal 版本为 V15 或更高。低版本对字符串指令的支持较弱,可能缺少
FIND或LEN等关键函数。 - 硬件型号:本项目适用于 S7-1200 或 S7-1500 系列 PLC。S7-200 SMART 或老款 S7-300/400 需要采用不同的梯形图逻辑,不适用本教程。
- 编程语言:建议使用 SCL(结构化控制语言)。虽然梯形图也能实现,但处理字符串循环和数组索引时,SCL 的代码量和可读性优势巨大。
核心逻辑设计
字符串分割的本质是循环查找分隔符的位置,并截取两个分隔符之间的字符。为了让你直观理解程序运行流程,请参考下方的逻辑流程图。
上图展示了程序如何通过循环不断切割字符串。关键在于记录当前的“起始位置”,每次找到分隔符后,更新起始位置为“当前分隔符位置 + 1",从而跳过已处理的部分。
步骤一:创建功能块
首先需要在项目中建立专用的功能块,以便重复调用。
- 打开 项目树,右键点击“程序块”文件夹。
- 选择 “添加新块”,在弹出的窗口中勾选 “函数块 (FB)"。
- 输入 名称为
FB_StringSplit,语言选择SCL。 - 点击 “确定”生成空白块。
步骤二:定义接口变量
接口定义决定了功能块的易用性。我们需要输入原始字符串、分隔符,输出分割后的字符串数组。请在 FB_StringSplit 的接口区域输入以下变量。
| 变量名称 | 数据类型 | 方向 | 说明 |
|---|---|---|---|
InputString |
String | Input | 待分割的原始字符串 |
Delimiter |
Char | Input | 分隔符字符,如 '-' 或 ',' |
MaxParts |
Int | Input | 最大分割段数,防止数组溢出 |
OutputArray |
Array[0..9] of String | Output | 存储分割结果的字符串数组 |
PartCount |
Int | Output | 实际分割出的段数 |
StartPosition |
Int | Static | 内部变量,记录当前查找起点 |
FoundPos |
Int | Static | 内部变量,记录找到分隔符的位置 |
Index |
Int | Static | 内部变量,循环计数器 |
注意:OutputArray 的大小应根据实际需求调整。上表定义为 10 段(0 到 9),若需要更多段数,请修改 数组上限。静态变量 Static 用于在扫描周期内保持中间计算状态,避免数据丢失。
步骤三:编写 SCL 代码
双击打开 FB_StringSplit 的编程界面,删除 默认生成的注释,复制 以下代码并粘贴 到编辑区。代码已添加详细注释,解释每一行的作用。
// 初始化变量
#Index := 0;
#StartPosition := 1; // SCL 字符串索引通常从 1 开始
#PartCount := 0;
// 获取输入字符串长度
#TempLength := LEN(#InputString);
// 开始循环处理
WHILE #StartPosition <= #TempLength AND #Index < #MaxParts DO
// 查找分隔符位置,从当前起始位置开始找
#FoundPos := FIND(#InputString, #Delimiter, #StartPosition);
IF #FoundPos > 0 THEN
// 找到分隔符,截取左侧部分
// MID 函数参数:原字符串,起始位置,长度
#OutputArray[#Index] := MID(#InputString, #StartPosition, #FoundPos - #StartPosition);
// 更新起始位置到分隔符之后
#StartPosition := #FoundPos + 1;
// 计数器加 1
#Index := #Index + 1;
ELSE
// 未找到分隔符,说明是最后一部分
// 截取剩余所有字符
#OutputArray[#Index] := MID(#InputString, #StartPosition, #TempLength - #StartPosition + 1);
// 计数器加 1
#Index := #Index + 1;
// 退出循环
EXIT;
END_IF;
END_WHILE;
// 输出实际分割的段数
#PartCount := #Index;
注意:部分旧版本固件可能不支持 MID 函数,若编译报错,请使用 LEFT 和 RIGHT 组合替代,或升级固件。上述代码假设 LEN 和 FIND 指令可用,这是 S7-1200/1500 的标准库函数。
步骤四:调用与测试
功能块编写完成后,需要在主程序中进行调用并验证效果。
- 打开 主程序块(如
Main [OB1])。 - 拖拽
FB_StringSplit到程序编辑区。 - 创建 一个背景数据块,命名为
DB_Split_Instance。 - 输入 测试数据。在全局数据块或监控表中定义 以下变量用于测试:
TestInput(String): 输入"A01-B02-C03"TestDelim(Char): 输入'-'ResultArray(Array of String): 用于接收结果
- 关联 引脚。将
TestInput连接到InputString,TestDelim连接到Delimiter,ResultArray连接到OutputArray。 - 下载 程序到 PLC 并运行。
- 监控
DB_Split_Instance数据块。观察OutputArray是否依次显示"A01","B02","C03",且PartCount显示为3。
常见问题排查
如果在测试过程中发现结果不正确,请按照以下清单逐项检查。
| 现象 | 可能原因 | 解决方法 |
|---|---|---|
| 结果全为空 | 起始位置索引错误 | 确认 PLC 字符串索引是从 0 还是 1 开始,SCL 通常为 1 |
| 数组溢出报错 | 分割段数超过设定 | 增大 MaxParts 参数或检查输入字符串分隔符数量 |
| 最后一次截取缺失 | 循环条件过早结束 | 检查 ELSE 分支是否正确处理了末尾无分隔符的情况 |
| 包含分隔符字符 | 截取长度计算错误 | 确认 MID 函数的长度参数是否减去了分隔符占用位 |
特别注意字符串长度计算。某些情况下,字符串实际长度可能包含末尾的空字符填充。使用 LEN 函数获取的是有效字符长度,而非数组定义长度。若发现截取结果包含乱码,请确保在截取前使用 LEN 函数动态计算长度,而非直接使用数组定义大小。
对于连续分隔符的情况(如 "A--B"),上述逻辑会将中间部分识别为空字符串。若业务不允许空字符串,需在截取后增加 判断逻辑:若 #OutputArray[#Index] 长度为 0,则跳过 该次计数,不增加 #Index,继续下一次循环查找。
若需要处理多个不同分隔符(如同时支持逗号和分号),可修改 FIND 逻辑,先查找第一个分隔符位置,再查找第二个,取最小值作为切割点。这需要嵌套 IF 判断或编写辅助函数比较位置大小。

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