android java 开发 使用modbus TCP/IP

本文详细介绍了在Android应用中使用Modbus4j库进行Modbus通信的步骤,包括配置权限、引入jar包、创建工具类以及读取不同类型的Modbus数据。通过创建Modbus4jReadUtils工具类,实现了读取线圈、输入状态、保持寄存器和输入寄存器的功能,并提供了批量读取的示例。需要注意的是,Modbus操作不能在主线程中执行,建议使用定时任务或其他异步方式处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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);

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值