国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Android 使用modbus協(xié)議與可能遇到的問(wèn)題解決一覽

這篇具有很好參考價(jià)值的文章主要介紹了Android 使用modbus協(xié)議與可能遇到的問(wèn)題解決一覽。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。


前言

本篇文章主要演示android的串口通訊功能,其中需要使用serialport模塊(下載鏈接),注意: 串口通訊需要root權(quán)限,需要將應(yīng)用設(shè)置成‘a(chǎn)ndroid:sharedUserId=“android.uid.system”’即可,如果出現(xiàn)串口通訊無(wú)法訪問(wèn)設(shè)備,首先看串口名稱與波特率是否一致,如果都一致看看是否是打開(kāi)串口就失敗了,如果出現(xiàn)無(wú)權(quán)限的情況,可能是Android開(kāi)發(fā)板不支持與該設(shè)備通訊,可以考慮讓嵌入式工程師使用單片機(jī)提供通訊訪問(wèn)能力,本篇文章只是演示android使用modbus協(xié)議,具體協(xié)議理論可以參考其它文章,這里不在講解。


一、導(dǎo)入模塊

implementation project(path: ':serialport')

二、協(xié)議相關(guān)

1. CRC16

package com.jujiang.fyc.myttftwo.utils.modbus;

import java.util.Arrays;

