1.首先需要在 AndroidManifest.xml 配置开启权限
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
2.引入modbus.jar
讲目录切换到项目,然后再libs 下引入jar包,idea 在jar包 右键选择 Add as Library
eclipse Build path ->Add to build Path就可以完成了
3.然后 创建工具类
package com.example.androidapp.moubusUtil;
import com.serotonin.modbus4j.ModbusFactory;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.ip.IpParameters;
public class moubusUtil {
private static ModbusFactory modbusFactory;
static {
if (modbusFactory == null) {
modbusFactory = new ModbusFactory();
}
}
/**
* 获取Tcp master
*
* @param
* @param port
* @return
*/
public static ModbusMaster getMaster( int port) {
IpParameters params = new IpParameters();
params.setHost(ip);
params.setPort(port);
//这个属性确定了协议帧是否是通过tcp封装的RTU结构,采用modbus tcp/ip时,要设为false, 采用modbus rtu over tcp/ip时,要设为true
params.setEncapsulated(false);
// 参数1:IP和端口信息 参数2:保持连接激活
ModbusMaster master = null;
master = modbusFactory.createTcpMaster(params, true);
master.destroy();
try {
//设置超时时间
master.setTimeout(1000);
//设置重连次数
master.setRetries(0);
//初始化
master.init();
} catch (ModbusInitException e) {
master = null;
}
return master;
}
}
然后创建 Modbus4jReadUtils
package com.example.androidapp.moubusUtil;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.exception.ErrorResponseException;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.serotonin.modbus4j.msg.ReadCoilsRequest;
import com.serotonin.modbus4j.msg.ReadCoilsResponse;
import com.serotonin.modbus4j.msg.ReadDiscreteInputsRequest;
import com.serotonin.modbus4j.msg.ReadDiscreteInputsResponse;
import com.serotonin.modbus4j.msg.ReadHoldingRegistersRequest;
import com.serotonin.modbus4j.msg.ReadHoldingRegistersResponse;
import com.serotonin.modbus4j.msg.ReadInputRegistersRequest;
import com.serotonin.modbus4j.msg.ReadInputRegistersResponse;
public class Modbus4jReadUtils {
/**
* 读(线圈)开关量数据
* 功能码为:01; 读取开关量输出点的ON/OFF状态,可以读写的布尔类型(0x)---00001 至 0xxxx – 开关量输出
*
* @param slaveId slaveId-从站编号-自行约定
* @param offset 位置
* @return 读取值-读取多少个
*/
public boolean[] readCoilStatus(ModbusMaster master, int slaveId, int offset, int numberOfBits)
throws ModbusTransportException, ErrorResponseException, ModbusInitException {
ReadCoilsRequest request = new ReadCoilsRequest(slaveId, offset, numberOfBits);
ReadCoilsResponse response = (ReadCoilsResponse) master.send(request);
boolean[] booleans = response.getBooleanData();
return valueRegroup(numberOfBits, booleans);
}
/**
* 开关数据 读取外围设备输入的开关量
* 功能码为:02;读取开关量输入点的ON/OFF状态,只能读的布尔类型(1x)---10001 至 1xxxx – 开关量输入
*
* @param slaveId-从站编号-自行约定
* @param offset-预访问的地址-地址范围:0-255
* @param numberOfBits-读取多少个
* @return
* @throws ModbusTransportException
* @throws ErrorResponseException
* @throws ModbusInitException
*/
public boolean[] readInputStatus(ModbusMaster master, int slaveId, int offset, int numberOfBits)
throws ModbusTransportException, ErrorResponseException, ModbusInitException {
ReadDiscreteInputsRequest request = new ReadDiscreteInputsRequest(slaveId, offset, numberOfBits);
ReadDiscreteInputsResponse response = (ReadDiscreteInputsResponse) master.send(request);
boolean[] booleans = response.getBooleanData();
return valueRegroup(numberOfBits, booleans);
}
/**
* 读取保持寄存器数据
* 功能码为:03 读取保持寄存器的数据,可以读写的数字类型(4x)---40001 至 4xxxx – 保持寄存器
* <p>
* *举例子说明:S7-200
* Smart PLC中,设置 [HoldStr~]=&VB1000;则对应的保持寄存器地址为VW1000\VW1002\VW10004
* *在java中对应的address为:0、1、2
*
* @param slaveId slave Id-从站编号-自行约定
* @param offset 位置
* @param numberOfBits numberOfRegisters 寄存器个数 每个寄存器表示一个16位无符号整数 相当于一个short
*/
public static short[] readHoldingRegister(ModbusMaster master, int slaveId, int offset, int numberOfBits)
throws ModbusTransportException, ErrorResponseException, ModbusInitException {
ReadHoldingRegistersRequest request = new ReadHoldingRegistersRequest(slaveId, offset, numberOfBits);
ReadHoldingRegistersResponse response = (ReadHoldingRegistersResponse) master.send(request);
return response.getShortData();
}
/**
* 读取[03 Holding Register类型 2x]模拟量数据
*
* @param slaveId slave Id
* @param offset 位置
* @param dataType 数据类型,来自com.serotonin.modbus4j.code.DataType
* @return
* @throws ModbusTransportException 异常
* @throws ErrorResponseException 异常
* @throws ModbusInitException 异常
*/
// public static Number readHoldingRegisterByDataType(ModbusMaster master, int slaveId, int offset, int dataType)
// throws ModbusTransportException, ErrorResponseException, ModbusInitException {
// // 03 Holding Register类型数据读取
// BaseLocator<Number> loc = BaseLocator.holdingRegister(slaveId, offset, dataType);
// Number value = master.getValue(loc);
// return value;
// }
/**
* 读取外围设备输入的数据
* 功能码为:04 读取模拟量输入值,只能读的数字类型(3x)---30001 至 3xxxx – 模拟量输入
* <p>
* 举例子说明:S7-200 Smart PLC中,模拟量输入寄存器AIW16\AIW18,则对应
* java中对应的address为:8\9
*
* @param slaveId slaveId-从站编号-自行约定
* @param offset 位置-预访问的地址-地址范围:0-55
*/
public static short[] readInputRegisters(ModbusMaster master, int slaveId, int offset, int numberOfBits)
throws ModbusTransportException, ErrorResponseException, ModbusInitException {
ReadInputRegistersRequest request = new ReadInputRegistersRequest(slaveId, offset, numberOfBits);
ReadInputRegistersResponse response = (ReadInputRegistersResponse) master.send(request);
return response.getShortData();
}
/**
* 批量读取 可以批量读取不同寄存器中数据
*/
// public static void batchRead(ModbusMaster master) throws ModbusTransportException, ErrorResponseException, ModbusInitException {
// BatchRead<Integer> batch = new BatchRead<Integer>();
// batch.addLocator(0, BaseLocator.holdingRegister(1, 1, DataType.TWO_BYTE_INT_SIGNED));
// batch.addLocator(1, BaseLocator.inputStatus(1, 0));
// batch.setContiguousRequests(true);
// BatchResults<Integer> results = master.send(batch);
// System.out.println("batchRead:" + results.getValue(0));
// System.out.println("batchRead:" + results.getValue(1));
// }
/**
* 批量读取 可以批量读取不同寄存器中数据
*/
// public static void batchReadTest(ModbusMaster master, int slaveId, int offset, int dataType) throws ModbusTransportException, ErrorResponseException, ModbusInitException {
// BatchRead<Integer> batch = new BatchRead<Integer>();
BaseLocator<Number> loc = BaseLocator.holdingRegister(slaveId, offset, dataType);
Number value = master.getValue(loc);
// batch.addLocator(0, BaseLocator.holdingRegister(1, 2, DataType.TWO_BYTE_INT_SIGNED));
// batch.addLocator(1, BaseLocator.inputStatus(1, 0));
// batch.addLocator(2, BaseLocator.holdingRegister(slaveId, offset, dataType));
// batch.setContiguousRequests(true);
// BatchResults<Integer> results = master.send(batch);
// System.out.println("batchRead:" + results.getValue(0));
// System.out.println("batchRead:" + results.getValue(1));
// System.out.println("batchRead:" + results.getValue(2));
// }
/**
* 数据重组
*
* @param numberOfBits
* @param values
* @return
*/
private boolean[] valueRegroup(int numberOfBits, boolean[] values) {
boolean[] bs = new boolean[numberOfBits];
int temp = 1;
for (boolean b : values) {
bs[temp - 1] = b;
temp++;
if (temp > numberOfBits)
break;
}
return bs;
}
}
modbus 不能再主线程里面使用所以需要开启 new Thraed 我在这里使用的是timer
timer.schedule(new TimerTask() {
@Override
public void run() {
String ip = "192.168.10.201";
int port = 502;
ModbusMaster master = null;
// runOnUiThread(new Runnable() {
// @Override
// public void run() {
//
// set_time();
// }
// });
if (master == null) {
System.out.println("等待连接");
master = moubusUtil.getMaster(ip, port);
} else {
//我在这里使用的是 读取外围设备输入的数据 03x
System.out.println("连接成功");
ReadInputRegistersRequest request = null;
try {
request = new ReadInputRegistersRequest(1, 0, 41);
} catch (ModbusTransportException e) {
master.destroy();
}
ReadInputRegistersResponse response;
try {
response = (ReadInputRegistersResponse) master.send(request);
short[] btye = response.getShortData();
for (int i = 0; i < btye.length; i++) {
// System.out.println(btye[i] + "位" + i);
BatteryData.getInstance().add_data(i, btye[i]);
}
} catch (ModbusTransportException e) {
master.destroy();
}
}
}
}, 0, 1000);