在 PLC 编程中,STRING 类型是处理文本数据最常用的变量类型之一。但很多工程师在首次使用时会遇到一个隐蔽却致命的问题:字符串莫名截断、赋值失败、HMI 显示乱码、甚至导致 FB 块逻辑异常跳转。根本原因往往不是逻辑错误,而是对 STRING 的底层结构缺乏认知——尤其是其长度限制机制。本文聚焦 Siemens S7-1200 / S7-1500 系列 PLC 中基于 Structured Text(ST)语言的 STRING 类型,用纯实操方式讲清三点:
STRING的默认长度是多少?它如何被存储?- 当输入内容超过长度上限时,系统实际执行哪一套溢出规则?
- 如何在不改硬件、不换型号的前提下,零风险规避溢出并稳定读写任意长度文本?
一、STRING 类型的本质:不是“文本”,而是“带长度头的字节数组”
STRING 在 S7-1200/S7-1500 中并非高级语言中的动态字符串(如 Python 的 str),而是一个固定大小的结构体,定义如下:
| 字段 | 类型 | 字节数 | 说明 |
|---|---|---|---|
LEN |
USINT |
1 | 当前实际字符数(0–254) |
MAX_LEN |
USINT |
1 | 该 STRING 变量声明时允许的最大字符数(即容量) |
DATA |
ARRAY[0..254] OF BYTE |
255 | 实际存储字符的字节数组(UTF-8 编码,每个 ASCII 字符占 1 字节) |
注意:MAX_LEN 的最大允许值为 254,因此 DATA 数组真正可用长度为 MAX_LEN 字节(索引从 0 到 MAX_LEN−1),而非整个 255 字节。
当你声明:
MyText : STRING;
系统自动按 STRING[254] 处理,即:
MAX_LEN := 254DATA占用254字节(索引0至253)- 总结构大小 =
1 (LEN)+1 (MAX_LEN)+254 (DATA)= 256 字节
这是 STRING 的默认长度,也是绝大多数初学者踩坑的起点:以为“没写长度就是无限”,实则上限铁板钉钉为 254 字符(ASCII)。
二、溢出发生时,PLC 不报错,但严格按以下 4 条规则静默执行
当执行 MyText := 'Hello, this is a very long text exceeding 254 characters...'; 时,PLC 不会触发运行时错误(RT error),也不会停机,而是按确定性规则裁剪。你必须掌握这四条底层行为:
-
截断优先于报错:系统先计算右侧字符串的字节数(非字符数!)。若字节数 >
MAX_LEN,则只取前MAX_LEN字节,丢弃后续全部内容。
✅ 示例:MyText : STRING[10];执行MyText := 'ABCDEFGHIJKL';→ 最终MyText = 'ABCDEFGHIJ'(10 字节),LEN = 10 -
LEN 始终等于实际写入字节数:即使源字符串含中文(UTF-8 下占 3 字节/字),
LEN也记录字节数,而非“汉字个数”。
✅ 示例:MyText : STRING[6];执行MyText := '你好世界';(UTF-8 编码为E4.BD.A0 E5:A5xBD E4:B896 E7:95:8C,共 12 字节)→ 因12 > 6,仅取前 6 字节E4.BD.A0 E5:A5→ 对应'你好'的前 2 字节E4.BD+'好'的前 1 字节A0→ 实际为乱码ä½(非完整汉字),且LEN = 6 -
空格与不可见字符计入长度:制表符
HT(0x09)、回车CR(0x0D)、换行LF(0x0A)、空格SP(0x20)全部占 1 字节,并参与截断判断。
✅ 示例:MyText : STRING[5];执行MyText := 'ABC' + CR + LF;('ABC\x0D\x0A'共 5 字节)→LEN = 5,内容完整;若再加一空格 → 超长截断,空格丢失。 -
赋值后 DATA 区域末尾不补 0,但 LEN 严格同步:截断后,
DATA[LEN]及之后字节保持原值(可能是历史残留),唯一可信的结束标志是LEN值。任何字符串处理函数(如FIND、LEFT)均以LEN为界,而非扫描0x00。
⚠️ 关键结论:永远不要用
IF MyText = 'xxx'做等值判断,除非你 100% 确保 LEN 和内容完全一致。更安全的做法是IF (MyText = 'xxx') AND (LEN(MyText) = 3)。
三、实战:3 种零成本防溢出方案(无需额外 DB 块或函数)
方案 1:声明时显式指定长度(最简单、最推荐)
放弃 STRING; 这种“偷懒写法”,始终用方括号明确定义容量:
// ✅ 推荐:根据业务场景预估最大长度
ProductName : STRING[32]; // HMI 产品名称,通常 ≤32 字符
SerialNo : STRING[20]; // 条码/序列号,标准 ≤20 字符
LogMessage : STRING[128]; // 日志消息,预留扩展空间
好处:编译期即检查,内存分配精准,无运行时不确定性。
方案 2:赋值前主动截断(适用于外部输入不可控场景)
当字符串来自 HMI 输入框、Modbus TCP 报文、或上位机下发时,需在 ST 代码中手动防护:
// 假设 RawInput 是外部传入的 STRING[254]
VAR
RawInput : STRING[254];
SafeDest : STRING[32];
InputLen : USINT;
END_VAR
// 步骤 1:获取原始长度
InputLen := LEN(RawInput);
// 步骤 2:按目标容量截断(使用 LEFT 函数)
IF InputLen > 32 THEN
SafeDest := LEFT(RawInput, 32);
ELSE
SafeDest := RawInput;
END_IF;
LEFT(Str, Len) 是 IEC 61131-3 标准函数,安全可靠,不触发溢出。
方案 3:用 MOVE 指令绕过 STRING 结构体校验(高级技巧)
当需将超长文本分段存入多个 STRING 变量,或需直接操作字节流时,可跳过 STRING 类型检查:
VAR
FullData : ARRAY[0..511] OF BYTE; // 原始 512 字节缓冲区
Part1 : STRING[254];
Part2 : STRING[254];
MoveLen : USINT;
END_VAR
// 将 FullData 前 254 字节移到 Part1(强制覆盖 LEN/MAX_LEN)
MoveLen := 254;
MOVE(
IN := ADR(FullData[0]),
OUT := ADR(Part1.DATA[0]),
LEN := MoveLen
);
// 手动设置 LEN(MOVE 不更新 LEN 字段!)
Part1.LEN := MoveLen;
// 同理处理 Part2
MOVE(
IN := ADR(FullData[254]),
OUT := ADR(Part2.DATA[0]),
LEN := 254
);
Part2.LEN := 254;
⚠️ 注意:MOVE 绕过了 STRING 的长度保护,必须确保 LEN 手动赋值正确,否则后续 CONCAT 或 FIND 会出错。
四、调试技巧:3 行代码实时监控字符串状态
在监控表(Watch Table)中无法直接看到 LEN 和 MAX_LEN 字段(TIA Portal 默认隐藏结构体成员),可用以下 ST 表达式快速诊断:
| 监控项 | 表达式 | 说明 |
|---|---|---|
| 当前长度 | MyText.LEN |
显示实际字节数 |
| 容量上限 | MyText.MAX_LEN |
验证声明是否生效 |
| 末字节值(查截断点) | MyText.DATA[MyText.LEN - 1] |
若 LEN > 0,返回最后一个有效字节的十六进制值,用于确认是否截断在汉字中间 |
例如,监控到 MyText.LEN = 6 且 MyText.DATA[5] = 16#A0,结合 UTF-8 规则可反推此处是某个汉字的第 2 字节,证实发生了不完整截断。
五、常见陷阱与避坑清单(直接抄录使用)
| 陷阱现象 | 根本原因 | 解决动作 |
|---|---|---|
HMI 输入中文后显示为 ä½ å¥½ |
HMI 发送 UTF-8,但 STRING[20] 容量不足,截断在汉字中间 | 将变量改为 STRING[60](3 字节/汉字 × 20 字) |
CONCAT(S1, S2) 结果比预期短 |
S1.LEN + S2.LEN > MAX_LEN,CONCAT 自动截断尾部 |
改用 LEFT(CONCAT(S1, S2), TargetLen) 显式控制 |
FIND(MyText, 'OK') 返回 0(未找到) |
MyText 末尾含不可见空格或 0x00,导致 'OK' 不连续 |
赋值前用 TRIM() 清除首尾空格:MyText := TRIM(RawInput); |
| 在 UDT 中嵌套 STRING 后 DB 块体积暴增 | 每个 STRING[254] 固定占 256 字节,大量声明浪费内存 |
按需缩减长度,如 STRING[16] 仅占 18 字节 |
✅ 最后验证:打开 TIA Portal → “项目视图” → 右键 DB 块 → “属性” → 查看 “大小” 字段。若发现某 STRING 变量占用远超预期,立即检查声明长度。
声明 STRING[254] 是习惯,不是必须;截断是规则,不是 Bug;监控 LEN 是底线,不是可选项。

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