modbus通信协议
主要分为三个子协议:
- rtu
- ascii
- tcp
modbus rtu:——传输的是字节数组(bit[])
- 通信:读写
- 输出:可以读写
- 输入:只能读
存储区:输出线圈、输入线圈、输出寄存器、输入寄存器
线圈:代表一个布尔量、最小单位是一个布尔(1或者0),
寄存器:一个寄存器代表16个最小单位,主要用于存储数据
存储区代号:
输出线圈: 0(代号)
- 00001-09999(标准存储区地址范围)
- 000001-065536(扩展存储区地址范围)
输入线圈:1
- 10001-19999
输出寄存器:4
- 40001-49999
输入寄存器:3
- 30001-39999
存储区范围:5位和6位
- 5位:标准地址-y xxxx
- 6位:扩展地址-y xxxxx
功能代码:

验证4个常用功能码,仿真软件上面有f=01,f=02,f=03和f=04来显示
- 0x01:读线圈
- 0x02:读离散量输入
- 0x03:读保持寄存器
- 0x04:读输入寄存器
测试使用modbus slave(下载) 模拟

- saveid:看资料"从站在modbus总线上可以有多个",仿真软件就能模拟一个从站,就是id=1,当然可以修改成id=2
- 功能码:4个功能码,对应写4个方法,,仿真软件上的f=1,或者f=2,3,4
- addr:一开始看代码4个方法addr都是从0开始,是否重复?答案是:4个功能码表示4个区域或者设备,addr表示各自区域的地址编号。
connection设置:设置连接参数

地址设置: f8 ,可以通过setup或者右击点位的


设置不同存储区