public class CRC16 {
    private static final byte[] crc16_tab_h = { (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
            (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80,
            (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0,
            (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00,
            (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81,
            (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0,
            (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01,
            (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80,
            (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1,
            (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00,
            (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81,
            (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0,
            (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00,
            (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81,
            (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0,
            (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00,
            (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80,
            (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1,
            (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01,
            (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80,
            (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1,
            (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00,
            (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81,
            (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1,
            (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01,
            (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
            (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81,
            (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1,
            (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01,
            (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40 };

    private static final byte[] crc16_tab_l = { (byte) 0x00, (byte) 0xC0, (byte) 0xC1, (byte) 0x01,
            (byte) 0xC3, (byte) 0x03, (byte) 0x02, (byte) 0xC2, (byte) 0xC6, (byte) 0x06, (byte) 0x07,
            (byte) 0xC7, (byte) 0x05, (byte) 0xC5, (byte) 0xC4, (byte) 0x04, (byte) 0xCC, (byte) 0x0C,
            (byte) 0x0D, (byte) 0xCD, (byte) 0x0F, (byte) 0xCF, (byte) 0xCE, (byte) 0x0E, (byte) 0x0A,
            (byte) 0xCA, (byte) 0xCB, (byte) 0x0B, (byte) 0xC9, (byte) 0x09, (byte) 0x08, (byte) 0xC8,
            (byte) 0xD8, (byte) 0x18, (byte) 0x19, (byte) 0xD9, (byte) 0x1B, (byte) 0xDB, (byte) 0xDA,
            (byte) 0x1A, (byte) 0x1E, (byte) 0xDE, (byte) 0xDF, (byte) 0x1F, (byte) 0xDD, (byte) 0x1D,
            (byte) 0x1C, (byte) 0xDC, (byte) 0x14, (byte) 0xD4, (byte) 0xD5, (byte) 0x15, (byte) 0xD7,
            (byte) 0x17, (byte) 0x16, (byte) 0xD6, (byte) 0xD2, (byte) 0x12, (byte) 0x13, (byte) 0xD3,
            (byte) 0x11, (byte) 0xD1, (byte) 0xD0, (byte) 0x10, (byte) 0xF0, (byte) 0x30, (byte) 0x31,
            (byte) 0xF1, (byte) 0x33, (byte) 0xF3, (byte) 0xF2, (byte) 0x32, (byte) 0x36, (byte) 0xF6,
            (byte) 0xF7, (byte) 0x37, (byte) 0xF5, (byte) 0x35, (byte) 0x34, (byte) 0xF4, (byte) 0x3C,
            (byte) 0xFC, (byte) 0xFD, (byte) 0x3D, (byte) 0xFF, (byte) 0x3F, (byte) 0x3E, (byte) 0xFE,
            (byte) 0xFA, (byte) 0x3A, (byte) 0x3B, (byte) 0xFB, (byte) 0x39, (byte) 0xF9, (byte) 0xF8,
            (byte) 0x38, (byte) 0x28, (byte) 0xE8, (byte) 0xE9, (byte) 0x29, (byte) 0xEB, (byte) 0x2B,
            (byte) 0x2A, (byte) 0xEA, (byte) 0xEE, (byte) 0x2E, (byte) 0x2F, (byte) 0xEF, (byte) 0x2D,
            (byte) 0xED, (byte) 0xEC, (byte) 0x2C, (byte) 0xE4, (byte) 0x24, (byte) 0x25, (byte) 0xE5,
            (byte) 0x27, (byte) 0xE7, (byte) 0xE6, (byte) 0x26, (byte) 0x22, (byte) 0xE2, (byte) 0xE3,
            (byte) 0x23, (byte) 0xE1, (byte) 0x21, (byte) 0x20, (byte) 0xE0, (byte) 0xA0, (byte) 0x60,
            (byte) 0x61, (byte) 0xA1, (byte) 0x63, (byte) 0xA3, (byte) 0xA2, (byte) 0x62, (byte) 0x66,
            (byte) 0xA6, (byte) 0xA7, (byte) 0x67, (byte) 0xA5, (byte) 0x65, (byte) 0x64, (byte) 0xA4,
            (byte) 0x6C, (byte) 0xAC, (byte) 0xAD, (byte) 0x6D, (byte) 0xAF, (byte) 0x6F, (byte) 0x6E,
            (byte) 0xAE, (byte) 0xAA, (byte) 0x6A, (byte) 0x6B, (byte) 0xAB, (byte) 0x69, (byte) 0xA9,
            (byte) 0xA8, (byte) 0x68, (byte) 0x78, (byte) 0xB8, (byte) 0xB9, (byte) 0x79, (byte) 0xBB,
            (byte) 0x7B, (byte) 0x7A, (byte) 0xBA, (byte) 0xBE, (byte) 0x7E, (byte) 0x7F, (byte) 0xBF,
            (byte) 0x7D, (byte) 0xBD, (byte) 0xBC, (byte) 0x7C, (byte) 0xB4, (byte) 0x74, (byte) 0x75,
            (byte) 0xB5, (byte) 0x77, (byte) 0xB7, (byte) 0xB6, (byte) 0x76, (byte) 0x72, (byte) 0xB2,
            (byte) 0xB3, (byte) 0x73, (byte) 0xB1, (byte) 0x71, (byte) 0x70, (byte) 0xB0, (byte) 0x50,
            (byte) 0x90, (byte) 0x91, (byte) 0x51, (byte) 0x93, (byte) 0x53, (byte) 0x52, (byte) 0x92,
            (byte) 0x96, (byte) 0x56, (byte) 0x57, (byte) 0x97, (byte) 0x55, (byte) 0x95, (byte) 0x94,
            (byte) 0x54, (byte) 0x9C, (byte) 0x5C, (byte) 0x5D, (byte) 0x9D, (byte) 0x5F, (byte) 0x9F,
            (byte) 0x9E, (byte) 0x5E, (byte) 0x5A, (byte) 0x9A, (byte) 0x9B, (byte) 0x5B, (byte) 0x99,
            (byte) 0x59, (byte) 0x58, (byte) 0x98, (byte) 0x88, (byte) 0x48, (byte) 0x49, (byte) 0x89,
            (byte) 0x4B, (byte) 0x8B, (byte) 0x8A, (byte) 0x4A, (byte) 0x4E, (byte) 0x8E, (byte) 0x8F,
            (byte) 0x4F, (byte) 0x8D, (byte) 0x4D, (byte) 0x4C, (byte) 0x8C, (byte) 0x44, (byte) 0x84,
            (byte) 0x85, (byte) 0x45, (byte) 0x87, (byte) 0x47, (byte) 0x46, (byte) 0x86, (byte) 0x82,
            (byte) 0x42, (byte) 0x43, (byte) 0x83, (byte) 0x41, (byte) 0x81, (byte) 0x80, (byte) 0x40 };

    /**
     * 計(jì)算CRC16校驗(yàn)
     *
     * @param data
     *            需要計(jì)算的數(shù)組
     * @return CRC16校驗(yàn)值
     */
    public static int compute(byte[] data) {
        return compute(data, 0, data.length);
    }

    /**
     * 校驗(yàn)byte數(shù)據(jù)是否是CRC16數(shù)據(jù)
     * @return 是否成功
     */
    public static boolean checkCRC16(byte[] data) {
        int size = data.length;
        if (size <= 2) {
            return false;
        }
        byte[] oldCheckArray = new byte[]{ data[size - 2], data[size - 1]};
        // 將數(shù)據(jù)拆分成三分
        byte[] bytes = new byte[size - 2];
        System.arraycopy(data, 0, bytes, 0, size - 2);
        // 計(jì)算CRC校驗(yàn)碼
        int crc = compute(bytes);
        ByteArrayWriter request = new ByteArrayWriter();
        request.writeInt16Reversal(crc);
        byte[] checkArray = request.toByteArray();
        return Arrays.equals(oldCheckArray, checkArray);
    }

    /**
     * 計(jì)算CRC16校驗(yàn)
     *
     * @param data
     *            需要計(jì)算的數(shù)組
     * @param offset
     *            起始位置
     * @param len
     *            長(zhǎng)度
     * @return CRC16校驗(yàn)值
     */
    public static int compute(byte[] data, int offset, int len) {
        return compute(data, offset, len, 0xffff);
    }

    /**
     * 計(jì)算CRC16校驗(yàn)
     *
     * @param data
     *            需要計(jì)算的數(shù)組
     * @param offset
     *            起始位置
     * @param len
     *            長(zhǎng)度
     * @param preval
     *            之前的校驗(yàn)值
     * @return CRC16校驗(yàn)值
     */
    public static int compute(byte[] data, int offset, int len, int preval) {
        int ucCRCHi = (preval & 0xff00) >> 8;
        int ucCRCLo = preval & 0x00ff;
        int iIndex;
        for (int i = 0; i < len; ++i) {
            iIndex = (ucCRCLo ^ data[offset + i]) & 0x00ff;
            ucCRCLo = ucCRCHi ^ crc16_tab_h[iIndex];
            ucCRCHi = crc16_tab_l[iIndex];
        }
        int result=((ucCRCHi & 0x00ff) << 8) | (ucCRCLo & 0x00ff) & 0xffff;
        return result;
    }
}

2. ByteUtil

package com.jujiang.fyc.myttftwo.utils.modbus;

public class ByteUtil {
    public static String toHexString(byte[] input, String separator) {
        if (input==null) return null;

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < input.length; i++) {
            if (separator != null && sb.length() > 0) {
                sb.append(separator);
            }
            String str = Integer.toHexString(input[i] & 0xff);
            if (str.length() == 1) str = "0" + str;
            sb.append(str);
        }
        return sb.toString();
    }

    public static String toHexString(byte[] input) {
        return toHexString(input, " ");
    }

    public static byte[] fromInt32(int input){
        byte[] result=new byte[4];
        result[3]=(byte)(input >> 24 & 0xFF);
        result[2]=(byte)(input >> 16 & 0xFF);
        result[1]=(byte)(input >> 8 & 0xFF);
        result[0]=(byte)(input & 0xFF);
        return result;
    }

    public static byte[] fromInt16(int input){
        byte[] result=new byte[2];
        result[0]=(byte)(input >> 8 & 0xFF);
        result[1]=(byte)(input & 0xFF);
        return result;
    }

    public static byte[] fromInt16Reversal(int input){
        byte[] result=new byte[2];
        result[1]=(byte)(input>>8&0xFF);
        result[0]=(byte)(input&0xFF);
        return result;
    }
}

3. ModbusError

package com.jujiang.fyc.myttftwo.utils.modbus;

import android.text.TextUtils;

public class ModbusError extends Exception {
    private int code;

    public ModbusError(int code, String message) {
        super(!TextUtils.isEmpty(message) ? message : "Modbus Error: Exception code = " + code);
        this.code = code;
    }

    public ModbusError(int code) {
        this(code, null);
    }

    public ModbusError(ModbusErrorType type, String message) {
        super(type.name() + ": " + message);
    }

    public ModbusError(String message) {
        super(message);
    }

    public int getCode() {
        return this.code;
    }
}

4. ModbusErrorType

package com.jujiang.fyc.myttftwo.utils.modbus;

/**
 * 常見(jiàn)的Modbus通訊錯(cuò)誤
 */
public enum ModbusErrorType {
    ModbusError,
    ModbusFunctionNotSupportedError,
    ModbusDuplicatedKeyError,
    ModbusMissingKeyError,
    ModbusInvalidBlockError,
    ModbusInvalidArgumentError,
    ModbusOverlapBlockError,
    ModbusOutOfBlockError,
    ModbusInvalidResponseError,
    ModbusInvalidRequestError,
    ModbusTimeoutError
}

5. ModbusFunction

package com.jujiang.fyc.myttftwo.utils.modbus;

/**
 * 功能碼(十進(jìn)制顯示)
 */
public class ModbusFunction {

    //讀線圈寄存器
    public static final int READ_COILS = 1;

    //讀離散輸入寄存器
    public static final int READ_DISCRETE_INPUTS = 2;

    //讀保持寄存器
    public static final int READ_HOLDING_REGISTERS = 3;

    //讀輸入寄存器
    public static final int READ_INPUT_REGISTERS = 4;

    //寫單個(gè)線圈寄存器
    public static final int WRITE_SINGLE_COIL = 5;

    //寫單個(gè)保持寄存器
    public static final int WRITE_SINGLE_REGISTER = 6;

    //寫入多個(gè)線圈寄存器
    public static final int WRITE_COILS = 15;

    //寫入多個(gè)保持寄存器
    public static final int WRITE_HOLDING_REGISTERS = 16;
}

6. ModbusRtuMaster

package com.jujiang.fyc.myttftwo.utils.modbus;

// 提供協(xié)議部分功能
public class ModbusRtuMaster {
    /**
     * 組裝Modbus RTU消息幀
     *
     * @param slave            從站地址號(hào)
     * @param function_code    功能碼
     * @param starting_address 讀取寄存器起始地址 / 寫入寄存器地址 / 寫入寄存器起始地址
     * @param quantity_of_x    讀取寄存器個(gè)數(shù) / 寫入寄存器個(gè)數(shù)
     * @param output_value     需要寫入單個(gè)寄存器的數(shù)值
     * @param output_values    需要寫入多個(gè)寄存器的數(shù)組
     * @return 將整個(gè)消息幀轉(zhuǎn)成byte[]
     * @throws ModbusError Modbus錯(cuò)誤
     */
    synchronized byte[] execute(int slave, int function_code, int starting_address, int quantity_of_x,
                                        int output_value, int[] output_values) throws ModbusError {
        //檢查參數(shù)是否符合協(xié)議規(guī)定
        if (slave < 0 || slave > 0xff) {
            throw new ModbusError(ModbusErrorType.ModbusInvalidArgumentError, "Invalid slave " + slave);
        }
        if (starting_address < 0 || starting_address > 0xffff) {
            throw new ModbusError(ModbusErrorType.ModbusInvalidArgumentError, "Invalid starting_address " + starting_address);
        }
        if (quantity_of_x < 1 || quantity_of_x > 0xff) {
            throw new ModbusError(ModbusErrorType.ModbusInvalidArgumentError, "Invalid quantity_of_x " + quantity_of_x);
        }

        // 構(gòu)造request
        ByteArrayWriter request = new ByteArrayWriter();
        //寫入從站地址號(hào)
        request.writeInt8(slave);
        //根據(jù)功能碼組裝數(shù)據(jù)區(qū)
        //如果為讀取寄存器指令
        if (function_code == ModbusFunction.READ_COILS || function_code == ModbusFunction.READ_DISCRETE_INPUTS
                || function_code == ModbusFunction.READ_INPUT_REGISTERS || function_code == ModbusFunction.READ_HOLDING_REGISTERS) {
            request.writeInt8(function_code);
            request.writeInt16(starting_address);
            request.writeInt16(quantity_of_x);

        } else if (function_code == ModbusFunction.WRITE_SINGLE_COIL || function_code == ModbusFunction.WRITE_SINGLE_REGISTER) {//寫單個(gè)寄存器指令
            if (function_code == ModbusFunction.WRITE_SINGLE_COIL)
                if (output_value != 0) output_value = 0xff00;//如果為線圈寄存器(寫1時(shí)為 FF 00,寫0時(shí)為00 00)
            request.writeInt8(function_code);
            request.writeInt16(starting_address);
            request.writeInt16(output_value);

        } else if (function_code == ModbusFunction.WRITE_COILS) {//寫多個(gè)線圈寄存器
            request.writeInt8(function_code);
            request.writeInt16(starting_address);
            request.writeInt16(quantity_of_x);

            //計(jì)算寫入字節(jié)數(shù)
            int writeByteCount = (quantity_of_x / 8) + 1;/// 滿足關(guān)系-> (w /8) + 1
            //寫入數(shù)量 == 8 ,則寫入字節(jié)數(shù)為1
            if (quantity_of_x % 8 == 0) {
                writeByteCount -= 1;
            }
            request.writeInt8(writeByteCount);

            int index = 0;
            //如果寫入數(shù)據(jù)數(shù)量 > 8 ,則需要拆分開(kāi)來(lái)
            int start = 0;//數(shù)組開(kāi)始位置
            int end = 7;//數(shù)組結(jié)束位置
            int[] splitData = new int[8];
            //循環(huán)寫入拆分?jǐn)?shù)組,直到剩下最后一組 元素個(gè)數(shù) <= 8 的數(shù)據(jù)
            while (writeByteCount > 1) {
                writeByteCount--;
                int sIndex = 0;
                for (index = start; index <= end; index++) {
                    splitData[sIndex++] = output_values[index];
                }
                //數(shù)據(jù)反轉(zhuǎn) 對(duì)于是否要反轉(zhuǎn)要看你傳過(guò)來(lái)的數(shù)據(jù),如果高低位順序正確則不用反轉(zhuǎn)
                splitData = reverseArr(splitData);
                //寫入拆分?jǐn)?shù)組
                request.writeInt8(toDecimal(splitData));
                start = index;
                end += 8;
            }
            //寫入最后剩下的數(shù)據(jù)
            int last = quantity_of_x - index;
            int[] tData = new int[last];
            System.arraycopy(output_values, index, tData, 0, last);
            //數(shù)據(jù)反轉(zhuǎn) 對(duì)于是否要反轉(zhuǎn)要看你傳過(guò)來(lái)的數(shù)據(jù),如果高低位順序正確則不用反轉(zhuǎn)
            tData = reverseArr(tData);
            request.writeInt8(toDecimal(tData));
        } else if (function_code == ModbusFunction.WRITE_HOLDING_REGISTERS) {//寫多個(gè)保持寄存器
            request.writeInt8(function_code);
            request.writeInt16(starting_address);
            request.writeInt16(quantity_of_x);
            request.writeInt8(2 * quantity_of_x);
            //寫入數(shù)據(jù)
            for (int v : output_values) {
                request.writeInt16(v);
            }
        } else {
            throw new ModbusError(ModbusErrorType.ModbusFunctionNotSupportedError, "Not support function " + function_code);
        }
        byte[] bytes = request.toByteArray();
        //計(jì)算CRC校驗(yàn)碼
        int crc = CRC16.compute(bytes);
        request.writeInt16Reversal(crc);
        bytes = request.toByteArray();
        return bytes;
    }

    //將數(shù)組反轉(zhuǎn)
    private int[] reverseArr(int[] arr) {
        int[] tem = new int[arr.length];
        for (int i = 0; i < arr.length; i++) {
            tem[i] = arr[arr.length - 1 - i];
        }
        return tem;
    }

    //將int[1,0,0,1,1,0]數(shù)組轉(zhuǎn)換為十進(jìn)制數(shù)據(jù)
    private int toDecimal(int[] data) {
        int result = 0;
        if (data != null) {
            StringBuilder sData = new StringBuilder();
            for (int d : data) {
                sData.append(d);
            }
            try {
                result = Integer.parseInt(sData.toString(), 2);
            } catch (NumberFormatException e) {
                result = -1;
            }

        }
        return result;
    }
}

7. ByteArrayWriter

package com.jujiang.fyc.myttftwo.utils.modbus;

import java.io.ByteArrayOutputStream;

public class ByteArrayWriter extends ByteArrayOutputStream {
    public ByteArrayWriter() {
        super();
    }

    public void writeInt8(byte b)
    {
        this.write(b);
    }

    public void writeInt8(int b)
    {
        this.write((byte)b);
    }

    public void writeInt16(int n) {
        byte[] bytes = ByteUtil.fromInt16(n);
        this.write(bytes, 0, bytes.length);
    }

    public void writeInt16Reversal(int n){
        byte[] bytes=ByteUtil.fromInt16Reversal(n);
        this.write(bytes,0,bytes.length);
    }

    public void writeInt32(int n) {
        byte[] bytes = ByteUtil.fromInt32(n);
        this.write(bytes, 0, bytes.length);
    }

    public void writeBytes(byte[] bs,int len){
        this.write(bs,0,len);
    }
}

8. ModbusRtuSerialPortUtil

package com.jujiang.fyc.myttftwo.utils.modbus

import android_serialport_api.SerialPort
import com.android.jws.JwsManager
import com.android.jws.JwsSerialPort
import com.jujiang.fyc.myttftwo.utils.LogUtils
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream

/**
 * 幫助Modbus 發(fā)送或接受數(shù)據(jù)
 */
class ModbusRtuSerialPortUtil {

    private var jwp: SerialPort? = null
    private var inputStream: InputStream? = null
    private var outputStream: OutputStream? = null

    fun open(device: String, baud: Int, dataBits: Int, parity: Int, stopBit: Int) {
        try {
            // 普通串口通訊
//            jwp = SerialPort(File(device), rate, 0)
            // 設(shè)置驗(yàn)證位等參數(shù)
            jwp = SerialPort(File(device), baud, parity, dataBits, stopBit)
            inputStream = jwp!!.inputStream
            outputStream = jwp!!.outputStream
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }

    // 發(fā)送數(shù)據(jù)
    fun send(bytes: ByteArray, millisecond: Long, block: (ByteArray, ByteArray) -> Unit) {
        try {
            LogUtils.e("bytes = ${bytes.map { String.format("%02x", *arrayOf<Any>(it)) }}")
            outputStream?.apply {
                write(bytes)
                flush()
            }
            Thread.sleep(millisecond)
            // 寫入數(shù)據(jù)
            val size = inputStream!!.available()
            val byteArray = ByteArray(size)
            inputStream!!.read(byteArray)
            block(bytes, byteArray)
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }
}

9. ModbusRtuMasterHelp

package com.jujiang.fyc.myttftwo.utils.modbus

import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.coroutines.resume

/**
 * 實(shí)際調(diào)用類
 */
class ModbusRtuMasterHelp(private val serialHelper: ModbusRtuSerialPortUtil) {
    private val modbusRtu: ModbusRtuMaster = ModbusRtuMaster()

    /**
     * 讀多個(gè)線圈寄存器
     * @param slave 從站地址
     * @param startAddress 起始地址
     * @param numberOfPoints 讀取線圈寄存器個(gè)數(shù)
     * @throws ModbusError Modbus錯(cuò)誤
     */
    fun readCoils(
        slave: Int,
        startAddress: Int,
        numberOfPoints: Int,
        millisecond: Long = 50,
        block: (ByteArray, ByteArray) -> Unit
    ) {
        val sendBytes = modbusRtu.execute(
            slave,
            ModbusFunction.READ_COILS,
            startAddress,
            numberOfPoints,
            0,
            null
        )
        this.serialHelper.send(sendBytes, millisecond, block)
    }

    //讀單個(gè)線圈寄存器
    fun readCoils(
        slave: Int,
        startAddress: Int,
        millisecond: Long = 50,
        block: (ByteArray, ByteArray) -> Unit
    ) {
        readCoils(slave, startAddress, 1, millisecond, block)
    }

    // 異步讀取并返回結(jié)果
    suspend fun readCoilsAsync(slave: Int,
                               startAddress: Int,
                               millisecond: Long = 50): Pair<ByteArray, ByteArray> {
        return suspendCancellableCoroutine { continuation ->
            readCoils(slave, startAddress, millisecond) { old, new ->
                continuation.resume(Pair(old, new))
            }
        }
    }

    /**
     * 寫單個(gè)線圈寄存器
     * @param slave 從站地址
     * @param address 寫入寄存器地址
     * @param value 寫入值(true/false)
     * @throws ModbusError Modbus錯(cuò)誤
     */
    fun writeSingleCoil(
        slave: Int, address: Int, value: Boolean, millisecond: Long = 50,
        block: (ByteArray, ByteArray) -> Unit
    ) {
        val sendBytes = modbusRtu.execute(
            slave,
            ModbusFunction.WRITE_SINGLE_COIL,
            address,
            1,
            if (value) 1 else 0,
            null
        )
        this.serialHelper.send(sendBytes, millisecond, block)
    }

    // 異步寫并返回結(jié)果
    suspend fun writeSingleCoilAsync(slave: Int, address: Int, value: Boolean, millisecond: Long = 50): Pair<ByteArray, ByteArray> {
        return suspendCancellableCoroutine { continuation ->
            writeSingleCoil(slave, address, value, millisecond) { old, new ->
                continuation.resume(Pair(old, new))
            }
        }
    }
}

三、使用

class MainActivity : BaseBindingActivity<ActivityMainBinding>({
    ActivityMainBinding.inflate(it)
}) {
    private val modbusRtuSerialPortUtil by lazy { ModbusRtuSerialPortUtil() }
    private val modbusRtuSerialPort by lazy { ModbusRtuMasterHelp(modbusRtuSerialPortUtil) }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // 連接串口, 一定要保證串口是能正常的讀寫, 否則會(huì)導(dǎo)致后續(xù)讀寫操作失效, 如果提示無(wú)權(quán)限, 只能讓嵌入式工程師
        // 使用單片機(jī)來(lái)做通訊, Android以普通串口讀取方式來(lái)使用, 如果能正常讀取成功, 可以采用實(shí)例方法
        modbusRtuSerialPortUtil.open("/dev/ttyS3", 19200, 8, 2, 1)
        // 同步讀取線圈, 參數(shù)1: 地址; 參數(shù)2: 線圈地址; 返回參數(shù)1: 表示發(fā)送時(shí)的byte數(shù)組; 參數(shù)2: 表示設(shè)備回發(fā)的數(shù)據(jù)數(shù)組
        modbusRtuSerialPort.readCoils(0x01, 0x0A) { oldAray, byteArray -> }
        // 異步讀取在協(xié)程中操作即可
        lifecycleScope.launch(Dispatchers.IO) {
            // 在協(xié)程中可以讀取的操作方式有很多種, 這里只演示一種, 如果只是需要讀一個(gè)那可以不需要使用 async 包裹
            async {
                val (oldArray, byteArray) = modbusRtuSerialPort.readCoilsAsync(0x01, 0x0A)
                // CRC16.checkCRC16 用于校驗(yàn)返回?cái)?shù)據(jù)的后兩位是否符合協(xié)議驗(yàn)證, 如果不符合則需要聯(lián)系設(shè)備商修改
                if (CRC16.checkCRC16(byteArray)) {
                }
            }.await()
        }
        // 同步寫數(shù)據(jù), 參數(shù)1: 地址; 參數(shù)2: 線圈地址; 參數(shù)3: 需要寫入的內(nèi)容,線圈操作類似于按鈕,所以只需要true/false即可;
        // 返回參數(shù)1: 表示發(fā)送時(shí)的byte數(shù)組; 參數(shù)2: 表示設(shè)備回發(fā)的數(shù)據(jù)數(shù)組
        // 異步寫入這里就不在演示了, 目前沒(méi)涉及到需要異步寫入的需求
        modbusRtuSerialPort.writeSingleCoil(0x01, 0x00, true) { oldAray, byteArray ->
            // 校驗(yàn)兩次數(shù)據(jù)是否相等,不相等即表示操作失敗
            if (oldAray.contentEquals(byteArray)) {
            }
        }
    }
}

總結(jié)

本篇文章主要記錄Android使用modbus協(xié)議, 其中遇到了按照本篇文章中的方式去讀取后會(huì)提示無(wú)權(quán)限的情況或?qū)懭霐?shù)據(jù)無(wú)返回, 對(duì)該情況的推測(cè)是串口的打開(kāi)是成功的但是沒(méi)有寫入數(shù)據(jù)到設(shè)備中, 因?yàn)槿绻跊](méi)打開(kāi)或打開(kāi)失敗會(huì)拋出異常, 通過(guò)協(xié)調(diào)之后得到的結(jié)論是設(shè)備并不支持Android主板, 解決方案是讓嵌入式工程師使用單片機(jī)做一個(gè)中間層,單片機(jī)只負(fù)責(zé)與設(shè)備連接與數(shù)據(jù)寫入操作, Android這邊按照modbus協(xié)議發(fā)送數(shù)據(jù)給單片機(jī), 單片機(jī)將數(shù)據(jù)發(fā)送給設(shè)備, 設(shè)備回發(fā)數(shù)據(jù)后單片機(jī)讀取數(shù)據(jù)后寫入數(shù)據(jù), Android讀取數(shù)據(jù)拿到實(shí)際結(jié)果, 該方案可以解決實(shí)際問(wèn)題。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-621648.html

到了這里,關(guān)于Android 使用modbus協(xié)議與可能遇到的問(wèn)題解決一覽的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Ubuntu20.04安裝sql server(內(nèi)含多個(gè)可能遇到的問(wèn)題以及解決方法)

    Ubuntu20.04安裝sql server(內(nèi)含多個(gè)可能遇到的問(wèn)題以及解決方法)

    這學(xué)期的課程有數(shù)據(jù)庫(kù),因此今天(2022.3.6)在ubuntu上安裝了sql server2019 即使根據(jù)官方指引進(jìn)行安裝也會(huì)遇到不少問(wèn)題,因此為在這里總結(jié)了我自己遇到的所有問(wèn)題,以及給出了相應(yīng)的解決方案,希望能為后來(lái)的人解決一些困惑和麻煩 根據(jù)指引,在終端輸入第一條語(yǔ)句:(導(dǎo)入

    2024年02月05日
    瀏覽(92)
  • Unity連接數(shù)據(jù)庫(kù)mysql全過(guò)程+可能遇到的問(wèn)題與解決方案

    Unity連接數(shù)據(jù)庫(kù)mysql全過(guò)程+可能遇到的問(wèn)題與解決方案

    目錄 一、具備條件 二、unity連接mysql 三、問(wèn)題總結(jié) 1. Mysql安裝完成 ????????安裝完成后需要查看mysql的版本,打開(kāi)終端(管理者身份運(yùn)行),輸入以下語(yǔ)句登錄mysql,查看MySQL版本; 可以看到我下載的版本是 5.7.38; 2. MySQL Connector/NET下載 目的:為了搭建unity連接mysql的環(huán)境

    2024年02月03日
    瀏覽(23)
  • 使用 Ant Design Vue 你可能會(huì)遇到的14個(gè)問(wèn)題

    公司有一個(gè)新需求,在原來(lái)項(xiàng)目基礎(chǔ)上開(kāi)發(fā),項(xiàng)目中使用 Ant Design Vue,版本是 1.X ,在此記錄下遇到的問(wèn)題;對(duì)于沒(méi)有使用過(guò)或者使用程度不深的同學(xué)來(lái)說(shuō),希望可以幫助你在開(kāi)發(fā)中遇到問(wèn)題時(shí)有個(gè)參考。對(duì)于已經(jīng)熟練使用的同學(xué),可能這些問(wèn)題都遇到過(guò),歡迎大家在評(píng)論區(qū)補(bǔ)

    2024年02月08日
    瀏覽(25)
  • Android 使用外置USB麥克風(fēng)MIC錄音遇到問(wèn)題并解決(含錄音播放源碼)

    Android 使用外置USB麥克風(fēng)MIC錄音遇到問(wèn)題并解決(含錄音播放源碼)

    使用RK3399的開(kāi)發(fā)板,跑Android8.1系統(tǒng) 一開(kāi)始插上外置的USB麥克風(fēng)的時(shí)候,無(wú)法使用 查看USB麥克風(fēng)拔插過(guò)程的debug打印日志 插入U(xiǎn)SB麥克風(fēng)后,adb 查詢當(dāng)前聲卡信息 cat cards 通過(guò)分析發(fā)現(xiàn),USB麥克風(fēng)設(shè)備沒(méi)有枚舉出來(lái),節(jié)點(diǎn)都沒(méi)掛載上去 這時(shí)候就懷疑是硬件問(wèn)題, USB麥克風(fēng)設(shè)備

    2024年02月09日
    瀏覽(31)
  • 關(guān)于Qt適配不同分辨率和縮放率時(shí)可能遇到的問(wèn)題和解決方案

    如果沒(méi)有特殊的處理,Qt的UI窗口在不同的分辨率和縮放率下,其顯示效果可能會(huì)出現(xiàn)問(wèn)題,常見(jiàn)的有: 子控件堆疊,無(wú)法顯示完整 窗口尺寸變大,超出屏幕的顯示范圍 控件變形,長(zhǎng)寬比不合理 界面模糊 字體變大,控件尺寸卻沒(méi)有變化 有兩種方式可以對(duì)UI界面進(jìn)行良好的縮

    2024年02月05日
    瀏覽(26)
  • Android 老項(xiàng)目導(dǎo)入可能遇到的問(wèn)題 Unsupported Java. Your build is currently configured to use Java 17.0.6 and Gr

    Unsupported Java. Your build is currently configured to use Java 17.0.6 and Gradle 5.4.1. Possible solution: Upgrade Gradle wrapper to 7.2 version and re-import the project 意思是當(dāng)前的Java17.0.6,需要升級(jí)到7.2. 原本這個(gè)項(xiàng)目執(zhí)行不是Java17,本地使用了更高的Java版本,因此同步需要更新gradle。 當(dāng)然,可以更新gradl

    2024年02月07日
    瀏覽(25)
  • 神器抓包工具 HTTP Analyzer v7.5 的下載,安裝,使用,破解說(shuō)明以及可能遇到的問(wèn)題

    神器抓包工具 HTTP Analyzer v7.5 的下載,安裝,使用,破解說(shuō)明以及可能遇到的問(wèn)題

    A1: HTTP Analyzer 是一款抓取網(wǎng)絡(luò)數(shù)據(jù)包的軟件,能夠?qū)ψト〉臄?shù)據(jù)包進(jìn)行分析。 A2:下載鏈接:http://pan.baidu.com/s/1bG7KU6。 A3:解壓剛剛下載好的軟件,選擇如下圖所示的setup.exe點(diǎn)擊安裝,一路next即可完成。 完成后桌面會(huì)生成一個(gè)相應(yīng)的圖標(biāo): A4:(1)雙擊剛剛的桌面圖標(biāo),

    2024年02月08日
    瀏覽(27)
  • Android 打包可能遇到的報(bào)錯(cuò)

    Android 打包可能遇到的報(bào)錯(cuò)

    問(wèn)題一:com.android.ide.common.signing.KeytoolException: Failed to read key testxlk from store “E:AndroidAndroid Keystestkey.jks”: Invalid keystore format 升高gradle JDK版本,我這里用了JDK11 問(wèn)題二:Integrity check failed: java.security.NoSuchAlgorithmException: Algorithm HmacPBESHA256 not available 在解決問(wèn)題一時(shí)升級(jí)到JDK1

    2024年04月11日
    瀏覽(29)
  • 可能會(huì)解決你Android studio中g(shù)radle安裝的問(wèn)題

    可能會(huì)解決你Android studio中g(shù)radle安裝的問(wèn)題

    我的電腦讓我不小心弄出了很多小毛病,我忍不了了,重裝了系統(tǒng) 然后在我配置as時(shí)發(fā)現(xiàn)gradle竟然出現(xiàn)了好多問(wèn)題,看了好多的帖子發(fā)現(xiàn)都對(duì)我沒(méi)用?。?! 概括 問(wèn)題是下載gradle超時(shí) 檢查是否有.gradle這個(gè)文件,有則改名,沒(méi)有的話就先下載,看報(bào)不報(bào)錯(cuò),報(bào)錯(cuò)了就看下一步(

    2024年02月03日
    瀏覽(22)
  • Windows 11 安裝 pytorch3d可能遇到的問(wèn)題,以及最終成功安裝使用的版本分享(使用RTX3070)

    Windows 11 安裝 pytorch3d可能遇到的問(wèn)題,以及最終成功安裝使用的版本分享(使用RTX3070)

    Win10下pytorch3D安裝方法 ??由于pytorch3d對(duì)于pytorch、CUDA、CUB的版本對(duì)應(yīng)實(shí)在是過(guò)于嚴(yán)苛,所以我的建議是直接找別人成功安裝的軟件版本列表對(duì)著抄,pytorch啥的該重裝重裝,反正可以用虛擬環(huán)境,CUDA也是,一臺(tái)電腦共存兩個(gè)版本的CUDA也不是不行。唯一麻煩一點(diǎn)的可能就是G

    2024年02月20日
    瀏覽(22)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包