java中使用modbusTcp与plc通信
Posted FreeFly辉
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java中使用modbusTcp与plc通信相关的知识,希望对你有一定的参考价值。
本人只是用此协议写过上位机,所以这里介绍的只是在java中的一些使用
首先引入jar包
<dependency>
<groupId>com.intelligt.modbus</groupId>
<artifactId>jlibmodbus</artifactId>
<version>1.2.9.7</version>
</dependency>
下面是自己封装的统一连接类
@Data
@Slf4j
public class ModBusConnector {
private static final Map<InetAddress, ModBusConnector> connectorMap = new HashMap<>();
private static final int MOD_BUS_PORT = 502;
private static final int SERVER_ADDRESS = 1;
private static final boolean KEEP_ALIVE = true;
private final ModbusMaster modbusMaster;
private final InetAddress ip;
protected ModBusConnector(ModbusMaster modbusMaster,InetAddress ip) {
this.modbusMaster = modbusMaster;
this.ip = ip;
}
public static ModBusConnector fetchOrCreate(InetAddress ip, int timeout) {
ModBusConnector connector = connectorMap.get(ip);
if (connector == null) {
ModbusMaster masterTCP = ModbusMasterFactory.createModbusMasterTCP(new TcpParameters(ip, MOD_BUS_PORT, KEEP_ALIVE));
connector = new ModBusConnector(masterTCP, ip);
}
log.info("ModBus connector connecting: {}", connector);
connector.getModbusMaster().setResponseTimeout(timeout);
try {
connector.getModbusMaster().connect();
log.info("ModBus connector connected: {}", connector);
} catch (ModbusIOException e) {
throw new IllegalStateException(e+ip.getHostAddress());
}
return connector;
}
public static ModBusConnector fetchOrCreate(InetAddress ip) {
return fetchOrCreate(ip, 3000);
}
public ReadHoldingRegistersResponse readRegisters(PlcReadRequest readRequest) {
return WrappingUtil.runWithRetry(() -> {
final long sending = System.currentTimeMillis();
// log.debug("sending modbus read request: " +
// "waiting consume {}ms, ip={}, request={}", (sending - wait), ip, readRequest);
ModbusRequest request;
synchronized (modbusMaster) {
try {
if (!modbusMaster.isConnected()) {
modbusMaster.connect();
}
request = ModbusRequestBuilder.getInstance().buildReadHoldingRegisters(SERVER_ADDRESS,readRequest.getStartAddress(),readRequest.getQuantity());
final ReadHoldingRegistersResponse response = (ReadHoldingRegistersResponse) modbusMaster.processRequest(request);
if (response.isException()) {
throw new IllegalStateException("ModBus返回异常:" + response.getModbusExceptionCode());
}
final long sent = System.currentTimeMillis();
log.debug("Successfully sent modbus read request : " +
"sending consume {}ms, ip={}, request={}, response: {}"
,(sent - sending),ip,readRequest,response.getHoldingRegisters().getRegisters());
return response;
} catch (Exception e) {
if (isConnected()) {
disconnect();
}
throw new IllegalStateException(e);
}
}
}, PlcConfig.getRetryTimes(),new IllegalStateException("failed refresh rgv status"+ip.getHostAddress()));
}
public void writeRegisters(PlcWriteRequest writeRequest) {
WrappingUtil.runWithRetry (() -> {
final long wait = System.currentTimeMillis ();
final long sending = System.currentTimeMillis ();
log.debug ("sending modbus write request: " +
"waiting consume {}ms, ip={}, request={}", (sending - wait), ip, writeRequest);
ModbusRequest request;
synchronized (modbusMaster) {
try {
if (!modbusMaster.isConnected()) {
modbusMaster.connect();
}
request = ModbusRequestBuilder.getInstance().buildWriteMultipleRegisters(SERVER_ADDRESS,writeRequest.getStartAddress(),writeRequest.getRegisters());
ModbusResponse response = modbusMaster.processRequest(request);
final long sent = System.currentTimeMillis();
log.info("successfully sent modbus write request : time={}" +
"sending consume {}ms, ip={}, request={}, response: {}",System.currentTimeMillis(),(sent - sending),ip,writeRequest,response.getModbusExceptionCode());
} catch (Exception e) {
if (isConnected()) {
disconnect();
}
throw new IllegalStateException(e);
}
}
}, PlcConfig.getRetryTimes (),new IllegalStateException("failed send command rgv status"+ip.getHostAddress()));
}
public boolean isConnected() {
return modbusMaster.isConnected();
}
public void disconnect() {
if (modbusMaster != null) {
if (!modbusMaster.isConnected()) {
log.info("connection already disconnected {}",this);
} else {
try {
modbusMaster.disconnect();
} catch (ModbusIOException e) {
log.info("modbus disconnected false: {}",this,e);
throw new IllegalStateException(e);
}
log.info("modbus disconnected success: {}",this);
}
}
}
}
代码快中用到了自己封装的工具类会放在文章结尾,这里截图解释以下关键部分
建立连接
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210507150921420.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NjQxNTE4OQ==,size_16,color_FFFFFF,t_70)读请求
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210507151446793.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NjQxNTE4OQ==,size_16,color_FFFFFF,t_70)写请求
关键理解
java中每个 int 是 4个字节 32位,但是寄存器中int数据类型是 16 位,而一个int类型就是寄存器中的一个地址位。好比我想在 寄存器的第2个地址位的倒数第2个bit位写入 1,那么java中构建的就是
int [2] = new int[2]
int[1] = 1<<2//第几个bit位就要向前移几位
注意,此时随在第二个地址位写了 数值 2,但是由于java中int默认值是0,所以这样构建还会把第一个地址位数据置0,所以如果不想影响到第一个地址为数值,需要如下构建
int [1] = new int[1]
int[0] = 1<<2//第几个bit位就要向前移几位
此时下发时起始地址为要携程 1,不能再是 0
还有一点要注意的,一个plc中一个int如果只用了 8 个bit位,那么这 8个bit位是 16位中的高8位,即先高8位后低8位。
以上是关于java中使用modbusTcp与plc通信的主要内容,如果未能解决你的问题,请参考以下文章
西门子300PLC连接组态王KingSCADA实现ModbusTCP通信
三菱Q系列PLC与上位机易控组态软件ModbusTCP通信案例