读取从站
代码实现
1、依赖下载
- 阿里云不能直接下载
<!-- 若想引用modbus4j需要引入下列repository id:ias-snapshots id:ias-releases 两个 ,使用默认仓库下载,不要使用阿里云仓库-->
<repositories>
<repository>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
<id>ias-snapshots</id>
<name>infinite automation snapshot repository</name>
<url>https://maven.mangoautomation.net/repository/ias-snapshot/</url>
</repository>
<repository>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>ias-releases</id>
<name>infinite automation release repository</name>
<url>https://maven.mangoautomation.net/repository/ias-release/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupid>junit</groupid>
<artifactid>junit</artifactid>
<version>4.13-beta-3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupid>com.infiniteautomation</groupid>
<artifactid>modbus4j</artifactid>
<version>3.0.3</version>
</dependency>
<dependency>
<groupid>org.apache.commons</groupid>
<artifactid>commons-lang3</artifactid>
<version>3.9</version>
</dependency>
</dependencies>
2、测试读取
- 读取04(寄存器)
import com.intelligt.modbus.jlibmodbus.modbus;
import com.intelligt.modbus.jlibmodbus.exception.modbusioexception;
import com.intelligt.modbus.jlibmodbus.master.modbusmaster;
import com.intelligt.modbus.jlibmodbus.master.modbusmasterfactory;
import com.intelligt.modbus.jlibmodbus.tcp.tcpparameters;
import java.net.inetaddress;
import java.net.unknownhostexception;
public class testmodbus {
public static void main(string[] args) throws unknownhostexception {
// 设置主机tcp参数
tcpparameters tcpparameters = new tcpparameters();
// 设置tcp的ip地址
inetaddress address = inetaddress.getbyname("127.0.0.1");
// tcp参数设置ip地址
tcpparameters.sethost(address);
// tcp设置长连接
tcpparameters.setkeepalive(true);
// tcp设置端口,这里设置是默认端口502
tcpparameters.setport(modbus.tcp_port);
// 创建一个主机
modbusmaster master = modbusmasterfactory.createmodbusmastertcp(tcpparameters);
modbus.setautoincrementtransactionid(true);
int slaveid = 1;//从机地址
int offset = 0;//寄存器读取开始地址
int quantity = 10;//读取的寄存器数量
try {
if (!master.isconnected()){
master.connect(); //开启连接
}
// 读取对应从机的数据,readinputregisters读取的写寄存器,功能码04
int[] registervalues4 = master.readinputregisters(slaveid,offset,quantity);
for (int value : registervalues4){
system.out.println("address:"+offset++ +",value:"+value);
}
}catch (exception e){
e.printstacktrace();
}finally {
try {
master.disconnect();
} catch (modbusioexception e) {
e.printstacktrace();
}
}
}
}
3、读取工具类
import com.serotonin.modbus4j.batchread;
import com.serotonin.modbus4j.batchresults;
import com.serotonin.modbus4j.modbusfactory;
import com.serotonin.modbus4j.modbusmaster;
import com.serotonin.modbus4j.code.datatype;
import com.serotonin.modbus4j.exception.errorresponseexception;
import com.serotonin.modbus4j.exception.modbusinitexception;
import com.serotonin.modbus4j.exception.modbustransportexception;
import com.serotonin.modbus4j.ip.ipparameters;
import com.serotonin.modbus4j.locator.baselocator;
public class modbus4jreadutils {
static modbusfactory modbusfactory;
static {
if (modbusfactory == null){
modbusfactory = new modbusfactory();
}
}
/***
* 初始化连接
* @return modbusmaster
*/
public static modbusmaster getmaster() throws modbusinitexception{
ipparameters params = new ipparameters();
params.sethost("localhost");
params.setport(502);
// modbusfactory.creatertumaster(wapper); //rtu 协议
// modbusfactory.createudpmaster(params);//udp 协议
// modbusfactory.createasciimaster(wrapper);//ascii 协议
// modbusmaster master = modbusfactory.crea
modbusmaster master = modbusfactory.createtcpmaster(params,false);
master.init();
return master;
}
/***
* 读取[01 coil status 0x]类型 开关数据
* @author zhengfuping
* @param slaveid 从站编号
* @param offset 偏移位置
* @return boolean
*/
public static boolean readcoilstatus(int slaveid,int offset) throws modbusinitexception, errorresponseexception, modbustransportexception {
baselocator<boolean> loc = baselocator.coilstatus(slaveid,offset);
boolean value = getmaster().getvalue(loc);
return value;
}
/**
* 读取[02 input status 1x]类型 开关数据
*
* @param slaveid 从站编号
* @param offset 偏移位
* @return
*/
public static boolean readinputstatus(int slaveid, int offset)
throws modbustransportexception, errorresponseexception, modbusinitexception {
// 02 input status
baselocator<boolean> loc = baselocator.inputstatus(slaveid, offset);
boolean value = getmaster().getvalue(loc);
return value;
}
/**
* 读取[03 holding register类型 2x]模拟量数据
* @param slaveid
* @param offset 位置
* @param datatype 数据类型,来自com.serotonin.modbus4j.code.datatype
*/
public static number readholdingregister(int slaveid, int offset, int datatype)
throws modbustransportexception, errorresponseexception, modbusinitexception {
// 03 holding register类型数据读取
baselocator<number> loc = baselocator.holdingregister(slaveid, offset, datatype);
number value = getmaster().getvalue(loc);
return value;
}
/**
* 读取[04 input registers 3x]类型 模拟量数据
*/
public static number readinputregisters(int slaveid, int offset, int datatype)
throws modbustransportexception, errorresponseexception, modbusinitexception {
// 04 input registers类型数据读取
baselocator<number> loc = baselocator.inputregister(slaveid, offset, datatype);
number value = getmaster().getvalue(loc);
return value;
}
// 批量读取
public static void batchread(integer count) throws modbusinitexception, errorresponseexception, modbustransportexception {
batchread<integer> batch = new batchread<integer>();
for (int i = 0; i <= count; i++) {
batch.addlocator(i,baselocator.holdingregister(1,i, datatype.two_byte_int_signed));
}
modbusmaster master =getmaster();
batch.setcontiguousrequests(false);
batchresults<integer> results = master.send(batch);
for (int i = 0; i <= count; i++) {
system.err.println(results.getvalue(i));
}
}
public static void main(string[] args) {
try {
// 01测试
boolean v011 = readcoilstatus(1,1);
boolean v012 = readcoilstatus(1,2);
boolean v013 = readcoilstatus(1,3);
system.out.println("v011:" + v011);
system.out.println("v012:" + v012);
system.out.println("v013:" + v013);
// 02测试
boolean v021 = readinputstatus(1, 1);
boolean v022 = readinputstatus(1, 2);
boolean v023 = readinputstatus(1, 3);
system.out.println("v021:" + v021);
system.out.println("v022:" + v022);
system.out.println("v023:" + v023);
// 03测试
number v031 = readholdingregister(1, 1, datatype.two_byte_int_signed);//signed
number v032 = readholdingregister(1, 2, datatype.two_byte_int_signed);// 同上
system.out.println("v031:" + v031);
system.out.println("v032:" + v032);
// 04测试
number v041 = readinputregisters(1, 1, datatype.two_byte_int_signed);//
number v042 = readinputregisters(1, 2, datatype.two_byte_int_signed);//
system.out.println("v041:" + v041);
system.out.println("v042:" + v042);
// 批量读取
batchread(9);
} catch (exception e) {
e.printstacktrace();
}
}
}
读取结果:

