ModbusTCP通讯错误的排查

Modbus是一种由MODICON公司开发的工业现场总线协议标准,是一项应用层报文传输协议。该协议用于传输数字和模拟变量1。有关该协议的报文具体格式,以及一些基本概念,见1

本文以一个例子,阐述当ModbusTCP通讯出现错误的时候,排查错误的方式。

一、例子说明

这里将Arduino Opta PLC作为ModbusTCP从站。Arduino Opta PLC运行时,默认开启了Modbus TCP从站功能2。其设置的方式见2。这里,Arduino Opta PLC的网络设置如下:

cpp 复制代码
// shared variables can be accessed with PLCIn.varname and PLCOut.varname

void setup()
{

	// Configure static IP address
	IPAddress ip(192, 168, 1, 90); //so ip is 192.168.1.90
	IPAddress dns(192, 168, 1, 1);
	IPAddress gateway(192, 168, 1, 1);
	IPAddress subnet(255, 255, 255, 0);
	// If cable is not connected this will block the start of PLC with about 60s of timeout!
	Ethernet.begin(ip, dns, gateway, subnet);

}

void loop()
{

}

而笔记本电脑作为ModbusTCP主站,IP设置如下:

笔记本电脑和PLC通过RJ45网线连接。

在Arduino Opta PLC上,ModbusTCP从站的离散输入(discrete input)和线圈(coil)已有内置的变量和它们对应2

而输入寄存器(Input register)对应的变量在Status variable中

保持寄存器(Holding register)对应的变量在Parameters中

二、错误分析和修正

现在,使用电脑上的ModbusClientX软件作为主站和PLC进行通讯。该软件在3可下载。

在这里输入Modbus从站,即Arduino Opta PLC的ip地址和端口,点击Connect即可完成连接

目前连接成功,但当尝试点击"Read from 0 to 9"读取数据时,出现了如下错误:

对于ModbusTCP方面的错误,建议从Modbus的报文入手,即通过网络调试助手,通过TCP/IP协议连接ModbusTCP从站的PLC,发送报文,观察返回的报文。这里推荐NetAssist软件4

根据1中的提示,要读取从地址0开始的10个离散输入,应当发送的报文是"00 01 00 00 00 06 01 02 00 00 00 12"。所以将这句报文键入NetAssist。

(一)报文形式

返回的信息是报错信息。经分析,发现刚才发送的信息没有以16进制解读,而是以ASCII码解读,导致Modbus从站接收了错误信息。故将发送设置里由ASCII改为HEX。使用NetAssist或其它网络调试助手时,要注意发送报文是16进制报文还是ASCII字符串,这两者是完全不同的。

(二)从站设备号

很遗憾,还是出现了错误的返回。通过阅读2中的内容,主要是Modbus TCP Client Opta™ 那一节,发现ModbusTCP从站设备除了有IP地址和端口外,还有设备号,通常在1和255之间,Arduino Opta PLC设备的ModbusTCP从站设备号是255。

在ModbusTCP报文中,报文头MBAP中的最后一个字节是设备号1,对于该PLC而言是16进制的FF,即255。

所以报文内容应为"00 01 00 00 00 06 FF 02 00 00 00 12"

第三行是返回的值。除MBAP报文头外,信息从02开始,02表示功能码,03表示数据长度为3个字节,之后的00 00代表数据均为0。

在写有Button Inputs Mapping的图中,可见一个叫btn的变量代表了PLC上的一个按钮是否按下,且它对应了ModbusTCP的一个离散输入。当按下按钮后,btn值会变1。

此时,从地址01开始,读取8个离散输入,得到以下结果:

返回的报文中,最后的3个字节,02表示功能码,01表示1个字节,08是数据,对应得2进制是00001000,也就是说第4个离散量输入是1,其余是0。

同样的,PLC的指示灯输出也有ModbusTCP的线圈和它们对应。可参见带有"LED outputs mapping"的图。

现在,用写线圈的报文,把LED灯的变量设为1。这里写在地址0x05

(三)寄存器地址的偏移

关于输入寄存器,在Status variables图中可知,在地址0x6001有一个叫做cnt的变量。所以,现在用读取输入寄存器的报文读出该变量。

从回复中可看出,数据未能读取,出现错误。原因在于寄存器地址的偏移。在Arduino Opta PLC中,地址为0x6001的变量,在ModbusTCP的输入寄存器中,实际地址为0x6000。

读出的数据为0xD82A,在十进制中为-10198。

不同的PLC会有不同的偏移量,有的PLC无偏移量,有的PLC会有1个偏移量,或者其它情况。建议尝试不同的地址找到偏移规律。

同样的,若要写入保持寄存器,即Parameters,也可用ModbusTCP报文。这里将位于0x4001的parameter写为0x32F1,即13041。

该变量被写入。位于0x4001的变量,在保持寄存器中的地址也是0x4000。

三、小结

总之,对于ModbusTCP通信中出现的错误,建议通过NetAssist等网络调试软件研究具体的报文,发现错误。首先要确保报文是HEX即16进制格式;另外,要注意ModbusTCP的从站除了IP地址和端口号外,还有设备号,不一定为1;对于寄存器,也包括离散输入和线圈,要考虑不同的PLC可能的地址偏移,即设备内存地址和ModbusTCP地址之间的偏移。

参考资料

1ModbusTCP协议 - ioufev - 博客园

2Modbus TCP On Opta™ Using PLC IDE

3ModbusClientX - Modbus Tool

4NetAssist网络调试助手下载_NetAssist5.0.2官方最新版下载 - 系统之家

相关推荐
网络研究院14 天前
2026年网络安全
网络·安全·法律·法规·趋势·发展
酣大智14 天前
ARP代理--工作原理
运维·网络·arp·arp代理
treesforest14 天前
AI安全系统如何识别异常访问?IP风险识别正在成为关键能力
网络·人工智能·tcp/ip·安全·web安全
shushangyun_14 天前
2026年快消品B2B系统推荐:支持终端门店订货、促销政策自动化的工具?
java·运维·网络·数据库·人工智能·spring·自动化
2601_9618451514 天前
粉笔行测题库|系统班|刷题
网络·百度·微信·微信公众平台·facebook·新浪微博
程序猿阿伟14 天前
《Chrome离线扩展安装的底层逻辑与场景落地指南》
服务器·网络·chrome
InHand云飞小白14 天前
无人值守站点网络困境?工业级路由器IR315破解连接难题
网络·物联网·4g·工业路由器·4g路由器·iiot·蜂窝路由器
森G14 天前
75、服务器源码解析---------云视频服务项目
linux·服务器·网络·c++·qt
江华森14 天前
TCP/IP 协议栈实战 — 7 个实验详解
网络·tcp/ip·智能路由器
酉鬼女又兒14 天前
零基础入门计算机网络运输层:端到端通信核心作用、端口号分类规则、复用分用工作机制及UDP与TCP协议全方位对比详解
网络·网络协议·tcp/ip·计算机网络·考研·udp·php