Java实现ModBus的slave端(从机server端,发送数据)

什么是ModBus?如何学习ModBus?

       最近由于项目需要重新接触ModBus这个网络协议,ModBus这个协议的内容在网络上有很多,如果是刚接触这个协议的新手需要将这个协议的主要参数了解清楚,比如从机的IP地址和端口,从机的slaveid,功能码,寄存器地址等,了解清楚这些主要参数的作用后可以下载ModBus的模拟器进行测试,可以参考下面这篇文章学习模拟器的使用,点击访问

       ModBus的模拟器分为Poll端和Slave端,Poll端相当于TCP中的客户端(Client),Slave端相当于服务端(Server),因此网络上也有人将ModBus分为Client端和Server端。对TCP了解的人应该知道服务端Server是根据客户端Client的请求进行发送数据(这里可能说的不是很专业),ModBus的Slave端也是根据Poll端的一些请求进行发送数据,但是它的命令格式有些不一样,根据功能码的不同而不同,我的下一篇博客会详细介绍。关于ModBus模拟器的下载可以百度进行搜索,这是官网地址,点击下载,另外也可以访问我的博客资源下载,博客资源下载

Java实现ModBus从机Slave

       这篇博客的重点是介绍如何用Java实现modbus tcp从机通信,从机需要实现的功能是实时监听主机发送过来的命令,然后根据主机的命令进行对应的操作,如果是查询读命令,返回对应寄存器地址的值,如果是写命令,则修改对应寄存器地址的值。

       如果要通过自己个人的能力将这些通信机制利用Java来实现使很困难的,我查询了大量的资料和考察了很多不同的Java开源库,最后采用了jlibmodbus,之所以选择这个是因为它的doc文档写的很好,一些example写的很全,这里可以附上我在一个modbus的官方网站上找到该库网站,点击访问,它上面包含很多modbus的开源库,大家都可以进行下载使用,这里再附上我博客资源,点击下载jlibmodbus

      下载jlibmodbus的jar包后在eclipse中将该包和相关依赖包导入到工程中,然后可以直接使用下面的代码了。

       导入的jlibmodbus和相关依赖包如下图。

        

Java源码

import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;

import com.intelligt.modbus.jlibmodbus.Modbus;
import com.intelligt.modbus.jlibmodbus.data.DataHolder;
import com.intelligt.modbus.jlibmodbus.data.ModbusCoils;
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.slave.ModbusSlave;
import com.intelligt.modbus.jlibmodbus.slave.ModbusSlaveFactory;
import com.intelligt.modbus.jlibmodbus.tcp.TcpParameters;

public class ModBusSlaveTest {
        
