本文通过Java开源库jlibmodbus实现modbusTCP通讯 从机端

添加依赖

<dependency><groupId>com.intelligt.modbus</groupId><artifactId>jlibmodbus</artifactId><version>1.2.9.7</version>
</dependency>

Java实现从机读写操作

ModbusSlaveUtil 类,主程序创建Modbus Slave监听事件

import com.intelligt.modbus.jlibmodbus.Modbus;
import com.intelligt.modbus.jlibmodbus.data.ModbusHoldingRegisters;
import com.intelligt.modbus.jlibmodbus.exception.IllegalDataAddressException;
import com.intelligt.modbus.jlibmodbus.exception.IllegalDataValueException;
import com.intelligt.modbus.jlibmodbus.exception.ModbusIOException;
import com.intelligt.modbus.jlibmodbus.slave.ModbusSlave;
import com.intelligt.modbus.jlibmodbus.slave.ModbusSlaveFactory;
import com.intelligt.modbus.jlibmodbus.tcp.TcpParameters;
import io.github.talelin.latticy.model.TPSensorValueDO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.List;//springboot启动时创建tcp slave
@Component
public class ModbusSlaveUtilimplements CommandLineRunner
{@Overridepublic void run(String... args) throws Exception {Thread.sleep(10000);new Thread(new Runnable() {@Overridepublic void run() {createSalve();}}).start();}private static int[] arr = new int[]{0,0};public static ModbusSlave slave ;public void createSalve(){try{initSlave();System.out.println("slave start...........");createDataHolder();closeSlave();}catch (Exception e){}}public static void initSlave() throws UnknownHostException, ModbusIOException {TcpParameters tcpParameters = new TcpParameters();// 设置从机TCP参数InetAddress adress = InetAddress.getByName("127.0.0.1");// 设置TCP的ip地址// getLocalHost()返回的是本机地址// tcpParameters.setHost(InetAddress.getLocalHost());tcpParameters.setHost(adress); // 为从机TCP设置上述ip地址参数// 设置从机TCP的是否长连接,通俗点讲就是一直保持连接,一次连接完下次就不要在连接了tcpParameters.setKeepAlive(true);tcpParameters.setPort(Modbus.TCP_PORT);// 设置从机TCP的端口// 创建一个从机slave = ModbusSlaveFactory.createModbusSlaveTCP(tcpParameters);// 设置控制台输出主机和从机命令交互日志Modbus.setLogLevel(Modbus.LogLevel.LEVEL_DEBUG);}public void createDataHolder() throws ModbusIOException {// 创建从机的寄存器MyOwnDataHolder dh = new MyOwnDataHolder();// 为从机寄存器添加监听事件,这里的监听事件主要是主机如果发送写命令修改从机则控制台输出dh.addEventListener(new ModbusEventListener() {@Overridepublic int[] readHoldingRegisterRange(int offset, int quantity){System.out.println("readHoldingRegisterRange: 读取信息 offset = " + offset+";quantity"+quantity);try{updateHoldingRegisters(offset, quantity);}catch (Exception e){e.printStackTrace();}return arr;}@Overridepublic int[] readInputRegisterRange(int offset, int quantity){System.out.println("readInputRegisterRange: 读取信息 offset = " + offset+";quantity"+quantity);try{updateInputRegisters(offset, quantity);}catch (Exception e){e.printStackTrace();}return arr;}@Overridepublic void onWriteToSingleCoil(int address, boolean value) {System.out.print("onWriteToSingleCoil: address " + address + ", value " + value);}@Overridepublic void onWriteToMultipleCoils(int address, int quantity, boolean[] values) {System.out.print("onWriteToMultipleCoils: address " + address + ", quantity "+ quantity);}@Overridepublic void onWriteToSingleHoldingRegister(int address, int value) {System.out.print("onWriteToSingleHoldingRegister: address " + address+ ", value " + value);}@Overridepublic void onWriteToMultipleHoldingRegisters(int address, int quantity,int[] values) {System.out.print("onWriteToMultipleHoldingRegisters: address " + address+ ", quantity " + quantity);}});// 为从机设置寄存器slave.setDataHolder(dh);// 设置从机的读超时时间,建议主机读的超时时间小于该值slave.setReadTimeout(1500);// 为从机设置从机服务地址slaveidslave.setServerAddress(1);// 开启从机监听事件,必须要这一句slave.listen();}public static void closeSlave() throws InterruptedException, ModbusIOException {//这部分代码主要是设置Java虚拟机关闭的时候需要做的事情,即本程序关闭的时候需要做的事情,直接使用即可if (slave.isListening()) {Runtime.getRuntime().addShutdownHook(new Thread(() -> {synchronized (slave) {slave.notifyAll();}}));synchronized (slave) {slave.wait();}slave.shutdown();System.out.println("slave shutdown........");}}public void updateHoldingRegisters(int offset, int quantity) throws IllegalDataAddressException, IllegalDataValueException {List<Float> list =  Arrays.asList(10.1f,20.3f,89.5f,77.353f);ModbusHoldingRegisters hr = new ModbusHoldingRegisters(10000);// 修改数值寄存器对应位置的值,第一个参数代表寄存器地址,第二个代表修改的数值//hr.set有几个方法,根据自己要赋值的数据类型选择,此处示例的是赋值float类型,一个float是4个字节,32bit,对应2个寄存器所以i*2for(int i=0;i<list.size();i++){hr.setFloat32At(i*2, list.get(i));}slave.getDataHolder().setHoldingRegisters(hr);}public void updateInputRegisters(int offset, int quantity) throws IllegalDataAddressException, IllegalDataValueException, ModbusIOException {List<Float> list =  Arrays.asList(10.1f,20.3f,89.5f,77.353f);ModbusHoldingRegisters hr = new ModbusHoldingRegisters(10000);// 修改数值寄存器对应位置的值,第一个参数代表寄存器地址,第二个代表修改的数值for(int i=0;i<list.size();i++){hr.setFloat32At(i*2, list.get(i));}slave.getDataHolder().setInputRegisters(hr);}}

ModbusEventListener 接口

public interface ModbusEventListener {int[] readHoldingRegisterRange(int offset, int quantity);int[] readInputRegisterRange(int offset, int quantity);void onWriteToSingleCoil(int address, boolean value);void onWriteToMultipleCoils(int address, int quantity, boolean[] values);void onWriteToSingleHoldingRegister(int address, int value);void onWriteToMultipleHoldingRegisters(int address, int quantity, int[] values);}

MyOwnDataHolder 继承jlibmodbus类库中的DataHolder

import com.intelligt.modbus.jlibmodbus.data.DataHolder;
import com.intelligt.modbus.jlibmodbus.exception.IllegalDataAddressException;import java.util.ArrayList;
import java.util.List;public class MyOwnDataHolder extends DataHolder {final List<ModbusEventListener> modbusEventListenerList = new ArrayList<ModbusEventListener>();public MyOwnDataHolder() {// you can place the initialization code here/** something like that: setHoldingRegisters(new* SimpleHoldingRegisters(10)); setCoils(new Coils(128)); ... etc.*/}public void addEventListener(ModbusEventListener listener) {modbusEventListenerList.add(listener);}public boolean removeEventListener(ModbusEventListener listener) {return modbusEventListenerList.remove(listener);}@Overridepublic int[] readHoldingRegisterRange(int offset, int quantity) throws IllegalDataAddressException {for (ModbusEventListener l : modbusEventListenerList) {l.readHoldingRegisterRange(offset, quantity);}return super.readHoldingRegisterRange(offset, quantity);}@Overridepublic int[] readInputRegisterRange(int offset, int quantity) throws IllegalDataAddressException{for (ModbusEventListener l : modbusEventListenerList) {l.readInputRegisterRange(offset, quantity);}return super.readInputRegisterRange(offset, quantity);}@Overridepublic void writeHoldingRegister(int offset, int value) throws IllegalDataAddressException,IllegalDataValueException {for (ModbusEventListener l : modbusEventListenerList) {l.onWriteToSingleHoldingRegister(offset, value);}super.writeHoldingRegister(offset, value);}@Overridepublic void writeHoldingRegisterRange(int offset, int[] range)throws IllegalDataAddressException, IllegalDataValueException {for (ModbusEventListener l : modbusEventListenerList) {l.onWriteToMultipleHoldingRegisters(offset, range.length, range);}super.writeHoldingRegisterRange(offset, range);}@Overridepublic void writeCoil(int offset, boolean value) throws IllegalDataAddressException,IllegalDataValueException {for (ModbusEventListener l : modbusEventListenerList) {l.onWriteToSingleCoil(offset, value);}super.writeCoil(offset, value);}@Overridepublic void writeCoilRange(int offset, boolean[] range) throws IllegalDataAddressException,IllegalDataValueException {for (ModbusEventListener l : modbusEventListenerList) {l.onWriteToMultipleCoils(offset, range.length, range);}super.writeCoilRange(offset, range);}}

测试

启动程序,用MODSCAN模拟modbus主机读取数据,本例从机发送的是float,使用MODSCAN测试时工具栏上的数据类型选浮点数就可以直接显示出正确的数据了

参考文章 Java实现ModBus的slave端(从机server端,发送数据),代码略有修改,添加了监听读取保持寄存器和读取输入寄存器的方法,并在监听到读事件时给寄存器赋值。

还有在一开始run()的时候,增加一个线程去处理业务,进而不至于阻塞主线程的启动,也不会因为出错致使主线程挂掉。因为原来的代码是在主线程上开启监听slave,在开发工具中运行正常,部署到tomcat上运行起来访问不到url,连tomcat主页都显示不出来。这个问题可以参考这篇文章:Spring Boot中实现CommandLineRunner完成启动时加载数据在内外置tomcat条件下的启动差异及正确的使用姿势

Modbus通讯协议(四)——Java实现ModbusTCP Slave(从机)相关推荐

  1. 一文搞懂物联网Modbus通讯协议

    简介: 一般来说,常见的物联网通讯协议众多,如蓝牙.Zigbee.WiFi.ModBus.PROFINET.EtherCAT.蜂窝等.而在众多的物联网通讯协议中,Modbus是当前非常流行的一种通讯协 ...

  2. modbus通讯协议详解

    1.Modbus协议简介 Modbus协议是一种广泛应用于当今工业控制领域的通用通信协议.通过此协议,控制器相互之间.或者控制器经由网路(如以太网)可以和其他设备之间进行通信.Modbus协议使用的是 ...

  3. modbus通讯协议详解(转载)

    转载自:https://www.cnblogs.com/The-explosion/p/11512677.html modbus通讯协议详解 1.Modbus 协议简介  Modbus协议是一种已广泛 ...

  4. STM32移植modbus通讯协议简明教程

    目录 一.本文讨论内容 二.工具与源码 三.Modbus概述 四.Modbus-RTU通讯协议 五.完成Modbus输入输出代码 六.完成Modbus逻辑功能 七.测试与验证 一.本文讨论内容 本文简 ...

  5. Modbus通讯协议学习文档

    1 什么是Modbus通讯协议 Modbus是一种串行通信协议,是Modicon公司(现在的施耐德电气Schneider Electric)于1979年为使用可编程逻辑控制器(PLC)通信而发表.Mo ...

  6. Modbus通讯协议的原文和详解

    这个协议很早以前就被公开发表了,现在Modbus已经成为工业领域通信协议的业界标准,有网站专门进行协议的整理和管理. 这里必须要吐槽一下,我就想查查协议发布时的原始文档,或者这个协议的英文原文和官方版 ...

  7. modbus rtu与计算机通讯,Modbus通讯协议原来是这么回事!看完秒懂了

    原标题:Modbus通讯协议原来是这么回事!看完秒懂了 [www.gkwo.net]工程师必备网站 导语:ModBus网络是一个工业通信系统,由带智能终端的可编程序控制器和计算机通过公用线路或局部专用 ...

  8. 杭州金田电磁转换器MODBUS通讯协议

    杭州金田电磁转换器MODBUS通讯协议 通讯协议采用标准MODBUS RTU通讯协议.仪表为从机. RTU消息帧定义 数据通讯由主机发起,主机首先发送RTU消息帧,消息帧发送至少要以3.5个字符时间的 ...

  9. 经过整理的Modbus通讯协议详解(一)

    Modbus通讯协议简介 Modbus协议 Modbus协议最初由Modicon公司开发出来,在1979年末该公司成为施耐德自动化(Schneider Automation)部门的一部分,现在Modb ...

最新文章

  1. 基于yolo4和yolo3(pytorch)的口罩识别的对比
  2. 大数据开发实战:数据仓库技术
  3. 基础练习 字母图形(找规律)
  4. 9.OD-断点、命令
  5. Java面试,如何在短时间内做突击
  6. 设计一个名为complex的类来表示复数_CAE必修课:结构动力优化设计_搜狐汽车
  7. qt 运动控制软件 界面_开源库分享----一款跨平台图形界面的百度网盘不限速客户端...
  8. linux shell中怎样批量修改文件名为 文件夹_文件名
  9. Sublime Text 3中SublimeLinter的使用
  10. 内核模块的加载与卸载
  11. Win10系统中英文切换
  12. php如何让图片大小自适应,dedecms怎么让图片自适应屏幕大小
  13. 小程序应用 饿了么美团外卖cps领券返利小程序+前端(带三级分销裂变)
  14. DVB电视机顶盒工作原理
  15. nodejs实现微博第三方登录
  16. jQuery第5章上机练习3(使用jQuery变换网页效果)
  17. 日常生活 之 有哪些道理是你慢慢才明白的?
  18. JavaScript中if嵌套
  19. IPHONE开发 VIEW之间的相互切换
  20. 使用百度翻译api支持中转英,中简转中繁等等

热门文章

  1. Win10取消文件默认打开方式
  2. uefi装完系统后无法引导_不重装系统修改引导方式为UEFI模式
  3. 蔡颖-《APS走向实践》书解读之三:供应、计划排程、供应链优化
  4. 告诉你Windows PE 是什么东东?详细介绍一下winpe
  5. TXT文件批量生成二维码
  6. 等了3个月终于来啦!传智播客C/C++视频教程开始更新喽~
  7. 每日一练——回文链表
  8. 荣耀x10更新鸿蒙,华为手机不要乱买,这4款是最值得选择的,全都可升级到鸿蒙系统...
  9. 安卓仿微信录音功能实现
  10. Python生成城市热力图