上个月接了个活,客户要求把一台西门子S7-1200和三菱FX5U连起来做数据交换。说简单也简单,两台PLC之间传几个温度值、设备状态和产量数据。说难也难,西门子走的是Profinet协议,三菱走的是CC-Link IE Field,这两个协议八竿子打不着。
客户是个食品厂的设备主管,姓刘,跟我合作好几年了。刘工在电话里说:”张工,我们新上了条生产线,旧设备是三菱的,新设备是西门子的,你帮我把它们打通,数据要能互相传。”我一听就知道,这事得用Modbus TCP来做”翻译”——两个协议虽然不通,但都支持Modbus TCP,这是个对双方都友好的中间协议。
想法很简单,但真正动手的时候,我踩了整整两天的坑。今天把这些坑写出来,兄弟们以后再遇到类似情况,能省不少时间。
第一个坑:西门子的数据区偏移量
我先从西门子这边下手。S7-1200做Modbus TCP服务器,这个在TIA Portal里配置不算复杂。调用MB_SERVER指令,设置端口502,连上就行。我花了一个小时把西门子这边的从站配好了,用Modscan软件测试,通讯正常,能读到数据。
问题出在数据映射上。西门子的Modbus地址映射有自己的规则:%DB1.DBW0对应Modbus地址40001,%DB1.DBW2对应40002,以此类推。这个规则我本来是知道的,但三菱那边做客户端的时候,读到的数据老是对不上。
查了半天才找到原因:西门子的MW(字)地址在Modbus映射的时候,如果用了M区而不是DB区,地址对应关系完全不一样。M区从M0.0开始,对应Modbus地址从00001开始(线圈区),而不是我想要的保持寄存器区。这是一个非常容易搞混的地方,我一不小心就栽了。
解决方法:统一用DB数据块来做Modbus映射,不要在M区和DB区之间混用。我在S7-1200里专门建了一个”Modbus_Data”数据块,所有要交换的数据都放在这个DB里,地址对应关系一目了然。
第二个坑:三菱的寄存器地址映射
西门子那边搞定了,轮到三菱FX5U做Modbus TCP客户端。三菱的GX Works3里配置Modbus TCP比西门子要麻烦一些,需要先建一个”以太网配置”,然后在”连接设备”里添加Modbus TCP连接。
最大的坑来了:三菱的Modbus地址跟西门子的地址对应关系不是完全一一对应的。比如三菱自己内部的D0,做Modbus从站的时候默认对应40001,但如果你做的是Modbus主站去读别人,那地址就完全由你自己编程定义了。
我一开始用SP.SOCCSET指令配了连接,然后用SP.ECPRTCL指令来发Modbus请求。按照手册上的示例写了读保持寄存器的请求帧:
发送帧: 01 03 00 00 00 0A C5 CD
这个帧的意思是:站地址1,功能码03(读保持寄存器),起始地址0000(即40001),读10个寄存器。正常来说,西门子那边应该返回10个寄存器的数据。
结果返回的全是0。反复检查了接线、IP地址、端口号,都没问题。我又用Modscan模拟Modbus服务器测试,三菱这边能读到数据。那就说明问题出在西门子和三菱之间的配合上。
最终发现:西门子MB_SERVER指令的MB_HOLD_REG引脚,默认指向的是一个系统自带的Modbus保持寄存器区域,不是我自己建的DB数据块。我在TIA Portal里忘记把MB_HOLD_REG引脚关联到我自己建的”Modbus_Data”数据块了!程序编译没问题,但数据根本就没存到我期望的地方。
把这个引脚重新关联后,三菱这边一下就读到数据了。当时那个心情啊,又高兴又憋屈——一个小疏忽,浪费了我大半天。
第三个坑:数据类型的匹配问题
数据能读了,新的问题又来了。西门子传过来的温度值是32位浮点数(REAL类型),三菱这边用D寄存器来接收,D寄存器是16位整数。一个REAL需要两个D寄存器来存,但三菱在读回来的时候,如果不对数据类型做处理,读到的就是两个莫名其妙的大整数。
这个问题说大不大,说小不小。解决方法是三菱这边用DMOV指令把连续的两个D寄存器数据搬运到32位浮点数变量里。或者更简单一点,在西门子那边就把浮点数拆成两个16位整数再传——但我建议还是保留原始数据类型,在接收端做转换,这样精度不会有损失。
还有一个细节:西门子的REAL字节序是”大端模式”(高字节在前),三菱默认也是大端,所以不需要额外做字节交换。但如果你的设备是”小端模式”,比如某些Modbus网关,那就需要在程序里做SWAP处理。这个也得注意。
最终方案:搞了一个通用数据映射表
折腾了两天终于搞通了,我怕以后再遇到类似项目又要重新踩坑,就做了个标准的数据映射表,给大家参考:
Modbus TCP通用映射规则:
40001~40010:浮点数区(西门子REAL ↔ 三菱双字D连续区)
40011~40020:整数区(西门子INT ↔ 三菱单字D)
40021~40030:开关量状态区(WORD按位解析)
40031~40040:控制命令区(WORD按位写入控制命令)
以后不管什么品牌的PLC做Modbus TCP通讯,我都按照这个映射表来分配地址,双方工程人员一看就明白,不用反复确认。我把这个表发给刘工,他说”早该有这种东西了”。
写在最后
西门子和三菱互相通讯这件事,在工控行业太常见了。国产化替代的大趋势下,不同品牌、不同协议的设备混用会越来越多。我的经验是:Modbus TCP是”通用语言”,基本上所有主流PLC都支持。但是每个品牌的实现细节都不一样,特别是地址映射规则和数据类型的匹配,这些地方最容易踩坑。
兄弟们,你们在做不同品牌PLC通讯的时候,有没有遇到过什么奇葩问题?欢迎在评论区说说,咱们一起总结一本”工控踩坑大全”。