1. 从新手到高手:为什么长字符串处理是个“坎”?
很多刚开始用CODESYS做项目的朋友,可能都遇到过这样的场景:设备需要记录一长串的生产日志,或者要处理从扫码枪读进来的一整条包含几十个字段的条码信息。这时候,如果你还像处理普通短字符串那样,直接用 LEN 或者 CONCAT 这些函数,程序要么编译报错,要么运行起来结果莫名其妙,长度永远卡在255。这个“255”的魔咒,可以说是CODESYS字符串处理从新手村迈向实战的第一个大BOSS。
我自己刚开始也在这里栽过跟头。记得有一次做一个包装线的数据追溯项目,需要把产品批号、生产时间、工位号等十几个信息拼接成一个长字符串,然后发给上位机数据库。我习惯性地用了 LEN 函数去检查字符串长度,结果发现无论怎么拼接,返回的长度最大就是255,后面的数据全“丢”了。当时排查了半天,才恍然大悟:原来CODESYS里那些我们最熟悉的字符串基本函数,比如 LEN, FIND, REPLACE, LEFT, RIGHT 等等,它们的设计上限就是255个字符。这不是BUG,而是由底层数据类型的限制决定的。一旦你的字符串长度超过了255,这些函数就“看不见”超出的部分了。
所以,理解CODESYS中字符串的存储机制是第一步。当你定义一个 STRING 变量,比如 strText: STRING := 'Hello',CODESYS在内存中其实是把它当作一个字符数组来处理的。如果你不指定长度,它默认会分配一个最大80个字符的数组空间(索引从0到79),并且会额外占用一个字节来存放字符串的结束符 \0。这就是为什么你用 SIZEOF(strText) 去查看大小时,会发现它占了81个字节(80个字符+1个结束符)。而对于长字符串,比如 strLong: STRING(1000),你声明了一个最大1000字符的字符串,它实际占用的内存就是1001个字节。关键点来了:那些只能处理255个字符的基本函数,它们内部可能只认 STRING 或 STRING(255) 这种特定的类型描述,对于更长的字符串类型,它们就“无能为力”了,读取长度时只会返回255这个最大值,而不是实际长度。
那么,面对动辄几千甚至上万字符的日志、报文、配方数据,我们该怎么办呢?别慌,CODESYS其实为我们准备了一套更强大的“武器库”,同时也允许我们“自己造轮子”。接下来,我就结合自己踩过的坑和实战经验,带你系统地掌握高效处理长字符串的两种核心方法。
2. 官方利器:StringUtils库深度解析与实战
当你需要处理长字符串时,第一选择应该是CODESYS标准库里的 StringUtils。这个库就像是为你准备的一整套专业级字符串手术刀,专门用来对付255字符以上的“大块头”。在库管理器里找到并添加它之后,你会发现里面主要提供了两套函数:一套是针对ANSI字符集的(后缀带A,如StrLenA),另一套是针对Unicode的(后缀带W,如StrLenW)。在大多数工业场景下,处理英文、数字和常见符号,用ANSI这套就足够了,效率也更高。
这些函数有一个共同特点:它们的参数通常是 POINTER TO BYTE 类型,也就是指向字符串内存首地址的指针。这听起来有点吓人,但其实用起来很简单。在CODESYS里,你可以用 ADR() 函数轻松获取任何一个字符串变量的地址。这种指针传递的方式,让函数摆脱了具体字符串长度类型的束缚,理论上可以处理长达40多亿字符(2^32-1)的字符串,完全满足工业应用的需求。
下面,我挑几个最常用、也最容易用错的函数,结合具体代码例子,带你上手实操。
2.1 获取真实长度:StrLenA的正确打开方式
这是你肯定会用的第一个函数。假设我们有一个长字符串变量 strLogData: STRING(5000),里面存满了日志。你用 LEN(strLogData) 得到的永远是255,而用 StrLenA(ADR(strLogData)) 才能得到真实的长度,比如4987。
这里有个坑需要注意:StrLenA 函数是通过遍历内存,寻找结束符 \0 来确定长度的。这意味着,如果你的字符串中间意外地出现了一个 16#00(即 \0 的十六进制表示),StrLenA 就会认为字符串在这里结束了,返回的长度就会比实际短。所以,确保你的长字符串数据里不包含非预期的零值,是很重要的。下面是一个对比示例:
PROGRAM PLC_PRG
VAR
strShort: STRING := 'Hello World';
strLong: STRING(1000) := 'A very long string...'; // 假设这里有很多字符
nShortLen: INT;
nLongLenBasic: INT; // 用基本LEN函数
nLongLenReal: DINT; // 用StrLenA
END_VAR
nShortLen := LEN(strShort); // 正确,返


被折叠的 条评论
为什么被折叠?



