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(); } } }
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论