首页 > 基础资料 博客日记
Modbus通讯协议——Java通过Jlibmodbus实现Modbus Master(主机)TCP/RTU的Read;Slave(从机)TCP/RTU的Write
2024-07-14 07:00:05基础资料围观266次
一、首先了解一下Java实现Modbus的三种jar包
只做参考,有能力的话还是建议根据需求自行编写协议工具类
1. modbus4: 支持Modbus-RTU、 Modbus-ASCl.Modbus-TCP三种协议,支持Modbus-RTU over Senal, Modbus.RTU over TCPUDP、 Modbus-ASCl over sera
和 Modbus-TCP over TCP/UDP。但是该工具是同步的不支持异步,实时性要求不强可以使用。
2. ililbmodbus:支持Modbus-RTU和Modbus-TCP两种协议,支持Modbus-RTU over Serial、Modbus-RTU over TCP
Modbus-TCP over TCP,Modbus-TCP内部通
过socket实现支持异步。Modbus-RTU Serial通过RXTX实现。
modbus-master-tcp:支持Modbus-TCP一种协议,支持Modbus-TCP over TCP,内部通过netty实现支持异步。
可以执行扩展使其支持Modbus-RTU over TCP和Moc
bus-RTU over Serial
以上三个工具包的所有连接都没有断线重连功能,所以使用时需要自行解决断线重
二、主要针对Jlibmodbus实现Modbus的主机与从机’
1、导入依赖
另附Maven仓库地址:https://mvnrepository.com/
<!-- https://mvnrepository.com/artifact/com.intelligt.modbus/jlibmodbus -->
<dependency>
<groupId>com.intelligt.modbus</groupId>
<artifactId>jlibmodbus</artifactId>
<version>1.2.9.10</version>
</dependency>
2、Master主机模式:
1)、Modbus-TCP
import com.intelligt.modbus.jlibmodbus.Modbus;
import com.intelligt.modbus.jlibmodbus.master.ModbusMaster;
import com.intelligt.modbus.jlibmodbus.master.ModbusMasterFactory;
import com.intelligt.modbus.jlibmodbus.tcp.TcpParameters;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.InetAddress;
public class JlibmodbusMasterTcpReader {
public static void main(String[] args) throws Exception {
TcpParameters tcpParameters = new TcpParameters();
tcpParameters.setHost(InetAddress.getByName("127.0.0.1"));
tcpParameters.setPort(502);
tcpParameters.setKeepAlive(true);
int[] num = {1};
for (int n : num){
int[] ints = new JlibmodbusMasterTcpReader().modbusReads(n,tcpParameters);
System.out.println(ints[0]);
int second = ints[0];
int first = ints[1];
System.out.println(ints[1]);
// for (int m : ints){
// System.out.print(m);
// }
//在进行字符串转化时,转化的16进制会存在缺少一位的情况,进行左侧补零操作
String hexStr = addZeroForStr(Integer.toHexString(first),4,1)+""+addZeroForStr(Integer.toHexString(second),4,1);
System.out.println(new BigDecimal(sfloat(hexStr)));
System.out.println();
}
}
public int[] modbusReads(int serverAddress, TcpParameters tcpParameters) throws Exception {
ModbusMaster master = ModbusMasterFactory.createModbusMasterTCP(tcpParameters);
master.setResponseTimeout(3000);
master.connect();
Modbus.setAutoIncrementTransactionId(true);
int[] result = master.readInputRegisters(serverAddress,0, 10);
master.disconnect();
return result;
}
//将字符串类型的16进制数据,转化为float字符串
private static String sfloat(String str){
Float value = Float.intBitsToFloat(new BigInteger(str, 16).intValue());
return String.valueOf(value);
}
/**
* 给字符串的左补0或右补0
* @param str 要处理的字符串
* @param length 补0后字符串总长度
* @return 返回补零字符串
*/
public static String addZeroForStr(String str, int length, int type) {
int strLen = str.length();
if (strLen < length) {
while (strLen < length) {
StringBuffer sb = new StringBuffer();
if(type==1){
// 左补0
sb.append("0").append(str);
}else if(type==2){
//右补0
sb.append(str).append("0");
}
str = sb.toString();
strLen = str.length();
}
}
return str;
}
}
2)、Modbus-RTU
import com.intelligt.modbus.jlibmodbus.Modbus;
import com.intelligt.modbus.jlibmodbus.master.ModbusMaster;
import com.intelligt.modbus.jlibmodbus.master.ModbusMasterFactory;
import com.intelligt.modbus.jlibmodbus.serial.*;
import java.io.*;
public class JlibmodbusMasterRtuReader {
public static void main(String[] args) throws Exception {
SerialParameters params = new SerialParameters();
params.setDevice("COM2"); // 串口名称
params.setBaudRate(SerialPort.BaudRate.getBaudRate(9600)); // 波特率
params.setDataBits(8); // 数据位
params.setStopBits(1); // 停止位
params.setParity(SerialPort.Parity.getParity(0)); // 无校验
ModbusMaster master = ModbusMasterFactory.createModbusMasterRTU(params);
Modbus.setAutoIncrementTransactionId(true);
master.connect();
int[] registers = master.readHoldingRegisters(1, 0, 10);
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("C:\\Users\\user\\Desktop\\data.txt"));
for (int reg : registers){
System.out.println(reg);
bufferedWriter.write(reg + " ");
}
bufferedWriter.newLine();
bufferedWriter.close();
master.disconnect();
}
}
3、Slave-从机模式
1)、Modbus-TCP
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;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;
public class JlibmodbusSlaveTcpWriter {
public static void main(String[] args) {
try {
// 设置从机TCP参数
TcpParameters tcpParameters = new TcpParameters();
// 设置TCP的ip地址
InetAddress address = InetAddress.getByName("127.0.0.1");
// getLocalHost()返回的是本机地址
// tcpParameters.setHost(InetAddress.getLocalHost());
// 为从机TCP设置上述ip地址参数
tcpParameters.setHost(address);
// 设置从机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);
hr.set(1, 54321);
// 设置从机寄存器的01和02功能码对应的位寄存器,即只有false和true值(或0和1)
ModbusCoils mc = new ModbusCoils(16);
// 设置对应位寄存器地址的位值
mc.set(0, true);
// 为从机设置04功能码对应的数值寄存器
slave.getDataHolder().setInputRegisters(hr);
// 为从机设置03功能码对应的数值寄存器
slave.getDataHolder().setHoldingRegisters(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);
}
}
}
2)、Modbus-RTU
import com.intelligt.modbus.jlibmodbus.Modbus;
import com.intelligt.modbus.jlibmodbus.data.DataHolder;
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.serial.SerialParameters;
import com.intelligt.modbus.jlibmodbus.serial.SerialPort;
import com.intelligt.modbus.jlibmodbus.serial.SerialPortException;
import com.intelligt.modbus.jlibmodbus.slave.ModbusSlave;
import com.intelligt.modbus.jlibmodbus.slave.ModbusSlaveFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class JlibmodbusSlaveRtuWriter {
public static void main(String[] args) throws SerialPortException, IllegalDataValueException, IllegalDataAddressException, ModbusIOException {
SerialParameters serialParameters = new SerialParameters();
serialParameters.setDevice("COM1");
serialParameters.setBaudRate(SerialPort.BaudRate.getBaudRate(9600));
serialParameters.setDataBits(8);
serialParameters.setStopBits(1);
serialParameters.setParity(SerialPort.Parity.NONE);
ModbusSlave modbusSlave = ModbusSlaveFactory.createModbusSlaveRTU(serialParameters);
modbusSlave.setReadTimeout(2400);
Modbus.setLogLevel(Modbus.LogLevel.LEVEL_DEBUG);
MyDataHolder myDataHolder = new MyDataHolder();
myDataHolder.addEventListener(new EventListeners() {
@Override
public void readHoldingRegister(int address) {
System.out.println("使用03功能码读取保持寄存器的数据 address = " + address);
}
@Override
public void readHoldingRegisterRange(int address, int quantity) {
try {
ModbusHoldingRegisters integers = updateHoldingRegisters(address, quantity);
modbusSlave.getDataHolder().setHoldingRegisters(integers);
}catch (Exception e){
e.printStackTrace();
}
System.out.println("使用03功能码范围读取保持寄存器的数据 address = " + address + " 读取寄存器个数:" + quantity);
}
@Override
public void writeHoldingRegister(int address, int value) throws IllegalDataValueException, IllegalDataAddressException {
System.out.println("使用03功能码写入保持寄存器 address = " + address + " 值:" + value);
}
@Override
public void writeHoldingRegisterRange(int address, int[] values) {
System.out.println("使用03功能码批量写入保持寄存器 address = " + address + " 值:" + values.toString());
}
});
modbusSlave.setDataHolder(myDataHolder);
modbusSlave.setServerAddress(1);
// ModbusHoldingRegisters mm = new ModbusHoldingRegisters(10);
// mm.set(0, 1223);
// mm.set(1, 321);
// modbusSlave.getDataHolder().setHoldingRegisters(mm);
modbusSlave.listen();
}
public interface EventListeners{
void readHoldingRegister(int address);
void readHoldingRegisterRange(int address, int quantity);
void writeHoldingRegister(int address, int value) throws IllegalDataValueException, IllegalDataAddressException;
void writeHoldingRegisterRange(int address, int[] values);
}
public static class MyDataHolder extends DataHolder{
final List<EventListeners> eventListenerList = new ArrayList<>();
public void addEventListener(EventListeners eventListener){
eventListenerList.add(eventListener);
}
public boolean removeEventListener(EventListeners eventListener){
return eventListenerList.remove(eventListener);
}
@Override
public int readHoldingRegister(int offset) throws IllegalDataAddressException {
for (EventListeners e : eventListenerList){
e.readHoldingRegister(offset);
}
return super.readHoldingRegister(offset);
}
@Override
public int[] readHoldingRegisterRange(int offset, int quantity) throws IllegalDataAddressException {
for (EventListeners e : eventListenerList){
e.readHoldingRegisterRange(offset, quantity);
}
return super.readHoldingRegisterRange(offset, quantity);
}
@Override
public void writeHoldingRegister(int offset, int value) throws IllegalDataAddressException, IllegalDataValueException {
for (EventListeners e : eventListenerList){
e.writeHoldingRegister(offset, value);
}
super.writeHoldingRegister(offset, value);
}
@Override
public void writeHoldingRegisterRange(int offset, int[] range) throws IllegalDataAddressException, IllegalDataValueException {
for (EventListeners e : eventListenerList){
e.writeHoldingRegisterRange(offset, range);
}
super.writeHoldingRegisterRange(offset, range);
}
}
// 为从机设置03功能码对应的数值寄存器
public static ModbusHoldingRegisters updateHoldingRegisters(int offset, int quantity) throws IllegalDataAddressException, IllegalDataValueException {
List<Float> list = Arrays.asList(10.1f,20.3f,89.5f,73.353f);
ModbusHoldingRegisters hr = new ModbusHoldingRegisters(10000);
// 修改数值寄存器对应位置的值,第一个参数代表寄存器地址,第二个代表修改的数值
//hr.set有几个方法,根据自己要赋值的数据类型选择,此处示例的是赋值float类型,一个float是4个字节,32bit,对应2个寄存器所以i*2
for(int i=0;i<list.size();i++){
hr.setFloat32At(i*2, list.get(i));
}
return hr;
}
}
Modbus通讯协议(四)——Java实现ModbusTCP Slave(从机)_java搭建modbus slave-CSDN博客
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!
标签: