ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

FX5U ModbusTCP主从站通信调试:用Modbus Slave模拟从站全程验证指南

FX5U ModbusTCP主从站通信调试:用Modbus Slave模拟从站全程验证指南 前阵子出差调试一条输送线PLC用的是FX5U要走现场好几台ModbusTCP设备的通信。设备到场时间比程序调试晚了一周但电柜里的接线和PLC程序又必须在发货前验证完。这种时候再去等真实设备显然不现实我的做法是用FX5U做ModbusTCP主站电脑上的Modbus Slave软件做从站在办公室就把通信链路、报文格式、地址映射和程序逻辑全部验证一遍。这个方案我用过很多次只要有网线、一台PLC和一台电脑就能开始非常稳。今天把整个调试流程、配置参数和踩过的坑完整整理出来希望能帮到正在折腾ModbusTCP主从站的朋友。这套方法特别适合三类人第一次调ModbusTCP、连报文格式都没搞清的初学者手头设备没到场但PLC程序需要提前做联调的工程师以及被现场通信故障折磨得想骂人的调试老手。就算你之前完全没接触过ModbusTCP只要跟着把环境搭好、把模拟从站跑起来对整条链路怎么工作也会有直观认识。1. 先想清楚这套调试方案到底在验证什么1.1 主站和从站各自扮演什么角色ModbusTCP本质上是一个请求-响应模型。主站也就是FX5U主动发出读写请求从站收到请求后返回应答。整个过程围绕TCP 502端口展开主站先跟从站建立TCP连接然后再在这条连接上一个请求一个请求地收发。这里有个容易混淆的点ModbusTCP虽然走的是以太网和TCP/IP协议栈但它并不是普通的上位机通讯它有你必须在配置里说清楚的“从站地址”。只不过在ModbusTCP里这个从站地址叫Unit ID单元标识符通常默认填1。在传统的串口Modbus里一个RS485总线上可以挂几十个从站每个从站分配不同地址而TCP里的Unit ID更像是一个逻辑编号主要给网关转换保留的。1.2 为什么用模拟软件而不是直接接真实设备最直接的理由是设备没到、设备太贵、设备不方便挪。但即便设备就在手边第一轮调试也建议先用模拟软件跑通。原因很简单真实设备的寄存器表可能几百页你根本不知道哪几个地址是只读的、哪几个地址需要写什么格式的数据一上来就接真设备会把“通信链路问题”和“设备数据定义问题”搅在一起排查起来非常痛苦。用Modbus Slave模拟软件就清爽得多。它就是一个跑在电脑上的TCP服务器你告诉它“我在502端口等着暴露1号从站的保持寄存器地址从0开始一共200个寄存器”它就开始监听。PLC发来的读请求它按Modbus协议解析并返回数据PLC发来的写请求它把数据写到自己的模拟寄存器里。这样链路是否通、报文格式是否正确、地址映射是否匹配一眼就能看出来。1.3 模拟验证的边界哪些坑它覆盖不了我必须先把话说清楚模拟器能验证的是“逻辑链路”验证不了“物理链路和现场环境”。它能证明你的IP配置、从站ID、功能码、地址映射、PLC程序流程都是对的但它模拟不了现场的强电干扰、网线接头松动、交换机丢包、设备响应延迟和从站寄存器写保护。我自己就吃过亏。有一回模拟器跑得顺顺当当接上真实伺服驱动后死活读不到数据。最后发现是伺服和电脑、PLC不在同一个网段三台设备的子网掩码还不一样。这种问题在模拟环境里根本不会出现因为模拟器和PLC都在同一台电脑网卡下只要Ping通基本就通了。所以严格说模拟验证是“通信逻辑验证”到场后的“物理链路验证”依然省不掉。2. 环境准备硬件软件清单和模拟从站的替代方案2.1 硬件清单和IP规划硬件方面很常规一台带内置以太网口的FX5U比如FX5U-32MT/ES这种、一台装了GX Works3的电脑、一根普通网线直连用交叉线现在已经无所谓现代网卡都支持自适应。如果PLC和电脑中间经过交换机也完全没有问题只要保证网段一致。IP规划是最容易翻车的点。FX5U出厂默认IP地址是192.168.3.250子网掩码255.255.255.0。如果你的电脑是自动获取IP很可能是192.168.1.x段那跟PLC根本不在一个网段连Ping都Ping不通。所以动手前先把PLC改到跟电脑同一个网段比如电脑设192.168.1.20/255.255.255.0PLC设192.168.1.10/255.255.255.0。注意PLC的IP是直接在CPU参数里修改然后下载的不是在面板上改。2.2 GX Works3和Modbus Slave的版本选择GX Works3建议用较新的版本因为FX5U的通信协议支持功能在旧版本里可能不够完善。如果你用的是FX5U-EP、FX5U-64DP等带两个以太网口的型号请特别注意两个口的IP要分别设置别把请求发到了没接线的那个口。Modbus Slave软件我用的是Witte Software出的那款。官网上直接有下载但要注意它的授权模式评估期有限功能也会受限制。网上流传的各种“密钥”“补丁”我不建议碰风险太大而且调试工作没必要冒险。如果试用期到了或者想用更灵活的方式可以试试下面几个替代方案。2.3 模拟从站的几个免费替代方案第一个替代方案是用Python的pymodbus库自己写一个最简单的TCP从站。这听起来吓人其实代码就十几行from pymodbus.server import StartTcpServer from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext from pymodbus.datastore import ModbusSequentialDataBlock # 分配四个数据区DI离散输入、CO线圈、HR保持寄存器、IR输入寄存器 block_di ModbusSequentialDataBlock(0, [0] * 200) block_co ModbusSequentialDataBlock(0, [0] * 200) block_hr ModbusSequentialDataBlock(0, [0] * 200) block_ir ModbusSequentialDataBlock(0, [0] * 200) # 组装成从站上下文从站ID为1 slave ModbusSlaveContext(diblock_di, coblock_co, hrblock_hr, irblock_ir, zero_modeTrue) context ModbusServerContext(slaves{1: slave}, singleFalse) # 监听所有网卡的502端口 StartTcpServer(contextcontext, address(0.0.0.0, 502))运行之前先安装pymodbus库命令是pip install pymodbus然后在Windows下要用管理员权限运行脚本因为502端口在1024以内需要权限。如果你机器的502端口被其他软件占用了程序会报错可以先查一下占用再继续。不同版本的pymodbus在API细节上会有区别如果报错就看你安装版本的官方示例但整体思路不会变。第二个替代方案是用ModRSsim2这种开源模拟器图形界面不需要写代码能配置多个从站ID、多个功能码日常调试完全够用。我个人的习惯是临时验证用Modbus Slave需要定制行为比如故意制造异常响应时就用pymodbus脚本。3. FX5U做主站的两种实现路径我推荐先看路径A3.1 路径A用GX Works3的通信协议支持功能配置ModbusTCP主站这是三菱官方提供的最省事方案不需要手拼报文只需要在软件里勾选配置。第一步在GX Works3里新建工程选择正确的CPU型号进入“参数→FX5UCPU→模块参数→内置以太网端口”。这里先设置IP地址、子网掩码比如IP填192.168.1.10子网掩码255.255.255.0。填写完以后重点看下面的“通信协议支持功能”点“详细设置”进入协议配置界面。第二步新建一个协议文件。协议文件里可以添加多个协议包每个协议包对应一种报文类型。以最常用的“读保持寄存器”为例选择添加“ModbusTCP”→“主站”→“读保持寄存器”。这时界面会让你填从站ID、起始地址、读取数量。这里有一个大坑地址到底从几开始。后面第7章我会专门讲先记住一句话报文里的实际地址是从0开始的偏移量你不要脑补什么40001、30001在协议里通常填0就是读40001这个寄存器。第三步设置通信参数。目标端口默认502超时时间可以设500ms左右重试次数建议设1次。如果是模拟器测试超时设短一点没问题但接真实设备前一定要适当放宽否则设备扫描周期稍长就会报超时。第四步在程序里调用协议执行指令。通信协议支持功能配好的协议包需要用SP.ECPRTCL指令来触发执行。指令参数里主要有协议编号、发送数据存放软元件、接收数据存放软元件、完成标志和异常标志。触发条件一般用一个常ON或者定时脉冲程序里要留意通信指令不能被重复触发最好是检测到上一次通信完成或异常后再发下一次请求。第五步把读到的数据从接收缓冲区搬走。比如你配置了读10个保持寄存器接收数据会存到D100到D109你直接用MOV指令搬到其他数据区即可。这个搬运动作很重要因为下一次通信会把缓冲区的数据覆盖掉。用这套方案的好处是报文完全由协议包自己组你不需要关心MBAP头、功能码、CRC这些底层细节配置对了就稳。缺点是如果厂家协议不是标准ModbusTCP或者你需要在一个请求里混用多种数据类型配置起来反而麻烦。3.2 路径B用Socket通信指令手拼报文路径B属于进阶玩法但我觉得搞懂它对理解ModbusTCP帮助极大。FX5U内置以太网口支持Socket通信也就是你可以直接打开一个TCP连接然后把十六进制报文发出去再接收响应。一条标准的ModbusTCP读保持寄存器请求报文长这样一共12个字节00 01 00 00 00 06 01 03 00 00 00 0A逐字段拆开看开头两个字节00 01是事务标识符每次请求递增从站响应时原样带回用来匹配请求和响应接着00 00是协议标识符Modbus固定为000 06是长度表示后续还有6个字节01是单元标识符也就是从站ID03是功能码表示读保持寄存器00 00是寄存器起始地址如果你要读40001这里就是00 0000 0A是读取数量十六进制0A就是10。在FX5U里用Socket指令实现的话流程是先用SP.SOCOPEN打开一条到从站IP和502端口的TCP连接然后用SP.SOCSND把上面这12个字节发出去最后用SP.SOCRCV接收从站的响应。从站响应报文的前6个字节是和请求对应的MBAP头后面才是数据区第一个字节是功能码最后一个字节是数据字节数数据按寄存器大端排列。路径B的优点是灵活遇到非标准协议也能自己拼字符串缺点是程序量明显变大还要处理粘包、拆包、超时、连接状态机这些麻烦事。我不建议第一次调ModbusTCP的人直接上手但当你用路径A把通信跑通之后再回过头来看路径B很多概念会立刻豁然开朗。4. Modbus Slave模拟从站的配置与抓包验证4.1 从站软件的核心设置Modbus Slave启动以后界面是空白的你要先新建一个从站连接。菜单里选择“Connection→Connect”在弹出的窗口里选TCP/IP端口填502然后点OK。接着在“Setup→Slave Definition”里配置从站从站ID填1这个必须和PLC侧请求里的Unit ID一致。功能码按需选择比如选03 Holding Register然后设置起始地址和数量。我一般会分配200个寄存器让PLC有足够的空间来读。地址起点建议从0开始和协议报文的偏移保持一致。设置完成后软件主界面会显示一个数据表格这些就是“从站的寄存器内容”。你可以双击任一单元格修改数值用来验证PLC读回来的数据对不对。比如把D区对应的寄存器改成12345然后看PLC里是不是也变成12345。一个容易忽略的点是“监听状态”。Modbus Slave启动后如果它真的在监听502端口软件标题栏或状态栏会有提示。如果你发现运行了但状态不对去防火墙里放行一下程序或者在管理员权限下运行。否则PLC连过来时会直接拒绝。4.2 用Wireshark抓包验证报文建议每个调试员都掌握模拟通信虽然“看起来通就行了”但遇到问题的时候抓包能帮你省下一天时间。Wireshark打开后选择电脑连接PLC的网卡过滤条件直接写tcp.port 502然后触发PLC的读取请求就能看到完整的TCP连接建立过程和Modbus报文。看抓包的顺序是先看有没有TCP三次握手也就是SYN、SYN-ACK、ACK这三个包。如果没有说明连接根本没建立起来问题出在IP、端口、防火墙这些链路环节。如果握手正常再看有没有Modbus请求和响应成对出现。请求是PLC发给电脑的响应是电脑回给PLC的。如果只有请求没有响应说明Modbus Slave没配置好或者根本没监听。如果有响应但PLC侧还是判断异常多半是事务标识符、单元标识或协议标识符没对上。抓包还能帮你确认字节序。比如你将Modbus Slave里的寄存器0001设为0x1234抓包看到响应报文数据区是12 34说明是大端字节序这个和Modbus标准一致。如果PLC读回D区里存的是0x3412说明在PLC侧做了大小端转换这不是通信问题是转换逻辑问题。5. 联调全流程从Ping通到读写数据一步不差5.1 网络的初步打通把PLC和电脑用网线连起来或者都接到交换机上。先在电脑的命令行窗口Ping PLC的IP然后再从PLC侧Ping电脑的IP。FX5U可以通过GX Works3的在线监视功能查看Ping结果也可以直接在电脑端操作。我碰到的Ping不通的情况90%都是IP网段问题。三菱PLC出厂默认IP是192.168.3.250如果你没改过PLC参数就下载电脑又设了192.168.1.20那必然不通。先把GX Works3里的CPU参数里内置以太网口的IP改好注意子网掩码。改完以后下载参数并复位CPUPing通了再继续。5.2 启动模拟从站并确认监听状态启动Modbus Slave建立好TCP连接和从站定义确认软件已经在502端口监听。此时可以用电脑自己的工具再验证一下比如在命令行执行netstat -an | findstr 502看到LISTENING状态就说明监听成功。Windows防火墙是所有模拟从站的隐形杀手。如果PLC请求总是超时而电脑端防火墙没有放行Modbus Slave或PythonTCP连接会被静默丢弃。建议在防火墙入站规则里显式放行对应程序调试期也可以把当前网卡设为“专用网络”后允许应用通过。5.3 PLC侧下载程序并观察通信状态PLC程序里触发通信指令的开关建议先用一个手动置位点方便你一步一步看效果。等确认通信稳定之后再改成定时触发或循环触发。下载程序后让PLC处于RUN状态把触发条件接通去Modbus Slave软件里看连接是否建立、收包计数是否增长。如果连接建立但对端没有收到请求去查通信协议支持功能里的从站ID、目标IP、端口号。这三项任何一个不对PLC都只会报超时而且不会给你具体提示。最让人迷惑的是地址配置错误时Modbus Slave是能收到请求的但PLC依然超时或者读到一堆假数据这时候就要去对照寄存器地址映射。5.4 读写验证的完整清单我一般会做三轮验证每轮都记录现象确认没跑偏再进入下一轮。第一轮是读验证。在Modbus Slave里把地址0000、0001、0002分别改成100、200、300在PLC监视里看对应D寄存器的值是不是100、200、300。读值全部一致说明IP、端口、功能码、地址映射、数据长度全对。第二轮是写验证。在PLC里对一个写保持寄存器的协议包进行触发把D500里的数据写给从站地址0000。然后看Modbus Slave里地址0000的值是否变成D500的值。写成功了说明通信协议支持功能里的写报文配置也正确。第三轮是连续循环验证。把通信触发方式改成周期性执行运行20分钟以上观察是否出现偶发超时或掉线。如果在模拟环境里都会偶发断连那接真实设备时问题会被放大十倍必须提前排查掉。6. 常见问题与排查技巧实录6.1 典型现象排查表现象可能原因处理办法Ping不通网段不一致、网线没插好、CPU处于STOP统一网段检查网线确认CPU参数已下载Ping通但PLC报连接超时从站没监听、防火墙拦截、端口不是502确认模拟器监听状态放行防火墙检查端口号连接正常但收不到Modbus请求通信协议支持功能未配置、协议编号不对、指令未触发检查协议包配置核对SP.ECPRTCL参数置位触发条件收到请求但PLC报异常响应从站ID不匹配、请求地址越界、功能码不被支持核对从站定义和PLC请求参数能读但数据全为0寄存器没初始化、地址偏移搞错、读到了空白区在从站软件里写入非零测试值用抓包对比地址数据读回来了但数值不对字节序大小端不对、寄存器类型选错、数据解析逻辑有误抓包对比原始字节检查字顺序设置通信时好时坏超时时间太短、重试次数为0、多个协议并发执行延长超时设置重试给通信触发加互锁6.2 三个排查思路按顺序来效率最高第一是分层排查。先把问题拆成链路层、报文层、应用层三段。链路层就是TCP连接能不能建立抓包看有没有三次握手报文层就是请求响应格式对不对抓包看报文内容应用层就是数据映射和解析对不对看寄存器数值是否按预期。这三段各管一段别混在一起猜。第二是以抓包为准。很多人调通信靠眼睛盯状态灯和软件界面但界面上的状态信息往往是滞后的。Wireshark抓包看到的是最原始的真相。比如PLC报了超时抓包一看从站的响应其实早已发出那问题就在PLC侧接收处理如果抓包发现请求根本没发出来那问题就在PLC侧配置。抓包一亮很多争议立刻平息。第三是主动制造故障。通信调通以后故意把从站关掉一次看看PLC侧异常标志能不能被捕获故意修改从站的地址范围看看PLC侧会不会正确报错。通过这些“负向测试”你能提前知道异常时程序会怎么表现而不是等现场出了问题再手忙脚乱。6.3 从模拟器切换到真实设备时你要额外注意什么模拟器验证通过只代表逻辑正确。接真实设备后第一步仍然要确认设备的IP、子网掩码、端口和从站ID都设置正确。不同的伺服驱动器、仪表、智能电表Modbus寄存器表完全不同有的读保持寄存器对应速度值有的对应状态字地址差一个全盘皆输。第二步是确认设备的寄存器访问权限。不少驱动器允许你读但写之前需要先写一个使能位或者解锁命令。你如果直接用模拟器里的写保持寄存器方式去写目标速度设备会返回异常响应甚至根本不理你。正确的做法是先看设备手册搞清楚启停和速度控制需要哪些寄存器、哪些必须顺序写入。第三步是注意设备响应延迟。模拟器是即时应答真实设备从收到请求到生成响应可能需要几十毫秒。你的主站超时时间如果设得太短比如只有50毫秒接模拟器时一切正常接真实设备后就频繁误报。我接伺服驱动器时超时一般设在300到500毫秒之间重试1次这样既有故障响应速度又不至于被慢速设备拖垮。7. 几个特别容易被忽略的细节全是经验换来的7.1 地址映射里的“1”偏移陷阱这是Modbus新手最容易犯错的地方没有之一。Modbus协议报文里的地址是从0开始的十六进制偏移而人们在组态软件、触摸屏里看到的地址却是40001、30001这种“人类地址”。它们的对应关系是报文地址0对应40001报文地址1对应40002以此类推。你在GX Works3通信协议支持功能里配置读保持寄存器时起始地址应该填0数量填10读到的就是40001到40010。如果交互界面里直接让你填40001那就不用减1直接填40001就行。最怕的是界面里写的明明是“起始地址”你却填了40001这就相当于从40002开始读。判断办法很简单先在Modbus Slave的寄存器0里面放一个特殊值比如999然后看PLC读回来的是第一个数据还是第二个数据就知道有没有差一位了。7.2 多个协议实例跑在同一个连接上容易互相踩踏通信协议支持功能里你可能会配置多个协议包比如一个读状态、一个写速度、一个写启停。如果这些协议包在程序里被同时触发它们会争抢同一条TCP连接导致请求和响应错乱。解决办法是给每个协议的触发加互锁。比如用M0触发读状态M1触发写速度编程时让M1只有在读状态完成标志置位后才允许置位发送指令执行期间锁住其他触发。这些细节在模拟环境里不明显一旦接上真实设备或者通信频率提高就会出现所谓“偶发性通信异常”。7.3 字节顺序和字顺序提供数据的设备说了算Modbus单条报文里16位寄存器的高字节在前、低字节在后这是标准。但32位数据比如浮点数、长整型需要占用两个寄存器先传高字还是先传低字标准并没有强制规定。所以经常出现PLC收到的两个寄存器数值都对但把它们拼成一个32位数时完全不对的情况。调试时如果遇到这种问题先别怀疑通信链路去把抓包数据里两个寄存器的原始值和PLC的拼接结果对比一下看是高低字颠倒还是高低字节颠倒。GX Works3里有字顺序设置的选项或者你可以自己在程序里用SWAP指令调整。一般情况下三菱系的CPU默认和Modbus标准能对上但还是要以设备手册为准。7.4 模拟器验证时的连接数限制别忽视Modbus Slave软件在授权受限的情况下可能只允许一个主站连接。如果你调试时开着这个模拟从站又在同一台电脑上开着Modbus Poll去读它PLC那边就可能会出现连接被拒或者被挤下线的情况。调试时最好只让PLC这个主站连着从站其他调试工具都关掉避免不必要的干扰。如果用pymodbus自己写从站脚本也要注意代码里有没有把singleFalse写成singleTrue这会影响多从站ID的响应逻辑。我建议直接用singleFalse并传入一个从站ID字典这样后面想模拟多个设备时不用改架构。最后分享一点个人经验这套用FX5U配合Modbus Slave做ModbusTCP主从站验证的方法几乎每次都能让我在半小时内把通信逻辑跑通。到了项目现场只要物理链路没问题剩下的基本就是改改设备IP、调整一下寄存器地址表的事。但我也必须提醒一句模拟通过后一定一定要花时间对着真实设备手册核一遍寄存器表。我有一次就是模拟器上全通接上JE-A伺服后报文也正常可速度就是没反应排查到最后才发现是寄存器地址理解错了把指令写到了一个只读区域。通信调试最大的对手往往不是技术而是“我以为对了”。希望这篇避坑指南能帮你少走几次弯路把精力留到真正该花的地方。
返回列表