Java接口开发及Modbus|Java接口开发及Modbus Slave仿真使用 Modbus TCP协议

一、ModbusTcp简介
什么是ModbusTcp?
/1、Modbus rtu和Modbus tcp两个协议的本质都是MODBUS协议,都是靠MODBUS寄存器地址来交换数据;
/2、但所用的硬件接口不一样,Modbus RTU一般采用串口RS232C或RS485/422,而Modbus TCP一般采用以太网口。
/3、现在市场上有很多协议转换器,可以轻松的将这些不同的协议相互转换 如:Intesisbox可以把modbus rtu转换成Modbus tcp实际上Modbus协议包括ASCII、RTU、TCP。
/4、标准的Modicon控制器使用RS232C实现串行的Modbus。Modbus的ASCII、RTU协议规定了消息、数据的结构、命令和就答的方式,数据通讯采用Maser/Slave方式。
/5、Modbus协议需要对数据进行校验,串行协议中除有奇偶校验外,ASCII模式采用LRC校验,RTU模式采用16位CRC校验.
/6、ModbusTCP模式没有额外规定校验,因为TCP协议是一个面向连接的可靠协议。
/7、TCP和RTU协议非常类似,只要把RTU协议的两个字节的校验码去掉,然后在RTU协议的开始加上5个0和一个6并通过TCP/IP网络协议发送出去即可。
二、报文解析
本报文以电力逆变器设备的报文做解析
1、查询指令
(发送)00 00 00 00 00 06[k1]01[k2]03[k3]00[k4]00[k5]00[k6]00[k7]
[k1]起始字符组,长度,代表后面还有6个字节
[k2]设备地址
[k3]读指令
[k4]寄存器地址高8位
[k5]寄存器地址低8位
[k6]寄存器数量高8位
[k7]寄存器数量低8位
(返回)00 00 00 00 00 25[k1]01[k2]03[k3]22[k4] (自定义功能码字节区)
[k1]起始字符组,长度,代表后面还有25个字节
[k2]设备地址
[k3]读指令
[k4]表示接下来数据字节的长度
2、控制指令(启动/停止)
(发送)00 00 00 00 00 06[k1]01[k2]06[k3]00 12 00 01[k4]
[k1]起始字符组,长度,代表后面还有6个字节
[k2]设备地址
[k3]写指令
[k4]00=停止/01=启动
(返回)同上

3、逆变功率设定指令
(发送)00 00 00 00 00 06[k1]01[k2]06[k3]00 13 00[k4]00[k5]
[k1]起始字符组,长度,代表后面还有6个字节
[k2]设备地址
[k3]写指令
[k4]功率设定高字节
[k5]功率设定低字节
(返回)同上

请求报文案例:
主站向从站发送请求报文:01 03 00 01 00 02 95 CB

01代表设备地址
03代表功能码(读取保存寄存器的值)
00 01代表采集点对应的寄存器号
00 02代表读取两个连续寄存器的值
【Java接口开发及Modbus|Java接口开发及Modbus Slave仿真使用 Modbus TCP协议】95 CB代表01 03 00 01 00 02计算多得的CRC校验值
从站向主站放回的数据报文:01 03 04 00 00 00 00 FA 33
01代表设备地址
03代表功能码(读取保存寄存器的值)
04代表设备返回的数据个数(单位为字节)
00 00 00 00代表为数据返回的连续两个寄电器的数据
FA 33代表01 03 04 00 00 00 00计算所得的CRC校验码