4、写入工具类
import com.serotonin.modbus4j.modbusfactory;
import com.serotonin.modbus4j.modbusmaster;
import com.serotonin.modbus4j.code.datatype;
import com.serotonin.modbus4j.exception.errorresponseexception;
import com.serotonin.modbus4j.exception.modbusinitexception;
import com.serotonin.modbus4j.exception.modbustransportexception;
import com.serotonin.modbus4j.ip.ipparameters;
import com.serotonin.modbus4j.locator.baselocator;
import com.serotonin.modbus4j.msg.*;
import org.apache.commons.logging.log;
import org.apache.commons.logging.logfactory;
public class modbus4jwriteutils {
static log log = logfactory.getlog(modbus4jwriteutils.class);
/**
* 工厂。
*/
static modbusfactory modbusfactory;
static {
if (modbusfactory == null) {
modbusfactory = new modbusfactory();
}
}
/**
* 获取tcpmaster
*
* @return
* @throws modbusinitexception
*/
public static modbusmaster getmaster() throws modbusinitexception {
ipparameters params = new ipparameters();
params.sethost("localhost");
params.setport(502);
modbusmaster tcpmaster = modbusfactory.createtcpmaster(params, false);
tcpmaster.init();
return tcpmaster;
}
/**
* 写 [01 coil status(0x)]写一个 function id = 5
* @param slaveid slave的id
* @param writeoffset 位置
* @param writevalue 值
*/
public static boolean writecoil(int slaveid, int writeoffset, boolean writevalue)
throws modbustransportexception, modbusinitexception {
// 获取master
modbusmaster tcpmaster = getmaster();
// 创建请求
writecoilrequest request = new writecoilrequest(slaveid, writeoffset, writevalue);
// 发送请求并获取响应对象
writecoilresponse response = (writecoilresponse) tcpmaster.send(request);
if (response.isexception()) {
return false;
} else {
return true;
}
}
/**
* 写[01 coil status(0x)] 写多个 function id = 15
* @param slaveid
* @param startoffset 开始位置
* @param bdata 写入的数据
* @return 是否写入成功
*/
public static boolean writecoils(int slaveid, int startoffset, boolean[] bdata)
throws modbustransportexception, modbusinitexception {
// 获取master
modbusmaster tcpmaster = getmaster();
// 创建请求
writecoilsrequest request = new writecoilsrequest(slaveid, startoffset, bdata);
// 发送请求并获取响应对象
writecoilsresponse response = (writecoilsresponse) tcpmaster.send(request);
if (response.isexception()) {
return false;
} else {
return true;
}
}
/***
* 写[03 holding register(4x)] 写一个 function id = 6
* @param slaveid
* @param writeoffset
* @param writevalue
*/
public static boolean writeregister(int slaveid, int writeoffset, short writevalue)
throws modbustransportexception, modbusinitexception {
// 获取master
modbusmaster tcpmaster = getmaster();
// 创建请求对象
writeregisterrequest request = new writeregisterrequest(slaveid, writeoffset, writevalue);
writeregisterresponse response = (writeregisterresponse) tcpmaster.send(request);
if (response.isexception()) {
log.error(response.getexceptionmessage());
return false;
} else {
return true;
}
}
/**
*
* 写入[03 holding register(4x)]写多个 function id=16
* @param slaveid
* @param startoffset 起始位置偏移量值
* @param sdata 写入的数据
*/
public static boolean writeregisters(int slaveid, int startoffset, short[] sdata)
throws modbustransportexception, modbusinitexception {
// 获取master
modbusmaster tcpmaster = getmaster();
// 创建请求对象
writeregistersrequest request = new writeregistersrequest(slaveid, startoffset, sdata);
// 发送请求并获取响应对象
modbusresponse response = tcpmaster.send(request);
if (response.isexception()) {
log.error(response.getexceptionmessage());
return false;
} else {
return true;
}
}
/**
* 写入数字类型的模拟量(如:写入float类型的模拟量、double类型模拟量、整数类型short、integer、long)
*
* @param slaveid
* @param offset
* @param value 写入值,number的子类,例如写入float浮点类型,double双精度类型,以及整型short,int,long
* @param datatype com.serotonin.modbus4j.code.datatype
*/
public static void writeholdingregister(int slaveid, int offset, number value, int datatype)
throws modbustransportexception, errorresponseexception, modbusinitexception {
// 获取master
modbusmaster tcpmaster = getmaster();
// 类型
baselocator<number> locator = baselocator.holdingregister(slaveid, offset, datatype);
tcpmaster.setvalue(locator, value);
}
public static void main(string[] args) {
try {
// 测试01 单个写入(0x)
boolean t01 = writecoil(1, 0, true);
system.out.println("t01:" + t01);
// 测试02 批量写入(0x)
boolean t02 = writecoils(1, 0, new boolean[] { true, false, true });
system.out.println("t02:" + t02);
// 测试03 单个写入(4x)
short v = -3;
boolean t03 = writeregister(1, 0, v);
system.out.println("t03:" + t03);
// 测试04 批量写入(4x)
boolean t04 = writeregisters(1, 0, new short[] { -309, 390, 91 });
system.out.println("t04:" + t04);
//写模拟量
writeholdingregister(1,8, 100, datatype.two_byte_int_signed);
} catch (exception e) {
e.printstacktrace();
}
}
}
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论