java调用串口,开箱即用

作者:刘东标
撰写日期:2022-08-02

开发遇到问题:

1、供应商提供的动态库各种底层代码有问题,指针也不对,参数也乱,加上长年不维护动态库
2、解决多个动态库问题,不同供应商提供动态库也不同,32位动态库和64位动态库,还有是供应商的测试demo
3、C++和java调用jna底层代码出现溢出内存,导致很多问题
在这里插入图片描述

1、下载调用串口工具包

下载地址
我使用是86位串口工具

2、拷贝对应文件到jdk指定目录下

RXTXcomm.jar —> <JAVA_HOME>\jre\lib\ext
rxtxSerial.dll —> <JAVA_HOME>\jre\bin
rxtxParallel.dll —> <JAVA_HOME>\jre\bin

3、将工程导入jar

将RXTXcomm.jar安装到java工程中

4、串口工具示例代码

package com.xh.etc.util.serialport;

import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;
import gnu.io.SerialPortEventListener;
import gnu.io.CommPort;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.TooManyListenersException;


public class SerialPortManager {
    
    
    /**
     * 16进制直接转换成为字符串(无需Unicode解码)
     *
     * @param hexStr
     * @return
     */
    public static String hexStr2Str(String hexStr) {
    
    
        String str = "0123456789ABCDEF";
        hexStr = hexStr.replace(" ", "");
        char[] hexs = hexStr.toCharArray();
        byte[] bytes = new byte[hexStr.length() / 2];
        int n;
        for (int i = 0; i < bytes.length; i++) {
    
    
            n = str.indexOf(hexs[2 * i]) * 16;
            n += str.indexOf(hexs[2 * i + 1]);
            bytes[i] = (byte) (n & 0xff);
        }
        return new String(bytes);
    }

    /**
     * 将16进制转换为二进制
     *
     * @param hexString
     * @return
     */
    public static String hexString2binaryString(String hexString) {
    
    
        if (hexString == null || hexString.length() % 2 != 0)
            return null;
        String bString = "", tmp;
        for (int i = 0; i < hexString.length(); i++) {
    
    
            tmp = "0000" + Integer.toBinaryString(Integer.parseInt(hexString.substring(i, i + 1), 16));
            bString += tmp.substring(tmp.length() - 4);

        }
        //字符串反转
        return new StringBuilder(bString).reverse().toString();
    }


    //Byte数组转十六进制
    public static String byte2HexString(byte[] bytes) {
    
    
        String hex = "";
        if (bytes != null) {
    
    
            for (Byte b : bytes) {
    
    
                hex += String.format("%02X", b.intValue() & 0xFF);
            }
        }
        return hex;
    }

