干了这么多年自动化,我越来越觉得,PLC和HMI之间的通信配置,才是项目里最容易拖工期、也最考验功底的环节。尤其是Codesys平台搭配威纶通触摸屏,两边单独用都挺顺手,一旦要在工程里做几十上百个变量的交互,还按老办法一个地址一个地址手工映射,加班到凌晨真不是开玩笑。之前我接手一个项目就是这种组合,控制器里几百个点位要接到威纶通屏上,还要做结构体数据交互,当时咬着牙把标签通信这条路完整走了一遍,从结构体设计到XML导出再到屏端导入,里面的坑基本都踩了一遍。所以今天想把这套流程里的经验整理出来,包括方案选型怎么定、结构体怎么设计、符号配置怎么弄、XML又是怎么被触摸屏“听懂的”,以及联调阶段会遇到哪些鬼问题。希望能给正在做类似项目的朋友一个参考,省掉一些弯路。
这套方案的关键就三个字:标签化。思路是用Codesys的符号配置功能,把PLC里的结构体变量整体导出成XML格式的文件,威纶通的EB Pro软件直接把这个XML导入,触摸屏就能自动识别PLC里的标签(Tag),随后在画面上直接绑定这些标签,省去手工一个个地址映射的繁琐过程。下面我按实际推进的顺序,把这个思路和细节掰开揉碎讲清楚。
1. 标签通信方案选型:为什么绕开传统变量映射
1.1 传统做法的痛点在哪
如果你做过Codesys和威纶通的通信,一定体会过手动建变量的崩溃感。传统方式下,我们要在PLC端规划好Modbus地址区,把需要交互的变量一个一个映射到保持寄存器或输入寄存器里,然后在威纶通的EB Pro里手动新建对应的地址标签,比如4x0001、3x0002这种东西,再把几百个变量和HMI控件绑定。前期规划地址映射表就要花掉不少时间,一旦中途要加一个变量,或者结构体里的数据类型改了,后面的地址全部要跟着重新编排,接口表来回改,脑袋都要炸掉。
这个过程的问题在于:地址是“人肉翻译”出来的,非常容易出错,而且改动成本极高。现场调试的时候,半夜三点加了两个模拟量,你还要重新算偏移量,再在HMI端手工维护一张毫无规律的地址表,这不叫技术活,叫体力活。
1.2 标签通信到底做了什么
标签通信的思路就直接多了。Codesys的符号配置功能可以把编译后的所有全局变量、结构体实例、甚至任务里的变量,按照标准的符号表格式导出成XML。这个XML文件里记录的不只是变量名,还包含了每个变量的数据类型、存储区域的相对地址偏移、访问路径。威纶通的EB Pro在导入这个XML时,会自动根据这些信息在触摸屏内部生成对应的标签名和内存映射,达到“所见即所得”的效果。
也就是说,原来需要在两端手动约定和维护的地址关系,全部由工具自动完成了。你只需要在PLC里用结构体把变量组织好、导出XML、在EB Pro里导入,剩下的就是画面上绑定标签。中途哪怕增加或删除变量,只要结构体整体重导一次,地址和偏移会自己对应好,基本告别了“接口表维护”这个反人类工作。
1.3 标签通信的适用边界
不过这里必须说清楚,标签通信不是万能的。它最舒服的应用场景是Codesys V3控制器(包括WAGO、Beckhoff的某些型号、汇川H系列等)和威纶通HMI之间的以太网通信。威纶通的EB Pro里目前对CODESYS V3 Ethernet驱动支持得非常成熟,才有这么好的体验。如果你的项目是西门子S7-1200配威纶通,也能做类似操作,但那是另外一套TIA Openness和符号导入的逻辑;如果HMI是昆仑通态,那这套XML导入方案基本用不上,还是老老实实走寄存器映射。
所以选型的时候别盲目套用。这套方案最划算的时机是:项目变量多(比如超过三十个)、后续可能有变动、现场有以太网条件。如果就五六个点位,手工映射反而更快,没必要为了“先进”而先进。
2. 结构体设计:通信质量的决定性一环
2.1 先想清楚再编码,否则后面全是坑
既然标签通信帮我们去掉了地址映射的脏活,那么真正决定通信体验的,就变成了PLC端怎么组织这些变量。我强烈建议用结构体(STRUCT)来打包业务相关的数据,而不是散落一堆全局变量。道理很简单:结构体是逻辑聚类,导出XML后,触摸屏端看到的标签会自动带有层级前缀,比如Axis1.Position、Axis1.Enable,一看就知道归属。如果都是Var1、Var2这种散装变量,导出来的标签表就是一团乱麻,HMI端维护起来照样痛苦。
结构体还有一个很实用的价值:它天然适合做整块数据同步。比如你要在HMI上做一个轴控页面,那这个轴的所有状态、给定值、报警码都打包在一个结构体里,通信时按块读取的效率远高于一个个零散变量。这种“物以类聚”的思路,不仅让代码更干净,也让通信性能更好。
2.2 一个可以直接抄的轴控结构体
我在做项目时常用的一种结构体设计思路,是以功能块为单位组织数据。比如一个伺服轴需要交互的数据,我通常这样定义:
TYPE ST_AxisData : STRUCT bEnable : BOOL; // 使能信号 bAlarm : BOOL; // 报警状态 nState : INT; // 轴当前状态码 rPosition : REAL; // 实际位置 rVelocity : REAL; // 实际速度 rTorque : REAL; // 实际扭矩 rTargetPos : REAL; // 目标位置 nErrorCode : WORD; // 故障代码 END_STRUCT END_TYPE定义好结构体类型以后,在主程序里声明一个全局变量实例:
VAR_GLOBAL Axis1 : ST_AxisData; Axis2 : ST_AxisData; END_VAR这样在HMI端导入XML后,你会看到Axis1.bEnable、Axis1.rPosition这类非常有规律的标签列表。这里我特别建议把布尔量放在结构体前部,因为它单个只占一个字节,放在开头便于字节对齐计算,后面连续放REAL、INT这类多字节数据的时候不会出现意外错位。关于对齐的坑,后面专门说。
2.3 数据类型匹配与字节对齐
结构体里的数据类型选择,直接决定HMI能不能正确识别。威纶通HMI对REAL(单精度浮点)支持得非常好,对LREAL(双精度浮点)的支持就比较弱。之前我把一个高精度温度变量定义成LREAL,导到触摸屏上显示出来全是#BAD,折腾了很久才发现是精度类型不支持。所以给HMI交互的数据,能不用LREAL就不用,实在要高精度,可以拆成两个DINT或者用放大系数转成DINT在HMI端还原。
字节对齐是另一个容易踩坑的地方。Codesys编译器默认遵循IEC 61131-3的规则,结构体成员之间会有填充字节。一个典型的坑是:结构体里如果写完一个REAL(4字节)后接着写一个BOOL(1字节),再写一个INT(2字节),实际占用的内存不是简单的4+1+2=7字节,而是8字节,因为编译器会在BOOL后填充一个空字节,让INT从偶数偏移量开始。这意味着如果你在HMI端试图通过计算偏移来手工访问某个成员,很可能算错位置。而标签通信的厉害之处就在于它自动处理了这个对齐关系,所有成员地址偏移量都记录在XML里。所以这里其实只有一个要求:你设计的结构体,导出成什么就是什么,不要在HMI端自己去猜偏移量,所有问题都交给XML和标签导入去解决。
3. Codesys符号配置与XML导出:核心环节的完整操作
3.1 打开符号配置的正确方式
这里要特意说明,直接在Codesys里点击项目树,其实没有“导出XML”这个按钮。我们用的功能叫符号配置(Symbol Configuration),它在应用程序节点右键菜单里。如果你用的是Codesys 3.5 SP18以上的版本,符号配置已经集成到“Application”节点下,右键点击Application,选择“符号配置”,会自动打开一个独立的编辑器页面。
打开之后,左侧是当前应用的所有POU、全局变量表、结构体等元素,默认可能都没被勾选。核心操作是:把要通信的全局变量组(通常是把包含结构体实例的全局变量表)全部勾上,然后看一眼Compiler选项里的“支持OPC UA特性”和“支持IEC 61131-3第三版特性”。这两个选项一开始我不太理解,后来实验发现,威纶通导入XML时对标准的兼容性更好,建议都勾选上。勾选完毕后需要重新编译整个工程,符号表才会生成。
3.2 编译导出与XML落盘位置
编译的时候,很多人误以为编译通过就万事大吉,结果去工程目录里翻半天找不到XML文件。实际上,XML文件会生成在工程目录下的一个固定路径,通常是项目文件夹里的plc目录下,文件名为项目名加后缀。如果你用的是Codesys安装目录里的默认工程路径,可以打开工程后右键Application选“编译”,然后在“工程”菜单里点击“创建启动项目相关文件”,或者在编译日志里看输出路径,这样找起来更准确。
保险的做法是:在符号配置界面左侧勾选完变量后,直接Ctrl+F7编译,编译成功的日志里会显示XML输出位置,例如C:\Users\xxx\Codesys Projects\MyProject\plc\MyProject.compiled.xml。拿到这个文件后,我习惯把它复制到项目资料目录里,因为它就是要交给HMI工程师的“通信名片”。数据规模比较大时,这个XML可能达到几MB,千万别用记事本直接硬开,后面我会说怎么处理这种大文件。
3.3 读懂XML标签结构
拿到XML文件后,即使你不做电气工程师,也应该能大概看懂里面的结构。这里我强烈建议用支持树形折叠的编辑器,比如VS Code或者Notepad++打开,一套典型的标签结构是这个样子的:
<Tags> <Tag Name="Axis1.bEnable" Address="%Q*0.1.2.4.1" DataType="BOOL" /> <Tag Name="Axis1.nState" Address="%Q*0.1.2.6.1" DataType="INT" /> <Tag Name="Axis1.rPosition" Address="%Q*0.1.2.8.1" DataType="REAL" /> <Tag Name="Axis1.rVelocity" Address="%Q*0.1.2.12.1" DataType="REAL" /> </Tags>可能不同的Codesys版本生成的标签结构字段名略有差异,关键是看懂两部分:Name是变量在PLC中的完整路径名,Address里的串就是它在该符号表体系下的内存地址描述符。这个地址串你不需要手动去解析,也不用在HMI端重新输入,EB Pro导入时会直接读取。但理解它有个好处:一旦通信不上、数据错乱,你可以拿这个地址串去和PLC调试窗口里的Memory Address对照,快速定位是哪一个环节出了问题。
3.4 修改PLC IP地址的常见操作
这一节本来不在计划内,但搜索热词里很多人都在问“Codesys修改PLC IP”,实际联调时也绕不开这个问题。标签通信是纯以太网通信,如果PLC和控制器的IP不在一个网段,HMI是无论如何也读不到数据的。在Codesys里修改IP的方式取决于控制器型号,通用做法是:在线(Online)模式下,点击顶部菜单“通讯设置”,找到活动连接,双击打开“通道设置”,里面有IP地址的自定义配置项。如果是现场临时修改,我更推荐直接在设备树里选中Ethernet接口,右键编辑,把静态IP改到和HMI同一网段,然后给PLC断电重启。这里有个细节:改完IP后必须重新激活应用,否则控制器内部的应用仍然在旧IP上监听服务。
4. 威纶通EB Pro导入XML与画面绑定
4.1 新建设备与导入标签
威纶通这边用的软件是EB Pro(现在叫EasyBuilder Pro)。新建工程后,首先要做的是在系统参数里新增设备。这里有个很容易选错的地方:通信驱动要选“CODESYS V3 Ethernet”,不是“Modbus TCP”,也不是“CODESYS V2”。很多朋友上来就选Modbus地址,后面就发现根本没有标签导入的入口,实际上选错驱动程序是一切的根源。
选对驱动后,会弹出以太网配置页面,填入PLC的IP地址。端口号一般保持默认,不要乱改,除非Codesys端做了特殊设置。填写好IP地址后,在设备属性中找到“标签”标签页,点击“从文件导入”,选择前面导出的XML文件。此时EB Pro会解析这个XML,并在标签表里生成对应条目。导入完成后,你会在该设备下的标签列表中看到诸如Axis1.rPosition这类完整路径的标签。此时可以先点击“测试”按钮,软件会自动尝试与PLC建立连接,如果通信成功,标签旁边会显示正常状态。
4.2 画面绑定与地址校验
接下来就进入画面设计阶段了。比如你要在HMI上做一个速度设定框,把数值输入控件拖到画面中,在“读取地址”里选择设备标签,找到Axis1.rVelocity;想做一个使能按钮,就往按钮控件里绑定Axis1.bEnable。这种绑定方式比手工填写寄存器地址直观太多,而且由于标签名和PLC端变量路径完全一致,后期维护代码时,打开HMI画面就能一眼看出这个控件连的是哪个PLC数据,不需要再翻接口表。
校验的时候,我习惯先在HMI的数值显示控件里临时显示几个关键标签,如果显示数值和PLC里的监控值一致,说明通信链路正常。还要注意一下字节顺序(Endian)的问题。威纶通默认的字节顺序通常是“低字节在前”,而Codesys的REAL存储有时会让人困惑。如果导入标签后数值显示不合理(比如把101.5显示成一个极大的数或者颠倒的乱数),多半是字节顺序没有配对。在EB Pro设备属性的“高级设置”里,可以切换字节顺序选项,试试看能不能恢复正常。
4.3 通信性能调优
标签通信虽然方便,但如果画面上的标签很多,且每个标签都独立频繁刷新,通信负载会直线上升。一个实际的例子:有一次我在画面上放了40多个趋势曲线变量,每个变量每秒要求刷新多次,结果触摸屏和PLC之间的通信延迟飙升,整个画面操作卡顿明显。
优化手段有两板斧。第一板斧是使用“区块读取”机制,EB Pro驱动本身会自动把地址连续的标签合并成批次读取,所以设计PLC变量时尽量把经常一起刷新的数据连续排列在结构体里,这样驱动合并效率最高。第二板斧是降低刷新频率,对于状态显示类标签,1秒刷新绰绰有余;设定值类标签,只有画面打开时才需要读取;只有趋势曲线和报警等实时性要求极高的数据才需要短周期刷新。在EB Pro的标签属性里可以对应调整采集周期。实测下来,同样一百多个标签,优化前后CPU占用能差出一倍。
5. 实战踩坑:常见问题与排查技巧实录
5.1 问题排查速查表
这里我把联调中遇到频率最高的问题整理成了表格,方便你对照排查:
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| HMI上所有标签显示#BAD | PLC IP配置错误或设备驱动选错 | 确认HMI和PLC网络连通,ping通IP;检查设备驱动是否为CODESYS V3 Ethernet |
| 导入XML后标签列表为空 | XML文件没有正确生成,或符号配置未勾选变量 | 回Codesys检查符号配置勾选项,重新编译;确认XML文件内有Tag节点 |
| 数值能读到但明显错乱 | 字节顺序(Endian)不匹配 | 在EB Pro高级属性中切换字节顺序选项 |
| LREAL变量显示异常 | 触摸屏不支持LREAL类型 | 改用REAL,或拆成两个DINT传输 |
| 结构体新增成员后HMI端没反应 | 没有重新导出XML或没有重新导入 | 重新编译PLC工程,重新导出XML,在EB Pro里再次导入覆盖 |
| 通信偶发掉线/慢 | 变量刷新频率过高、以太网不稳定 | 调整标签采集周期;检查网络交换机质量,必要时直连网线测试 |
5.2 几个值得长期收藏的避坑技巧
几个心得,都是拿时间换来的,希望你能直接受益。
第一,变量命名要有强约束力。XML导入后所有标签完全跟随PLC变量名,所以千万不要在结构体里写a1、b2这种缩写,后期维护会逼疯自己。我现在的习惯是:全局变量用大驼峰,结构体成员用小驼峰,布尔量用b开头,数值用r开头,一眼就能分辨类型和用途。这样HMI工程师拿到XML文件时,不用看PLC程序也能知道每个标签的大致含义。
第二,结构体里的成员顺序会影响通信效率,但真正影响调试体验的是它会影响XML里的地址连续区。如果你有几个需要画曲线、需要高刷新率的变量,请把它们连续放置,例如放在结构体的中间连续区域。这样EB Pro驱动自动合并区块的时候,能精准命中那一段连续地址,刷新效率和稳定性都要好很多。
第三,每次修改PLC结构体后,一定要回到EB Pro里重新导入一次XML,千万不要觉得只是加了一个成员、地址没变就不管了。事实是,结构体内一旦插入新成员,后面的所有变量偏移量都会变,HMI端还保留旧标签地址的话,数据就会整体错位。我一开始就吃过这个亏:在结构体中间加了一个BOOL量,结果后面十几个REAL数值全部错乱,排查了半天才发现是没重新导入XML。
第四,联调之前,先给PLC写一个心跳变量,做成一个周期递增的INT,并在HMI画面上用一个小数字框显示它。这个心跳变量成本极低,但价值极高:现场通信出问题时,你第一眼就能判断是链路断了、PLC死机了还是HMI卡堵了,不必靠猜。这条经验在大小项目里都救过我很多次。
最后再分享一个小技巧。如果你手里的项目是Codesys V3高版本(比如SP18以上),记得在符号配置里打开“支持OPC UA特性”这个选项。一开始我以为这只是给OPC UA服务器用的,跟HMI导入无关,后来无意中发现打开它之后,威纶通导入XML的成功率和标签兼容性明显提升。原理上讲,这个选项会让符号表生成时附带更完整的数据类型描述信息,HMI端解析起来更从容。如果你遇到反复导入失败的情况,不妨回Codesys勾上这个选项再编译试试。
整体上,从结构体设计、符号配置、XML生成,到威纶通EB Pro导入标签、画面绑定、联调排查,这条链路一旦跑通,后续再做类似项目会非常省心。现在我做Codesys加威纶通的项目,基本能保证半天之内把全部通信打通,剩下的时间全用来做画面逻辑和调试,这才是这套方案真正的价值所在。