文章目录

ST字符串长度限制:STRING类型默认长度与溢出处理实战

发布于 2026-03-19 11:24:39 · 浏览 7 次 · 评论 0 条

在 PLC 编程中,STRING 类型是处理文本数据最常用的变量类型之一。但很多工程师在首次使用时会遇到一个隐蔽却致命的问题:字符串莫名截断、赋值失败、HMI 显示乱码、甚至导致 FB 块逻辑异常跳转。根本原因往往不是逻辑错误,而是对 STRING 的底层结构缺乏认知——尤其是其长度限制机制。本文聚焦 Siemens S7-1200 / S7-1500 系列 PLC 中基于 Structured Text(ST)语言的 STRING 类型,用纯实操方式讲清三点:

  1. STRING 的默认长度是多少?它如何被存储?
  2. 当输入内容超过长度上限时,系统实际执行哪一套溢出规则
  3. 如何在不改硬件、不换型号的前提下,零风险规避溢出并稳定读写任意长度文本?

一、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 字节(索引从 0MAX_LEN−1),而非整个 255 字节。

当你声明:

MyText : STRING;

系统自动按 STRING[254] 处理,即:

  • MAX_LEN := 254
  • DATA 占用 254 字节(索引 0253
  • 总结构大小 = 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),也不会停机,而是按确定性规则裁剪。你必须掌握这四条底层行为:

  1. 截断优先于报错:系统先计算右侧字符串的字节数(非字符数!)。若字节数 > MAX_LEN,则只取前 MAX_LEN 字节,丢弃后续全部内容。
    ✅ 示例:MyText : STRING[10]; 执行 MyText := 'ABCDEFGHIJKL'; → 最终 MyText = 'ABCDEFGHIJ'(10 字节),LEN = 10

  2. 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

  3. 空格与不可见字符计入长度:制表符 HT0x09)、回车 CR0x0D)、换行 LF0x0A)、空格 SP0x20)全部占 1 字节,并参与截断判断。
    ✅ 示例:MyText : STRING[5]; 执行 MyText := 'ABC' + CR + LF;'ABC\x0D\x0A' 共 5 字节)→ LEN = 5,内容完整;若再加一空格 → 超长截断,空格丢失。

  4. 赋值后 DATA 区域末尾不补 0,但 LEN 严格同步:截断后,DATA[LEN] 及之后字节保持原值(可能是历史残留),唯一可信的结束标志是 LEN。任何字符串处理函数(如 FINDLEFT)均以 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 手动赋值正确,否则后续 CONCATFIND 会出错。


四、调试技巧:3 行代码实时监控字符串状态

在监控表(Watch Table)中无法直接看到 LENMAX_LEN 字段(TIA Portal 默认隐藏结构体成员),可用以下 ST 表达式快速诊断:

监控项 表达式 说明
当前长度 MyText.LEN 显示实际字节数
容量上限 MyText.MAX_LEN 验证声明是否生效
末字节值(查截断点) MyText.DATA[MyText.LEN - 1] LEN > 0,返回最后一个有效字节的十六进制值,用于确认是否截断在汉字中间

例如,监控到 MyText.LEN = 6MyText.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_LENCONCAT 自动截断尾部 改用 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 是底线,不是可选项。

评论 (0)

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

扫一扫,手机查看

扫描上方二维码,在手机上查看本文