    //十六进制转Byte数组
    public static byte[] hexStringToByteArray(String s) {
    
    
        int len = s.length();
        byte[] data = new byte[len / 2];
        try {
    
    
            for (int i = 0; i < len; i += 2) {
    
    
                data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                        + Character.digit(s.charAt(i + 1), 16));
            }
        } catch (Exception e) {
    
    
            // Log.d("", "Argument(s) for hexStringToByteArray(String s)"+ "was not a hex string");
        }
        return data;
    }

    /**
     * 查找所有可用端口
     *
     * @return 可用端口名称列表
     */
    @SuppressWarnings("unchecked")
    public static final ArrayList<String> findPort() {
    
    
        // 获得当前所有可用串口
        Enumeration<CommPortIdentifier> portList = CommPortIdentifier
                .getPortIdentifiers();
        ArrayList<String> portNameList = new ArrayList<String>();
        // 将可用串口名添加到List并返回该List
        while (portList.hasMoreElements()) {
    
    
            String portName = portList.nextElement().getName();
            portNameList.add(portName);
        }
        return portNameList;
    }

    /**
     * 打开串口
     *
     * @param portName 端口名称
     * @param baudrate 波特率
     * @return 串口对象
     */
    public static final SerialPort openPort(String portName, int baudrate, int DATABITS, int Parity)
            throws Exception {
    
    
        // 通过端口名识别端口
        CommPortIdentifier portIdentifier = CommPortIdentifier
                .getPortIdentifier(portName);
        // 打开端口,设置端口名与timeout(打开操作的超时时间)
        CommPort commPort = portIdentifier.open(portName, 2000);
        // 判断是不是串口
        if (commPort instanceof SerialPort) {
    
    
            SerialPort serialPort = (SerialPort) commPort;


            // 设置串口的波特率等参数
            serialPort.setSerialPortParams(baudrate,
                    DATABITS, SerialPort.STOPBITS_1,
                    Parity);
            return serialPort;
        }
        return null;
    }

    /**
     * 关闭串口
     *
     * @param
     */
    public static void closePort(SerialPort serialPort) {
    
    
        if (serialPort != null) {
    
    
            serialPort.close();
        }
    }

    /**
     * 向串口发送数据
     *
     * @param serialPort 串口对象
     * @param order      待发送数据
     *                   关闭串口对象的输出流出错
     */
    public static void sendToPort(SerialPort serialPort, byte[] order)
            throws Exception {
    
    
        OutputStream out = null;
        try {
    
    
            out = serialPort.getOutputStream();
            out.write(order);
            out.flush();
            Thread.sleep(100);//间隔20ms
        } catch (IOException e) {
    
    
            throw new Exception();
        } finally {
    
    
            try {
    
    
                if (out != null) {
    
    
                    out.close();

                }
            } catch (IOException e) {
    
    
                throw new Exception();
            }
        }
    }

    /**
     * 从串口读取数据
     *
     * @param serialPort 当前已建立连接的SerialPort对象
     * @return 读取到的数据
     */
    public static byte[] readFromPort(SerialPort serialPort)
            throws Exception {
    
    
        InputStream in = null;
        byte[] bytes = null;
        try {
    
    
            in = serialPort.getInputStream();
            // 获取buffer里的数据长度
            int bufflenth = in.available();
            while (bufflenth != 0) {
    
    
                // 初始化byte数组为buffer中数据的长度
                bytes = new byte[bufflenth];
                in.read(bytes);
                bufflenth = in.available();
            }
        } catch (IOException e) {
    
    
            throw new Exception();
        } finally {
    
    
            try {
    
    
                if (in != null) {
    
    
                    in.close();
                }
            } catch (IOException e) {
    
    
                throw new Exception();
            }
        }
        return bytes;
    }

    /**
     * 添加监听器
     *
     * @param port     串口对象
     * @param listener 串口监听器
     * @throws
     */
    public static void addListener(SerialPort port,
                                   SerialPortEventListener listener) throws Exception {
    
    
        try {
    
    
            // 给串口添加监听器
            port.addEventListener(listener);
            // 设置当有数据到达时唤醒监听接收线程
            port.notifyOnDataAvailable(true);
            // 设置当通信中断时唤醒中断线程
            port.notifyOnBreakInterrupt(true);
        } catch (TooManyListenersException e) {
    
    
            throw new Exception();
        }
    }
}

5、调用main

public static void main(String[] args) throws Exception {
    
    
    //连接
    SerialPort serialPort = SerialPortManager.openPort("COM1", 115200, SerialPort.DATABITS_8, SerialPort.PARITY_EVEN);
    System.out.println("连接++++++++++++++++++++++++" + serialPort);
    //发送数据--指令
    SerialPortManager.sendToPort(serialPort, SerialPortManager.hexStringToByteArray("F20003433130C52A"));
    //接收数据
    byte[] byteOBUStaus = SerialPortManager.readFromPort(serialPort);
    System.out.println("收到的数据:" + SerialPortManager.byte2HexString(byteOBUStaus));
    //关闭串口---
    SerialPortManager.closePort(serialPort);
    System.out.println("关闭串口++++++++++++++++++++++++" + serialPort);
}

6、打包问题发布遇到问题

(1)no rxtxSerial in java.library.path
(2)Could not initialize class gnu.io.RXTXCommDriver
(3)rxtxSerial.dll: Can’t load IA 32-bit .dll on a AMD 64-bit platform

rxtxSerial.dll和rxtxParallel.dll丢到system64环境中

在这里插入图片描述

RXTXcomm.jar放到项目里面

在这里插入图片描述
在这里插入图片描述

<dependency>
    <groupId>RXTXcomm</groupId>
    <artifactId>RXTXcomm</artifactId>
    <version>1.0</version>
    <scope>system</scope>
    <systemPath>${
    
    project.basedir}/src/main/resources/libs/RXTXcomm.jar</systemPath>
</dependency>

jdk环境是8_32位

7、成功调用

在这里插入图片描述

总结:
开发不易,当然也参考了网上很多列子,一个个试过来,才能成功调用,希望少一些人走弯路
1、jna调用单个动态库是没什么问题,这些大概都知道,涉及到多个慢慢就出现问题,除非能保证各大供应商的动态库没问题,或者逻辑不错就能用吧
2、建议能用串口方式,尽量用串口方式,想要什么效果就能实现什么样的效果,不要被供应商牵着鼻子走

猜你喜欢

转载自blog.csdn.net/weixin_44538423/article/details/126120062