物联网---03.Modbus协议实现与设备的通讯,收发信息,实现对设备信息的采集
一、扫盲:什么是modbus?
Modbus是由Modicon(现为施耐德电气公司的一个品牌)在1979年发明的,是全球第一个真正用于工业现场的总线协议
Modbus协议是应用于电子控制器上的一种通用语言。通过此协议,控制器相互之间、控制器经由网络(例如以太网)和其它设备之间可以通信。它已经成为一种通用工业标准。有了它,不同厂商生产的控制设备可以连成工业网络,进行集中监控。此协议定义了一个控制器能认识使用的消息结构,而不管它们是经过何种网络进行通信的。它描述了一个控制器请求访问其它设备的过程,如何回应来自其它设备的请求,以及怎样侦测错误并记录。它制定了消息域格局和内容的公共格式。
modbus本身就是一个通信协议,可以基于串口,也可以基于网口,基于串口的有RTU;基于网口的有TCP,默认端口号为502,通常我们把服务器端作为主站,将带有modbus模块的设备作为从站处理。利用modbus从寄存器中读取或写入数据
modbus功能码参照表:
二、请求报文案例
主站向从站发送请求报文:01 03 00 01 00 02 95 CB
01代表设备地址
03代表功能码(读取保存寄存器的值)
00 01代表采集点对应的寄存器号
00 02代表读取两个连续寄存器的值
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校验码
最后向大家推荐一款modbus从站虚拟机,可以用做测试【ModbusSlave.exe】
从站虚拟机测试案例:
提供一个读取及写入的工具类:
依赖jar包:commons-codec-1.6.jar modbus4J.jar seroUtils.jar
1 2 3 4 5 6 7 8 9 10 11 12 | <!-- https: //mvnrepository.com/artifact/org.apache.directory.studio/org.apache.commons.codec --> <dependency> <groupId>org.apache.directory.studio</groupId> <artifactId>org.apache.commons.codec</artifactId> <version> 1.8 </version> </dependency> <dependency> <groupId>com.infiniteautomation</groupId> <artifactId>modbus4j</artifactId> <version> 3.0 . 3 </version> </dependency> <!-- 需要下载 --> <dependency><br> <groupId>com.automation</groupId><br> <artifactId>seroUtils</artifactId><br> <systemPath>${project.basedir}/src/lib/seroUtils.jar</systemPath><br> <scope>system</scope><br> </dependency> |
seroUtils.jar 下载
链接:https://pan.baidu.com/s/1sbjR9w4JWe5ctBcLZwb8UA
提取码:c9sv
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | import com.serotonin.modbus4j.ModbusFactory; import com.serotonin.modbus4j.ModbusMaster; import com.serotonin.modbus4j.exception.ModbusInitException; import com.serotonin.modbus4j.exception.ModbusTransportException; import com.serotonin.modbus4j.ip.IpParameters; import com.serotonin.modbus4j.msg.ModbusRequest; import com.serotonin.modbus4j.msg.ModbusResponse; import com.serotonin.modbus4j.msg.ReadHoldingRegistersRequest; import com.serotonin.modbus4j.msg.WriteRegistersRequest; import com.serotonin.modbus4j.msg.WriteRegistersResponse; import com.serotonin.util.queue.ByteQueue; public class ReadAWriteUtil { /** * 批量写数据到保持寄存器 * @param ip 从站IP * @param port modbus端口 * @param slaveId 从站ID * @param start 起始地址偏移量 * @param values 待写数据 */ public static void modbusWTCP(String ip, int port, int slaveId, int start, short [] values) { ModbusFactory modbusFactory = new ModbusFactory(); // 设备ModbusTCP的Ip与端口,如果不设定端口则默认为502 IpParameters params = new IpParameters(); params.setHost(ip); // 设置端口,默认502 if ( 502 != port) { params.setPort(port); } ModbusMaster tcpMaster = null ; // 参数1:IP和端口信息 参数2:保持连接激活 tcpMaster = modbusFactory.createTcpMaster(params, true ); try { tcpMaster.init(); System.out.println( "=======初始化成功========" ); } catch (ModbusInitException e) { System.out.println( "初始化异常" ); } try { WriteRegistersRequest request = new WriteRegistersRequest(slaveId, start, values); WriteRegistersResponse response = (WriteRegistersResponse) tcpMaster.send(request); if (response.isException()){ System.out.println( "Exception response: message=" + response.getExceptionMessage()); } else { System.out.println( "Success" ); } } catch (ModbusTransportException e) { e.printStackTrace(); } } /** * 读保持寄存器上的内容 * @param ip 从站IP * @param port modbus端口 * @param start 起始地址偏移量 * @param readLenth 待读寄存器个数 * @return */ public static ByteQueue modbusTCP(String ip, int port, int start, int readLenth) { ModbusFactory modbusFactory = new ModbusFactory(); // 设备ModbusTCP的Ip与端口,如果不设定端口则默认为502 IpParameters params = new IpParameters(); params.setHost(ip); //设置端口,默认502 if ( 502 !=port){ params.setPort(port); } ModbusMaster tcpMaster = null ; tcpMaster = modbusFactory.createTcpMaster(params, true ); try { tcpMaster.init(); System.out.println( "========初始化成功=======" ); } catch (ModbusInitException e) { return null ; } ModbusRequest modbusRequest= null ; try { //功能码03 读取保持寄存器的值 modbusRequest = new ReadHoldingRegistersRequest( 1 , start, readLenth); } catch (ModbusTransportException e) { e.printStackTrace(); } ModbusResponse modbusResponse= null ; try { modbusResponse = tcpMaster.send(modbusRequest); } catch (ModbusTransportException 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); return byteQueue; } } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