• java调用串口,开箱即用


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

    开发遇到问题:

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

    1、下载调用串口工具包

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

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

    RXTXcomm.jar —> \jre\lib\ext
    rxtxSerial.dll —> \jre\bin
    rxtxParallel.dll —> \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();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223

    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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    jdk环境是8_32位

    7、成功调用

    在这里插入图片描述

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

  • 相关阅读:
    浮动IP、IP、动态IP、静态IP等各类IP之区别
    StoneDB顺利通过中科院软件所 2023 开源之夏 结项审核
    Rouge安装问题
    探索工业4.0:数字孪生如何重塑工业生产流程?
    获取随机id的api接口
    (附源码)springboot大学生创新创业管理 毕业设计 041557
    React Refs 使用场景及核心要点
    【python】头匹配,尾匹配
    剑指Offer 06. 从尾到头打印链表
    spring cloud rebuild project z
  • 原文地址:https://blog.csdn.net/weixin_44538423/article/details/126120062