1、ModbusTCP仿真 ModbusSlave(软件官方网站地址)是一个从站设备仿真软件,它用于接收主设备的命令包,并回送数据包;可用于测试和调试Modbus主站设备,便于观察Modbus通信过程中的各种报文。ModbusPoll及ModbusSlave支持ModbusRTU, ASCII,TCP/IP等协议。首先,了解MODBUS支持的部分功能代码,以十进制表示,如下表所示。代码中文名称英文名称位操作/字操作操作数量 01读线圈状态READ COIL STATUS位操作单个或多个 02读离散输入状态READ INPUT STATUS位操作单个或多个 03读保持寄存器READ HOLDING REGISTER字操作单个或多个 04读输入寄存器READ INPUT REGISTER字操作单个或多个 05写线圈状态WRITE SINGLE COIL位操作单个 06写单个保持寄存器WRITE SINGLE REGISTER字操作单个 15写多个线圈WRITE MULTIPLE COIL位操作多个 16写多个保持寄存器WRITE MULTIPLE REGISTER字操作多个 参数设置: 点击菜单“Setup”中“Slave Definition.. F2”进行参数设置,会弹出如下图对话框其中: (1)Slave ID:设备ID; (2)Function:对应上表所对应的Modbus功能,例如本文所选用的“03 Holding Register…”,与下文Java代码“见类ReadHoldingRegistersResponse ”所对应。 (3)Address:寄存器地址; (4)Quantity:数量。打开ModbusSlave软件,为方便起见,本文采用默认的地址(localhost,与下文第二段代码对应“见类ClientForTests ”),功能码,寄存器数量,单击Connection->connect,在弹出的窗口设置connection为TCP/IP,端口Port设置为30502,点击OK,如下图所示,从端配置完毕。注意: (1)本文连接Connection采用Modbus TCP/IP协议; (2)网络地址为本地地址,127.0.0.1; (3)端口与下文第二段代码“见类ClientForTests”中的地址和端口设置为“30502”; (4)选择“Ignore Unit ID”,如果不选择,测试程序返回空值。 --------------------- /** * 读保持寄存器上的内容 * * @param ip从站IP * @param portmodbus端口 * @param start起始地址偏移量 * @param readLenth 待读寄存器个数 * @return */ public static String modbusTCP(String ip, int port, int start, int readLenth) { ModbusFactory modbusFactory = new ModbusFactory(); // 设备ModbusTCP的Ip与端口,如果不设定端口则默认为502 IpParameters params = new IpParameters(); params.setHost("116.62.210.27"); //设置端口,默认502 if (502 != 15835) { params.setPort(15835); } ModbusMaster tcpMaster = null; tcpMaster = modbusFactory.createTcpMaster(params, true); try { tcpMaster.init(); System.out.println("========初始化成功======="); } catch (Exception e) { return null; } ModbusRequest modbusRequest = null; try { //功能码03读取保持寄存器的值 modbusRequest = new ReadHoldingRegistersRequest(1, start, readLenth); } catch (Exception e) { e.printStackTrace(); } ModbusResponse modbusResponse = null; try { modbusResponse = tcpMaster.send(modbusRequest); } catch (Exception e) { e.printStackTrace(); } ByteQueue byteQueue = new ByteQueue(1024); modbusResponse.write(byteQueue); System.out.println("功能码:" + modbusRequest.getFunctionCode()); System.out.println("从站地址:" + modbusRequest.getSlaveId()); System.out.println("收到的响应信息大小:" + byteQueue.size()); System.out.println("收到的响应信息值:" + byteQueue); //数据解析 Float fl = toBytes(String.valueOf(byteQueue)); return fl.toString(); }//----------------------------------------------解析16进制数据 public static Float toBytes(String s) { if (s.startsWith("[")) s = s.substring(1); if (s.endsWith("]")) s = s.substring(0, s.length() - 1); String parts = s.replaceAll("[`~!@#$%^&*()+=|{}':; ',\\[\\].<>/?~!@#¥%……& amp; *()——+|{}【】‘;:”“’。,、?|-]", ""); Float value = https://www.it610.com/article/Float.intBitsToFloat(Integer.valueOf(parts.trim(), 16)); System.out.println("valuehttps://www.it610.com/article/=================" + value); return value; }

    推荐阅读