	public static void main(String[] args) {
		try {
			// 设置从机TCP参数
			TcpParameters tcpParameters = new TcpParameters();

			// 设置TCP的ip地址
			InetAddress adress = InetAddress.getByName("127.0.0.1");

			// getLocalHost()返回的是本机地址
			// tcpParameters.setHost(InetAddress.getLocalHost());

			// 为从机TCP设置上述ip地址参数
			tcpParameters.setHost(adress);

			// 设置从机TCP的是否长连接,通俗点讲就是一直保持连接,一次连接完下次就不要在连接了
			tcpParameters.setKeepAlive(true);

			// 设置从机TCP的端口
			tcpParameters.setPort(Modbus.TCP_PORT);

			// 创建一个从机
			ModbusSlave slave = ModbusSlaveFactory.createModbusSlaveTCP(tcpParameters);
			// 设置控制台输出主机和从机命令交互日志
			Modbus.setLogLevel(Modbus.LogLevel.LEVEL_DEBUG);

			// 创建从机的寄存器
			MyOwnDataHolder dh = new MyOwnDataHolder();

			// 为从机寄存器添加监听事件,这里的监听事件主要是主机如果发送写命令修改从机则控制台输出
			dh.addEventListener(new ModbusEventListener() {
				@Override
				public void onWriteToSingleCoil(int address, boolean value) {
					System.out
							.print("onWriteToSingleCoil: address " + address + ", value " + value);
				}

				@Override
				public void onWriteToMultipleCoils(int address, int quantity, boolean[] values) {
					System.out.print("onWriteToMultipleCoils: address " + address + ", quantity "
							+ quantity);
				}

				@Override
				public void onWriteToSingleHoldingRegister(int address, int value) {
					System.out.print("onWriteToSingleHoldingRegister: address " + address
							+ ", value " + value);
				}

				@Override
				public void onWriteToMultipleHoldingRegisters(int address, int quantity,
						int[] values) {
					System.out.print("onWriteToMultipleHoldingRegisters: address " + address
							+ ", quantity " + quantity);
				}
			});

			// 为从机设置寄存器
			slave.setDataHolder(dh);
			// 设置从机的读超时时间,建议主机读的超时时间小于该值
			slave.setReadTimeout(1500);
			// 设置从机寄存器的03和04功能码对应的数值寄存器
			ModbusHoldingRegisters hr = new ModbusHoldingRegisters(10);
			// 修改数值寄存器对应位置的值,第一个参数代表寄存器地址,第二个代表修改的数值
			hr.set(0, 12345);
			// 设置从机寄存器的01和02功能码对应的位寄存器,即只有false和true值(或0和1)
			ModbusCoils mc = new ModbusCoils(16);
			// 设置对应位寄存器地址的位值
			mc.set(0, true);

			// 为从机设置04功能码对应的数值寄存器
			slave.getDataHolder().setInputRegisters(hr);
			// 为从机设置01功能码对应的数值寄存器
			slave.getDataHolder().setCoils(mc);
			// 为从机设置从机服务地址slaveid
			slave.setServerAddress(1);	
			// 开启从机监听事件,必须要这一句
			slave.listen();

			//这部分代码主要是设置Java虚拟机关闭的时候需要做的事情,即本程序关闭的时候需要做的事情,直接使用即可
			if (slave.isListening()) {
				Runtime.getRuntime().addShutdownHook(new Thread() {
					@Override
					public void run() {
						synchronized (slave) {
							slave.notifyAll();
						}
					}
				});

				synchronized (slave) {
					slave.wait();
				}

				/*
				 * using master-branch it should be #slave.close();
				 */
				slave.shutdown();
			}
		} catch (RuntimeException e) {
			throw e;
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	// 监听接口
	public interface ModbusEventListener {
		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);
	}

	// 寄存器类定义
	public static 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);
		}

		@Override
		public void writeHoldingRegister(int offset, int value) throws IllegalDataAddressException,
				IllegalDataValueException {
			for (ModbusEventListener l : modbusEventListenerList) {
				l.onWriteToSingleHoldingRegister(offset, value);
			}
			super.writeHoldingRegister(offset, value);
		}

		@Override
		public void writeHoldingRegisterRange(int offset, int[] range)
				throws IllegalDataAddressException, IllegalDataValueException {
			for (ModbusEventListener l : modbusEventListenerList) {
				l.onWriteToMultipleHoldingRegisters(offset, range.length, range);
			}
			super.writeHoldingRegisterRange(offset, range);
		}

		@Override
		public void writeCoil(int offset, boolean value) throws IllegalDataAddressException,
				IllegalDataValueException {
			for (ModbusEventListener l : modbusEventListenerList) {
				l.onWriteToSingleCoil(offset, value);
			}
			super.writeCoil(offset, value);
		}

		@Override
		public void writeCoilRange(int offset, boolean[] range) throws IllegalDataAddressException,
				IllegalDataValueException {
			for (ModbusEventListener l : modbusEventListenerList) {
				l.onWriteToMultipleCoils(offset, range.length, range);
			}
			super.writeCoilRange(offset, range);
		}
	}
}

 

  • 9
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值