三菱FX5UJ PLC Socket TCP客户端通信配置与编程实战
1. 为什么要在FX5UJ上折腾Socket通信三菱FX5UJ这台PLC玩过的人都知道它自带以太网口支持MC协议、SLMP、Socket通信这些功能。但很多人拿到手之后翻遍手册也搞不清楚Socket通信到底怎么配置尤其是做TCP客户端的时候各种参数设置让人头大。我刚开始接触FX5UJ做Socket通信那会儿也是踩了不少坑GX Works3里那些设置项看着简单实际连起来就是不通排查半天发现是端口号搞错了或者连接目标IP写反了。这篇内容就是把我自己在FX5UJ上实现Socket TCP客户端的完整过程整理出来从基础概念到参数配置再到实际编程和调试全部走一遍。不管你是刚接触PLC编程的新手还是从FX3U、Q系列转过来的老手只要涉及到FX5UJ的以太网Socket通信这里面的内容都能直接参考。特别是那些需要跟上位机、视觉系统、机器人控制器做TCP通信的场景FX5UJ作为客户端主动连接对方服务器的需求非常常见。先说清楚一个概念Socket通信本质上就是TCP/IP协议栈上面的一层编程接口。你可以把它理解成打电话——客户端就是主动拨号的一方服务端是接听的一方。FX5UJ做TCP客户端就是让PLC主动去连接指定的IP地址和端口号建立连接之后双方就可以互相发数据了。这个过程中PLC不需要等别人来连它而是它去找别人这在工业现场很实用比如PLC要把数据推给MES系统、要把结果发给视觉控制器都是PLC做客户端更顺手。FX5UJ的Socket通信支持TCP和UDP两种协议TCP又分客户端和服务器两种角色。TCP客户端模式下PLC主动发起连接请求经过三次握手建立连接然后就可以收发数据。这里有个关键点FX5UJ的Socket通信是通过内置以太网口实现的不需要额外加通信模块但需要用到专用的Socket通信指令比如SP.SOCOPEN、SP.SOCRCV、SP.SOCSND这些。这些指令跟普通的FROM/TO指令不一样它们是专门为Socket通信设计的用起来有固定的套路。我见过很多人卡在第一步——不知道FX5UJ初始IP是多少。出厂默认是没有IP的需要通过GX Works3或者SD卡来设置。一般来说我们会把PLC的IP设成跟目标设备同一个网段比如目标服务器是192.168.1.100那PLC就设成192.168.1.10这种。子网掩码通常255.255.255.0默认网关看情况如果跨网段通信就需要设同网段直连可以不设。这些参数在GX Works3的“模块参数”里面配置具体路径是导航窗口→参数→FX5UJCPU→模块参数→以太网端口→基本设置→IP地址设置。还有一个容易混淆的地方Socket通信的端口号。FX5UJ做客户端时需要指定目标服务器的端口号同时PLC自己也会用一个本地端口。本地端口可以固定也可以设为0让系统自动分配。我一般建议固定本地端口方便排查问题比如设成5000、6000这种不常用的端口。目标端口就要看对方服务器开的是什么端口了常见的有502Modbus TCP、9600、8080这些。这里要特别注意本地端口和目标端口不能搞混我见过有人把目标端口填成了PLC自己的端口结果怎么都连不上。2. FX5UJ Socket TCP客户端的核心配置拆解2.1 以太网基本参数设置打开GX Works3在导航窗口找到“参数”→ “FX5UJCPU”→ “模块参数”→ “以太网端口”。这里有几个关键页面需要配置。第一个是“基本设置”。IP地址设置里面选择“直接设置”然后填入PLC的IP地址、子网掩码、默认网关。比如IP地址192.168.1.10子网掩码255.255.255.0默认网关192.168.1.1同网段通信可以不填通信速度可以选“自动检测”或者强制100Mbps全双工。如果现场干扰大建议强制100M全双工避免自动协商出问题。第二个是“打开设置”。这里就是配置Socket通信的关键地方。FX5UJ支持最多8个连接同时打开8个Socket每个连接可以独立配置协议、角色、端口号等。我们做TCP客户端就选一个连接来配置协议TCP打开方式Active主动——这就是客户端模式本地端口号比如6000目标IP地址比如192.168.1.100目标端口号比如9600这里有个细节目标IP地址可以填IP或者主机名但工业现场一般直接用IP避免DNS解析出问题。目标端口号一定要跟服务器端监听的端口一致差一个数字都连不上。2.2 Socket通信指令体系FX5UJ的Socket通信指令主要有这几个指令功能使用场景SP.SOCOPEN打开Socket连接建立TCP连接SP.SOCCLOSE关闭Socket连接断开TCP连接SP.SOCRCV接收数据从对方读取数据SP.SOCSND发送数据向对方发送数据SP.SOCINF获取Socket信息查询连接状态这些指令都是带完成标志和错误标志的编程的时候需要配合触点使用。比如SP.SOCOPEN指令需要指定连接编号、执行方式首次执行还是连续执行然后等待完成标志ON。SP.SOCOPEN的参数设置连接编号1~8对应打开设置里的连接号执行方式0首次执行1连续执行完成标志指令执行完成后置ON错误标志执行出错时置ON我一般用首次执行方式用一个上升沿触发然后等待完成标志。如果出错错误标志ON这时候需要查错误代码来定位问题。2.3 数据收发缓冲区规划Socket通信收发数据都需要缓冲区FX5UJ用的是数据寄存器D或者文件寄存器R。发送的时候把要发的数据放到连续的D寄存器里然后指定起始地址和长度接收的时候指定接收缓冲区的起始地址和最大长度。比如我规划发送缓冲区D100~D199共100个字200字节接收缓冲区D200~D299共100个字200字节发送长度和接收长度都是按字节算的不是按字数。比如要发10个字节长度就填10。接收的时候SP.SOCRCV指令会返回实际接收到的字节数放在指定的寄存器里。这里有个坑FX5UJ的Socket通信数据是以字节为单位传输的但PLC内部是16位寄存器。所以发送的时候如果数据长度是奇数最后一个字节的高8位会被忽略或者补零。接收的时候也一样如果收到奇数个字节最后一个寄存器的高8位可能是无效数据。处理ASCII字符串的时候要特别注意这个问题。3. 手把手搭建TCP客户端通信程序3.1 连接建立与断开逻辑先写连接建立的部分。用一个启动按钮X0触发上升沿执行SP.SOCOPEN指令。X0上升沿 ├─ SP.SOCOPEN 连接编号1执行方式0 ├─ 完成标志M100 └─ 错误标志M101M100 ON表示连接建立成功M101 ON表示连接失败。连接失败的时候需要查错误代码。错误代码放在SP.SOCOPEN指令的最后一个参数里比如D500。连接成功之后就可以进行数据收发了。断开连接用SP.SOCCLOSE指令同样指定连接编号和执行方式。X1上升沿 ├─ SP.SOCCLOSE 连接编号1执行方式0 ├─ 完成标志M110 └─ 错误标志M111实际项目中我一般会在PLC上电后自动尝试连接连接失败后延时重试。重试间隔设个3~5秒避免频繁重连把网络搞拥塞。3.2 数据发送的完整流程发送数据用SP.SOCSND指令。假设我要把D100开始的10个字节发出去M100连接已建立AND X2上升沿 ├─ SP.SOCSND 连接编号1发送起始地址D100发送长度10 ├─ 完成标志M120 └─ 错误标志M121发送完成标志M120 ON表示数据已经成功发出去了。注意这里只是表示数据从PLC发出去了不表示对方已经收到。TCP协议本身有确认机制但应用层不知道对方有没有处理。发送的数据需要提前准备好。比如要发字符串“HELLO”就把ASCII码放到D100、D101、D102D100 0x4845H和ED101 0x4C4CL和LD102 0x4F00O和填充或者用$MOV指令直接写字符串FX5UJ支持字符串常量。3.3 数据接收与超时处理接收数据用SP.SOCRCV指令。这个指令有点特殊它是非等待的执行后立即返回如果有数据就接收没有数据就等下次扫描。M100连接已建立AND M200接收使能 ├─ SP.SOCRCV 连接编号1接收起始地址D200最大长度100 ├─ 完成标志M130 └─ 错误标志M131接收完成标志M130 ON表示收到了数据实际接收长度放在指定的寄存器里比如D300。然后根据D300的值来处理接收到的数据。这里有个关键点SP.SOCRCV指令需要在每次扫描都执行或者用连续执行方式。如果只用上升沿触发一次可能错过后续的数据。我一般用一个常ON触点来驱动或者用定时器周期性触发。接收超时怎么处理FX5UJ本身没有内置接收超时功能需要自己用定时器做。比如启动接收后如果500ms内没有收到数据就认为超时做相应处理。这个逻辑用定时器T0来实现M100 AND NOT M130 ├─ T0 K505秒定时器 └─ T0 ON时置位超时标志M1403.4 完整通信状态机设计实际项目中Socket通信不能只是简单的发和收需要有一个状态机来管理整个通信过程。我一般设计这几个状态状态说明转移条件0初始状态上电或复位1连接中执行SOCOPEN2已连接连接成功可收发3发送中执行SOCSND4接收中执行SOCRCV5错误处理出错后重试或报警状态机用D寄存器或者M寄存器来存当前状态然后根据状态和事件来转移。这种写法比一堆触点和线圈清晰得多后期维护也方便。4. 调试过程中那些让人抓狂的问题4.1 连接不上怎么办连接不上是最常见的问题。排查顺序我一般是这样先ping一下目标IP看网络通不通。如果ping不通检查网线、交换机、IP设置。用电脑上的网络调试工具比如TCP测试工具模拟服务器看PLC能不能连上。如果能连上说明PLC配置没问题问题在目标服务器。检查端口号。目标端口号是不是服务器实际监听的端口本地端口号有没有被占用检查防火墙。目标服务器或者中间网络设备有没有拦截这个端口看错误代码。SP.SOCOPEN的错误代码会告诉你具体原因比如超时、拒绝连接、网络不可达等。常见错误代码错误代码含义处理方式0x0000正常-0x0001连接超时检查网络和目标设备0x0002连接被拒绝目标端口未监听0x0003网络不可达检查IP和路由0x0004连接已存在先关闭再打开4.2 数据收发异常排查数据发出去了但对方没收到或者收到的是乱码这种问题也很常见。先确认发送长度对不对。长度是按字节算的不是字数。比如发“ABCD”4个字符长度填4不是2。再确认字节序。FX5UJ的寄存器是低字节在前还是高字节在前发送的时候D100的低8位先发还是高8位先发这个跟对方服务器的解析方式有关。如果对方是按大端序解析而PLC发的是小端序就会乱码。解决办法是在PLC端做字节交换或者跟对方约定好字节序。接收的时候也一样。如果收到的数据长度是奇数最后一个字节可能有问题。我一般会在接收缓冲区后面多留几个寄存器避免越界。4.3 连接断开与重连策略TCP连接可能因为各种原因断开网络抖动、对方服务器重启、超时等。PLC需要能检测到断开并自动重连。检测断开的方法SP.SOCRCV指令如果返回错误或者SP.SOCINF查询到连接状态不是已连接就认为断开了。然后关闭连接延时后重新执行SP.SOCOPEN。重连策略我一般这样设计首次重连延时1秒第二次重连延时3秒第三次重连延时5秒之后每次重连延时10秒避免频繁重连把网络搞崩。同时记录重连次数超过一定次数比如10次就报警提示人工检查。4.4 性能优化与注意事项FX5UJ的Socket通信性能跟扫描周期有关。SP.SOCRCV和SP.SOCSND指令的执行需要时间如果扫描周期太短可能指令还没执行完就进入下一次扫描了。我一般会把Socket通信相关的程序放在扫描周期的后半段或者用定时器中断来执行。发送数据不要太频繁。TCP协议本身有开销每次发送都有包头包尾。如果数据量小但发送频率高网络效率很低。我一般会做数据缓冲攒够一定长度或者间隔一定时间再发。接收缓冲区要足够大。如果对方发得快PLC接收不及时数据可能会丢失。FX5UJ的Socket接收缓冲区大小有限具体看手册。如果数据量大建议用文件寄存器R来存接收数据。还有一个容易忽略的点PLC断电重启后Socket连接会断开需要重新建立。所以程序里要有上电自动连接的逻辑不能只靠手动按钮触发。5. 实际项目中的经验总结5.1 与上位机通信的实战案例我之前做过一个项目FX5UJ作为TCP客户端连接一台工控机上的MES系统。MES系统开了一个TCP服务器端口9600PLC每生产一个产品就发一条数据过去包含产品编号、检测结果、时间戳。数据格式是ASCII字符串用逗号分隔比如“SN12345,OK,20240101120000”。PLC这边用$MOV指令把字符串拼好放到D寄存器然后SP.SOCSND发出去。MES收到后解析入库。这个项目里遇到一个问题MES服务器有时候会重启PLC检测到连接断开后需要自动重连。我用了前面说的重连策略效果不错。另外MES服务器对数据格式要求很严格多一个空格都会解析失败。所以PLC发送之前一定要确认数据格式完全正确。5.2 与视觉系统通信的注意事项另一个项目是FX5UJ连接视觉控制器。视觉控制器作为TCP服务器PLC作为客户端。PLC触发拍照后视觉控制器返回检测结果比如“OK”或“NG”。这个场景下实时性要求比较高。PLC发触发信号后要在100ms内收到结果。我用了SP.SOCRCV的连续执行方式配合定时器做超时检测。如果超时没收到结果就认为视觉系统故障报警停机。这里有个细节视觉控制器返回的数据可能分多次到达。比如先发“O”再发“K”。PLC需要能处理这种分包情况。我的做法是接收缓冲区不清零每次收到数据就追加直到收到结束符比如换行符才认为一帧数据完整。5.3 多连接并发处理FX5UJ支持最多8个Socket连接同时打开。如果需要同时跟多个设备通信可以配置多个连接。比如连接1跟MES通信连接2跟视觉控制器通信连接3跟机器人控制器通信。每个连接独立配置、独立编程。但要注意所有连接共享同一个以太网口带宽是有限的。如果数据量大需要考虑网络负载。我一般会把实时性要求高的连接设成高优先级数据量大的连接做流量控制。多连接编程的时候指令的连接编号一定要对应好。我见过有人把连接1的发送指令写成了连接2的编号结果数据发到错误的设备上去了。这种错误很隐蔽调试的时候要特别小心。5.4 常见问题速查表现象可能原因排查方法连接超时IP或端口错误ping测试检查配置连接被拒绝目标端口未监听用电脑测试目标端口发送成功但对方没收到字节序或格式问题抓包分析检查数据格式接收乱码字节序不匹配做字节交换测试频繁断连网络不稳定或对方重启检查网络质量看重连日志扫描周期变长Socket指令耗时优化程序结构用中断数据丢失接收缓冲区太小增大缓冲区降低发送频率5.5 编程习惯与代码规范最后说几个编程习惯上的建议。Socket通信程序一定要加注释每个指令的作用、参数含义、完成标志和错误标志的地址都要写清楚。不然过几个月自己都看不懂。错误处理要完善。每个Socket指令都要有错误标志判断出错后要有相应的处理逻辑不能不管。我一般会把错误代码存到连续的寄存器里方便后期排查。程序结构要清晰。连接管理、数据发送、数据接收、错误处理分开写用不同的程序块或者FB。这样后期修改的时候不会牵一发而动全身。还有调试的时候善用GX Works3的监控功能。可以实时看Socket指令的执行状态、完成标志、错误代码比猜要快得多。网络调试工具也是必备的Wireshark抓包能看到底层的数据流定位问题很有效。我在实际项目中最大的体会是Socket通信本身不复杂复杂的是各种边界情况和异常处理。把异常处理做好了程序就稳了。另外跟对方设备的开发者保持沟通很重要数据格式、通信协议、超时时间这些都要提前约定好不然联调的时候会浪费很多时间。