1. 项目缘起:为什么要在S7-1200和三菱Q系列之间做开放式以太网通信
1.1 一个真实到让人头疼的现场需求
前阵子接了个改造项目,现场情况是这样的:主控用的是西门子S7-1200,负责整线的逻辑控制和数据采集;旁边一台老设备上跑着三菱Q系列PLC,管着一套伺服定位机构,型号是QD77MS2配MR-J4-20B伺服放大器。甲方要求把三菱那边的实时位置、报警状态、生产计数全部汇总到S7-1200里,再由S7-1200统一上传到上位机。
问题来了——这两家PLC原生协议完全不搭边。西门子走的是S7通信或者开放式用户通信,三菱Q系列有自己的MC协议和固定缓冲通信。你要硬上,就得加网关模块,成本高、周期长,还得改柜子。但现场有个现成条件:两台PLC都带以太网口,而且都在同一个局域网段里。这就给了我们一个非常务实的方案——用开放式以太网通信,也就是基于TCP/IP的Socket通信,让两边直接对话。
这个方案的核心思路很简单:把S7-1200当客户端,三菱Q系列当服务端,通过TCP连接交换数据。S7-1200这边用TSEND_C和TRCV_C指令,三菱那边用内置以太网端口的Socket通信功能。不需要任何额外硬件,不需要网关,只要网络通,数据就能跑起来。
1.2 开放式以太网通信到底是个什么东西
很多刚入行的朋友听到“开放式以太网通信”这个词会觉得玄乎,其实说白了就是PLC自己写Socket程序。你不需要依赖任何厂商的专有协议栈,直接调用PLC提供的通信指令,建立TCP连接,然后收发原始字节流。
打个比方:S7通信和MC协议就像是两家公司各自内部的“方言”,外人听不懂;而开放式以太网通信就像是双方约定说“普通话”——TCP/IP就是这套普通话的语法,至于传输的内容是什么格式,完全由你自己定义。你可以传字符串、传结构体、传二进制数据,只要两边约定好解析规则就行。
S7-1200这边,开放式通信靠的是TSEND_C(建立连接并发送)和TRCV_C(接收数据)这两个指令,它们属于“开放式用户通信”指令集。三菱Q系列这边,用的是内置以太网端口的Socket通信功能,通过GX Works2里的“内置以太网端口设置”来配置,然后用专用的通信指令(比如SP.SOCOPEN、SP.SOCSND、SP.SOCRCV)来操作。
1.3 这个方案适合谁、不适合谁
先说适合的场景:两台PLC在同一个局域网内,数据量不大(几十到几百字节),实时性要求不是特别苛刻(几十毫秒到几百毫秒的周期),预算有限不想加网关。这种条件下,开放式以太网通信是最经济实惠的选择。
不适合的场景也得说清楚:如果数据量特别大(比如几KB以上的连续数据流),或者要求毫秒级硬实时,那还是老老实实上Profinet或者加专用网关。另外,如果两边不在同一网段,中间隔着路由器或者防火墙,配置会复杂很多,需要额外处理端口映射和访问规则。
还有一个容易被忽略的点:开放式以太网通信是“裸”通信,没有协议层的校验和重传机制。TCP本身保证了数据可靠性,但应用层的数据解析完全靠你自己。如果发送方和接收方的字节序、数据类型对不上,收到的就是一堆乱码。所以后面我会重点讲数据格式的约定和转换。
2. 方案设计与核心思路拆解
2.1 为什么选TCP而不是UDP
开放式以太网通信支持TCP和UDP两种传输层协议。这个项目里我选的是TCP,原因有三条。
第一,TCP是面向连接的,通信前必须建立连接,连接断了能立刻发现。UDP是无连接的,发出去就不管了,丢包了也不知道。对于生产数据采集来说,丢一个报警信号可能就是一次事故。
第二,TCP有重传机制,网络抖动导致丢包会自动重发。UDP没有这个保障,虽然速度快,但可靠性差。我们这个场景数据量不大,TCP的开销完全可以接受。
第三,三菱Q系列的内置以太网Socket通信对TCP的支持更成熟,配置起来也更直观。UDP虽然也能用,但在数据完整性要求高的场合,TCP是更稳妥的选择。
2.2 客户端和服务端的角色分配
谁当客户端、谁当服务端,这个选择很关键。我的分配是:S7-1200做客户端,三菱Q系列做服务端。
理由是这样的:S7-1200的TSEND_C指令本身就支持主动建立连接,配置起来很方便,在OB1里调用就行。三菱Q系列这边,用SP.SOCOPEN指令打开端口后被动等待连接,逻辑更简单,不需要处理重连的复杂逻辑。而且三菱Q系列作为老设备,让它安安静静当个“数据提供方”更符合现场实际情况——它的主要任务是控制伺服,通信只是附加功能,不应该占用太多扫描周期。
还有一个实际考虑:如果三菱那边当客户端,一旦网络波动断线,它需要主动重连,而三菱的重连逻辑写起来比较绕。反过来S7-1200当客户端,断线重连用TSEND_C的CONT参数和DONE/ERROR状态位就能搞定,代码更干净。
2.3 数据帧格式的约定
这是整个方案里最需要动脑筋的地方。两边PLC的数据类型和字节序不一样,必须提前约定好一套“翻译规则”。
我的做法是定义一个固定长度的数据帧,比如32字节。前2字节是帧头(比如0xAA55),用来做同步校验;接下来2字节是数据长度;然后是实际数据区;最后2字节是校验和。这样接收方先找帧头,再读长度,再取数据,最后验校验,一套流程下来数据不会错位。
数据区里怎么放?S7-1200这边用DB块定义结构体,三菱那边用D寄存器或者M寄存器映射。比如:
| 数据内容 | S7-1200地址 | 三菱地址 | 数据类型 | 字节数 |
|---|---|---|---|---|
| 当前位置 | DB1.DBD0 | D100-D101 | REAL | 4 |
| 报警状态 | DB1.DBW4 | D102 | INT | 2 |
| 生产计数 | DB1.DBD6 | D103-D104 | DINT | 4 |
| 设备状态 | DB1.DBB10 | D105 | BYTE | 1 |
这里有个大坑:西门子的REAL是IEEE 754标准浮点数,三菱的浮点数也是IEEE 754,但字节序可能不同。西门子是高字节在前(大端),三菱Q系列默认也是大端,但有些情况下D寄存器的排列方式会导致字节顺序看起来是反的。实际调试时一定要用在线监控对比两边数值,确认字节序一致。
2.4 通信周期的设定
通信周期设多少合适?这个要根据实际需求来。我的经验是:不要低于50ms,建议100ms左右。
为什么不能太快?因为S7-1200的TSEND_C和TRCV_C是异步指令,每次调用需要几个扫描周期才能完成。如果你在OB1里每个周期都调用,可能会因为上一次还没完成而导致错误。正确的做法是放在一个定时中断OB里,比如OB35,设置100ms的循环周期。
三菱那边也一样,SP.SOCRCV指令需要时间处理,太快了会丢包。而且三菱Q系列的扫描周期本身就有几毫秒到十几毫秒,通信太频繁会影响伺服控制的实时性。
100ms的周期意味着每秒交换10次数据,对于位置监控和状态采集来说完全够用。如果确实需要更快,可以降到50ms,但再低就不建议了。
3. 核心细节解析与实操要点
3.1 S7-1200侧的硬件组态和连接配置
先在博途里把S7-1200的硬件组态做好。CPU的以太网口要设置IP地址,比如192.168.1.10,子网掩码255.255.255.0。三菱Q系列的以太网口设成192.168.1.20,同一网段。
然后在博途里新建一个全局DB块,专门用来存放通信数据。这个DB块要取消“优化的块访问”,因为TSEND_C和TRCV_C需要绝对地址访问。在DB块属性里把“优化的块访问”勾去掉,然后手动定义变量和偏移量。
接下来配置TSEND_C指令。在OB1或者OB35里拖入TSEND_C,它会自动弹出一个对话框让你创建连接。选择“TCP”协议,连接类型选“主动连接”,然后填三菱那边的IP地址和端口号。端口号我一般用2000以上的,比如5000,避免和系统端口冲突。
TSEND_C的关键参数:
- REQ:上升沿触发发送,用一个时钟脉冲或者手动触发
- CONT:保持连接,设为TRUE表示连接断开后自动重连
- CONNECT:连接描述,由系统自动生成
- DATA:要发送的数据区,指向DB块的起始地址
- LEN:发送长度,单位是字节
TRCV_C的参数类似,但多了几个:
- EN_R:接收使能,设为TRUE持续接收
- DATA:接收缓冲区
- LEN:接收长度
- RCVD_LEN:实际接收到的字节数
注意:TSEND_C和TRCV_C不能同时用同一个连接ID,需要分别建立两个连接,一个用于发送,一个用于接收。或者用TSEND和TRCV配合TCON来手动管理连接。
3.2 三菱Q系列的内置以太网端口设置
三菱这边在GX Works2里操作。打开“PLC参数”,找到“内置以太网端口设置”,然后选“打开设置”。
这里要配置几项关键内容:
- 协议:选TCP
- 打开方式:选“Unpassive”或者“Fullpassive”,意思是被动等待连接
- 本地端口号:填5000,和西门子那边对应
- 对方IP地址:可以不填,或者填西门子的IP做限制
然后设置“初始设置”,把通信超时时间设长一点,比如10秒,避免网络抖动导致断线。
三菱的Socket通信指令在程序里这样用:
// 打开连接 SP.SOCOPEN U0 K1 D100 M100 // 接收数据 SP.SOCRCV U0 K1 D200 K32 M110 // 发送数据 SP.SOCSND U0 K1 D300 K32 M120 // 关闭连接 SP.SOCCLOSE U0 K1 M130U0表示内置以太网端口,K1表示连接编号,D100开始是控制数据区,M100是完成标志位。
实操心得:三菱的SP.SOCRCV指令是异步的,调用后要等M110置位才能读数据。如果连续调用而不检查完成标志,会报“指令未完成”错误。我一般用步进梯形图或者状态机来管理这些指令的调用顺序。
3.3 数据格式转换的实操细节
前面说了数据帧格式,现在讲具体怎么转换。
西门子这边,发送前要把数据打包成字节数组。比如要发送一个REAL类型的当前位置值,在DB块里它占4个字节。你可以用MOVE指令把REAL值移到DBD0,然后TSEND_C直接发DBB0到DBB3这4个字节。
三菱那边收到后,把这4个字节存到D100和D101里。但三菱的D寄存器是16位的,一个REAL需要两个连续的D寄存器。读取的时候用DMOV指令把D100和D101组合成一个32位数据,再用EBCD或者DECO指令转换成浮点数。
反过来,三菱发数据给西门子也一样。三菱把REAL值存到D100和D101,然后SP.SOCSND发送这4个字节。西门子收到后存到DBD0,直接用REAL格式读取。
这里有个字节序的坑:西门子的REAL在内存里是高字节在前,三菱的32位数据在D寄存器里也是高字在前,但两个16位寄存器的顺序可能是反的。实际调试时,如果读出来的浮点数明显不对(比如变成极小值或者极大值),就把两个D寄存器的顺序换一下,或者用SWAP指令交换字节。
3.4 通信中断的处理策略
网络通信最怕的就是断线。我的处理策略是三层防护:
第一层,TSEND_C的CONT参数设为TRUE,断线后自动重连。但自动重连不是万能的,有时候需要手动触发。
第二层,在程序里监控TSEND_C和TRCV_C的ERROR位。一旦ERROR置位,记录错误代码,然后延时一段时间后重新触发REQ。
第三层,加一个心跳机制。西门子每秒钟发一个心跳包,三菱收到后回一个应答。如果连续3秒没收到应答,就判断通信故障,触发报警。
三菱那边也一样,SP.SOCRCV如果超时没收到数据,会置位错误标志。我在程序里加了个定时器,如果接收完成标志超过500ms没置位,就重新调用SP.SOCOPEN。
常见问题:三菱Q系列的SP.SOCOPEN指令在连接已打开的情况下重复调用会报错。所以重新打开之前,必须先调用SP.SOCCLOSE关闭连接。这个逻辑要用状态机来管理,不能简单粗暴地反复调用。
4. 完整实操流程与核心环节实现
4.1 网络硬件连接和IP规划
先做物理连接。两台PLC的以太网口用网线连到同一台交换机上。如果只有两台设备,也可以直接用交叉网线对接,但现在大多数交换机都支持自动翻转,用直通线也行。
IP规划如下:
| 设备 | IP地址 | 子网掩码 | 端口号 |
|---|---|---|---|
| S7-1200 | 192.168.1.10 | 255.255.255.0 | 5000(客户端) |
| 三菱Q系列 | 192.168.1.20 | 255.255.255.0 | 5000(服务端) |
在电脑上先ping一下两个IP,确认网络通。如果ping不通,检查网线、交换机、IP设置。这一步看似简单,但现场很多问题都出在这里。
4.2 西门子侧程序编写步骤
第一步,新建DB块“CommData”,取消优化访问。定义以下变量:
SendData : Array[0..31] of Byte; // 发送缓冲区 RecvData : Array[0..31] of Byte; // 接收缓冲区 SendLen : Int; // 发送长度 RecvLen : Int; // 接收长度第二步,在OB35里调用TSEND_C。OB35的循环周期设为100ms。
TSEND_C_Instance( REQ := SendTrigger, CONT := TRUE, DATA := P#DB1.DBX0.0 BYTE 32, LEN := 32, DONE => SendDone, ERROR => SendError, STATUS => SendStatus );第三步,调用TRCV_C。
TRCV_C_Instance( EN_R := TRUE, CONT := TRUE, DATA := P#DB1.DBX32.0 BYTE 32, LEN := 32, RCVD_LEN => RecvLen, DONE => RecvDone, ERROR => RecvError, STATUS => RecvStatus );第四步,写数据打包逻辑。把需要发送的数据从其他DB块MOVE到CommData.SendData里。注意字节序和数据类型转换。
第五步,写数据解析逻辑。从CommData.RecvData里提取数据,MOVE到对应的变量里。
4.3 三菱侧程序编写步骤
第一步,在GX Works2里设置内置以太网端口参数。打开设置里选TCP,端口号5000,打开方式选“Fullpassive”。
第二步,写通信主程序。用一个状态机管理:
// 状态0:初始状态,打开连接 // 状态1:连接已打开,等待接收 // 状态2:接收完成,处理数据 // 状态3:发送数据 // 状态4:错误处理,关闭连接后重试第三步,调用SP.SOCOPEN打开连接。
SP.SOCOPEN U0 K1 D100 M100D100开始的控制数据区要设置好,包括IP地址、端口号等参数。
第四步,调用SP.SOCRCV接收数据。
SP.SOCRCV U0 K1 D200 K32 M110第五步,数据解析。把D200开始的32字节数据按约定格式解析,存到对应的D寄存器和M寄存器里。
第六步,调用SP.SOCSND发送数据。
SP.SOCSND U0 K1 D300 K32 M1204.4 联调步骤和验证方法
联调分三步走。
第一步,先验证网络层。用电脑ping两个PLC的IP,确认网络通。然后用网络调试助手模拟服务端,测试西门子能否正常连接和收发数据。
第二步,验证三菱侧。用网络调试助手模拟客户端,连接三菱的5000端口,手动发送测试数据,看三菱能否正确接收和解析。
第三步,两边对接。先发固定测试数据,比如全0或者全1,用在线监控看两边数据是否一致。然后发实际数据,对比数值是否正确。
实操心得:联调时一定要用Wireshark抓包。很多时候程序逻辑没问题,但数据就是不对,抓包一看发现是字节序反了,或者帧头对不上。Wireshark能直接看到原始字节流,比在线监控直观得多。
4.5 参数计算与选择过程
通信周期100ms是怎么算出来的?假设S7-1200的扫描周期是5ms,TSEND_C执行一次需要3-5个扫描周期,也就是15-25ms。TRCV_C类似。加上三菱那边的处理时间,一个完整的收发周期大约需要50-80ms。设100ms留有余量,确保不会因为上一次没完成而导致错误。
数据帧长度32字节是怎么定的?根据实际数据量来。当前位置4字节,报警状态2字节,生产计数4字节,设备状态1字节,加上帧头2字节、长度2字节、校验2字节,总共17字节。取32字节是为了对齐和留扩展空间。
端口号5000是怎么选的?1024以下的端口是系统保留端口,不建议用。5000以上的端口一般不会被占用。我习惯用5000-5100这个范围,方便记忆和管理。
5. 常见问题与排查技巧实录
5.1 连接建立失败怎么办
这是最常见的问题。排查顺序如下:
先检查IP地址和端口号是否填对。西门子那边TSEND_C的CONNECT参数里,远程IP和端口必须和三菱的设置完全一致。
再检查三菱的打开设置。打开方式必须是“Fullpassive”或“Unpassive”,不能选“Active”。如果选错了,两边都在主动连接,就连不上。
然后检查防火墙。有些交换机或者工控机自带防火墙,会拦截5000端口的TCP连接。临时关闭防火墙测试一下。
最后检查连接资源。S7-1200的开放式通信连接数有限制,最多8个。如果之前建立的连接没释放,新的连接就建不起来。在博途的“在线和诊断”里看连接资源占用情况。
5.2 数据收发不正常怎么排查
数据不对,先分清楚是“收不到”还是“收到了但解析错”。
收不到:看TRCV_C的RCVD_LEN是否为0。如果是0,说明没收到数据。检查三菱那边SP.SOCSND是否执行成功,M120是否置位。
收到了但解析错:用Wireshark抓包,对比发送和接收的原始字节。重点看字节序、数据类型长度、帧头位置。
数据错位:最常见的原因是发送长度和接收长度不一致。比如发送方发了32字节,接收方只收了16字节,后面的数据就丢了。确保两边LEN参数一致。
5.3 通信断线重连的处理
断线是不可避免的,关键是怎么快速恢复。
西门子这边,TSEND_C的CONT设为TRUE后,断线会自动重连。但有时候自动重连会卡住,需要手动干预。我的做法是加一个定时器,如果ERROR位持续置位超过5秒,就手动复位REQ,重新触发连接。
三菱这边,SP.SOCOPEN失败后要先调用SP.SOCCLOSE,等100ms后再重新打开。不能连续调用SP.SOCOPEN,否则会报“端口已打开”错误。
避坑技巧:三菱的SP.SOCRCV指令在连接断开后会一直等待,不会自动返回错误。所以要在程序里加超时判断,如果接收完成标志超过1秒没置位,就强制关闭连接重新打开。
5.4 常见问题速查表
| 问题现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| 连接建立失败 | IP/端口不对 | ping测试、检查配置 | 核对IP和端口号 |
| 连接建立失败 | 打开方式错误 | 检查三菱打开设置 | 改为Fullpassive |
| 收不到数据 | 发送指令未执行 | 检查M120标志位 | 确保SP.SOCSND执行 |
| 数据错位 | 长度不一致 | 对比两边LEN参数 | 统一为32字节 |
| 数据乱码 | 字节序反了 | Wireshark抓包对比 | 交换字节顺序 |
| 频繁断线 | 网络不稳定 | 检查网线和交换机 | 更换网线或交换机 |
| 通信影响伺服 | 周期太短 | 监控扫描周期 | 降低通信频率到100ms |
| 重连失败 | 连接未释放 | 检查连接资源 | 先关闭再重新打开 |
5.5 独家避坑经验分享
第一个坑:博途的TSEND_C和TRCV_C不能共用同一个连接ID。我一开始图省事,想用一个连接同时收发,结果怎么都不行。后来查资料才知道,发送和接收必须分别建立连接,各用各的ID。
第二个坑:三菱的D寄存器地址和西门子的DB块地址不能直接对应。三菱的D100是16位,西门子的DBD0是32位。传输REAL类型数据时,三菱需要两个连续的D寄存器,而且高低字顺序可能和西门子相反。这个必须实际测试确认。
第三个坑:通信程序不要放在OB1里。OB1的扫描周期不固定,有时候快有时候慢,会导致通信时序混乱。放在OB35这种固定循环中断里,周期稳定,通信可靠性高很多。
第四个坑:三菱Q系列的以太网端口设置修改后必须断电重启。我改完参数直接下载程序,怎么都不生效,折腾了半天才发现需要重新上电。这个在手册里没写,是现场踩出来的经验。
第五个坑:网络调试助手是个好东西。联调阶段不要急着两边对接,先用网络调试助手分别测试两边。确认各自都能正常收发后,再对接。这样能把问题范围缩小一半。
6. 通信性能优化与扩展思路
6.1 如何降低通信对PLC扫描周期的影响
开放式以太网通信会占用PLC的CPU资源。如果通信程序写得太重,会影响主程序的执行。优化方法有几个:
把通信程序放在独立的OB里,比如OB35,设置合理的循环周期。不要让通信程序在OB1里每个周期都执行。
减少不必要的数据传输。只传需要的数据,不要传整个DB块。比如只需要当前位置,就只传4个字节,不要传32个字节。
用数组和指针优化数据打包。西门子这边用MOVE_BLK或者BLKMOV指令批量移动数据,比逐个字节MOVE快得多。
三菱那边,SP.SOCRCV和SP.SOCSND指令的执行时间比较长,不要在同一个扫描周期里连续调用。用状态机分步执行,每个扫描周期只执行一个指令。
6.2 数据量增大后的处理策略
如果数据量从32字节增加到256字节甚至更多,通信周期就要相应调整。我的经验是:每增加32字节,周期增加20ms。256字节的话,周期设200ms比较稳妥。
数据量大了之后,帧结构也要调整。可以加一个序列号字段,用来检测丢包和重复包。序列号每发一帧加1,接收方检查序列号是否连续,不连续就报警。
还可以加分片传输。如果一帧数据超过TCP的MSS(最大报文段长度),TCP会自动分片,但接收方需要处理粘包问题。简单的做法是每帧数据不超过1400字节,避免IP分片。
6.3 多台PLC之间的通信扩展
如果现场有多台PLC需要互相通信,开放式以太网通信也能胜任。有两种架构:
一种是星型架构,一台主PLC做服务端,其他PLC做客户端,都连到主PLC上。主PLC负责数据汇总和分发。这种架构简单,但主PLC的通信负担重。
另一种是网状架构,每台PLC既可以做客户端也可以做服务端,互相之间直接通信。这种架构灵活,但配置复杂,连接数多。
我的建议是:超过3台PLC就用星型架构,找一台性能最好的做数据中枢。连接数控制在8个以内,避免资源耗尽。
6.4 与上位机系统的对接
S7-1200采集到三菱的数据后,怎么传给上位机?有几种方式:
如果上位机是WinCC,可以直接用S7通信读S7-1200的DB块。S7-1200把三菱的数据存在DB块里,WinCC直接读就行。
如果上位机是第三方SCADA,可以用OPC UA。S7-1200支持OPC UA服务器功能,上位机作为客户端订阅数据。
如果上位机是自定义软件,可以用Modbus TCP。S7-1200支持Modbus TCP服务器,上位机用Modbus协议读取数据。
实操心得:不管用哪种方式,都建议在S7-1200里做一个“数据映射区”,把三菱的数据和本机数据统一整理到一个DB块里。这样上位机只需要读这一个DB块,不用关心数据来源。后期维护和扩展也方便。
6.5 安全防护的基本措施
开放式以太网通信是“裸”通信,没有加密和认证。在工业现场,安全防护主要靠网络隔离。
把PLC通信网络和办公网络物理隔离,用独立的交换机。如果必须连接,加防火墙,只开放必要的端口。
在程序里加简单的校验机制。比如帧头校验、长度校验、校验和校验。虽然不能防恶意攻击,但能防误码和干扰。
限制连接来源。三菱的打开设置里可以指定对方IP地址,只允许特定IP连接。西门子那边也可以在防火墙里设置访问规则。
定期检查连接日志。如果发现异常连接尝试,及时排查。工业现场一般不会有恶意攻击,但误配置导致的异常连接很常见。
7. 调试工具与实用技巧汇总
7.1 必备调试工具清单
| 工具名称 | 用途 | 使用场景 |
|---|---|---|
| Wireshark | 抓包分析 | 排查数据格式和字节序问题 |
| 网络调试助手 | 模拟客户端/服务端 | 联调阶段分别测试两边 |
| 博途在线监控 | 监控S7-1200变量 | 查看发送接收状态 |
| GX Works2在线监控 | 监控三菱变量 | 查看D寄存器和M标志位 |
| Ping命令 | 测试网络连通性 | 排查网络层问题 |
| 串口调试助手 | 备用调试 | 如果以太网不通,临时用串口 |
7.2 Wireshark抓包分析实战
Wireshark是排查通信问题的利器。使用方法很简单:在电脑上安装Wireshark,选对网卡,设置过滤条件“tcp.port == 5000”,然后开始抓包。
抓到的包会显示每一次TCP交互。重点看以下几个字段:
- Source和Destination:确认IP地址对不对
- Length:确认数据长度对不对
- Data:展开TCP payload,看原始字节
如果发现发送方发了32字节,接收方只收到16字节,说明TCP分片了,需要调整MSS或者增加接收缓冲区。
如果发现字节顺序和预期不符,比如发送的是0x41 0x42 0x43 0x44,收到的是0x44 0x43 0x42 0x41,那就是字节序反了,需要在程序里做SWAP。
7.3 在线监控的技巧
博途的在线监控可以同时看多个变量。我习惯把TSEND_C和TRCV_C的DONE、ERROR、STATUS都加到监控表里,一眼就能看出通信状态。
三菱的GX Works2在线监控可以看D寄存器和M标志位。我一般把通信相关的D寄存器和M标志位集中在一个监控窗口里,方便对比。
小技巧:博途的监控表可以导出和导入。调试完成后把监控表保存下来,下次调试直接导入,不用重新配置。
7.4 程序备份和版本管理
通信程序调试好后,一定要备份。博途的项目文件、GX Works2的项目文件、网络配置参数、IP地址规划表,全部存档。
建议用Git或者SVN做版本管理。每次修改程序都提交一次,记录修改内容和原因。现场出问题时可以快速回滚到上一个稳定版本。
IP地址规划表要单独维护,记录每台设备的IP、端口、通信协议、数据格式。后期扩展或者换设备时,这张表能省很多事。
8. 从项目实战中提炼的经验教训
8.1 前期规划比后期调试重要
这个项目我最大的体会是:通信协议的设计决定了调试的难度。如果前期把数据帧格式、字节序、数据类型、通信周期都规划清楚,后期调试就是按部就班。如果前期拍脑袋决定,后期就是无穷无尽的排查。
我的建议是:动手写程序之前,先画一张数据流图,标明每个数据的来源、去向、格式、长度。然后写一份通信协议文档,两边开发人员都确认。这份文档就是调试时的“宪法”,有争议就查文档。
8.2 分步验证比整体联调高效
不要想着一次性把两边都调通。先调网络层,再调传输层,再调应用层。每一步都验证通过后再进入下一步。
具体来说:先用ping验证网络通,再用网络调试助手验证TCP连接能建立,再验证数据能收发,最后验证数据解析正确。每一步都确认无误后再往下走。这样出问题时,问题范围很小,排查很快。
8.3 异常处理要提前设计
通信程序最怕的就是异常情况没处理。断线、超时、数据错误、连接资源耗尽,这些都要提前考虑。
我的做法是:在程序里加一个“通信状态机”,用状态变量管理通信的各个阶段。每个状态都有超时判断和错误处理。状态机的好处是逻辑清晰,不会因为某个异常导致程序卡死。
8.4 文档和注释不能省
通信程序的可读性很重要。变量命名要规范,比如“SendData”“RecvData”“SendLen”“RecvLen”,一看就知道什么意思。关键逻辑要加注释,说明为什么这么做。
我见过太多项目,程序写完就不管了,半年后自己都看不懂。通信程序尤其如此,涉及两边的配置和约定,不写文档根本维护不了。
8.5 现场调试的心态管理
现场调试最容易急躁。网络不通、数据不对、设备报警,一堆问题堆在一起,很容易乱了阵脚。
我的经验是:一次只解决一个问题。先把网络搞通,再搞连接,再搞数据。每个问题解决后记录一下,避免重复踩坑。遇到搞不定的问题,先放一放,喝杯水,换个思路再回来。很多时候问题没那么复杂,只是自己钻牛角尖了。
这个S7-1200和三菱Q系列的开放式以太网通信方案,我在三个项目里用过,最长的已经稳定运行两年多。中间也出过几次通信中断,但都是网络硬件问题,程序本身没出过毛病。这套方案的可靠性是经过验证的,只要前期规划到位,后期维护成本很低。
如果你也在做类似的多品牌PLC通信项目,不妨试试这个思路。不一定非要用网关,开放式以太网通信有时候更简单、更灵活、更省钱。关键是你要把数据格式和通信时序设计好,剩下的就是按部就班地实现和调试。