java调用串口,开箱即用

2023-11-09

作者:刘东标
撰写日期: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、建议能用串口方式,尽量用串口方式,想要什么效果就能实现什么样的效果,不要被供应商牵着鼻子走

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java调用串口,开箱即用 的相关文章

  • Play框架运行应用程序问题

    每当我尝试运行使用以下命令创建的新 Web 应用程序时 我都会收到以下错误Play http www playframework org Error occurred during initialization of VM Could no
  • Final字段的线程安全

    假设我有一个 JavaBeanUser这是从另一个线程更新的 如下所示 public class A private final User user public A User user this user user public void
  • 反射找不到对象子类型

    我试图通过使用反射来获取包中的所有类 当我使用具体类的代码 本例中为 A 时 它可以工作并打印子类信息 B 扩展 A 因此它打印 B 信息 但是当我将它与对象类一起使用时 它不起作用 我该如何修复它 这段代码的工作原理 Reflection
  • JavaMail 只获取新邮件

    我想知道是否有一种方法可以在javamail中只获取新消息 例如 在初始加载时 获取收件箱中的所有消息并存储它们 然后 每当应用程序再次加载时 仅获取新消息 而不是再次重新加载它们 javamail 可以做到这一点吗 它是如何工作的 一些背
  • 磁模拟

    假设我在 n m 像素的 2D 表面上有 p 个节点 我希望这些节点相互吸引 使得它们相距越远吸引力就越强 但是 如果两个节点之间的距离 比如 d A B 小于某个阈值 比如 k 那么它们就会开始排斥 谁能让我开始编写一些关于如何随时间更新
  • 我可以使用 HSQLDB 进行 junit 测试克隆 mySQL 数据库吗

    我正在开发一个 spring webflow 项目 我想我可以使用 HSQLDB 而不是 mysql 进行 junit 测试吗 如何将我的 mysql 数据库克隆到 HSQLDB 如果您使用 spring 3 1 或更高版本 您可以使用 s
  • Spring @RequestMapping 带有可选参数

    我的控制器在请求映射中存在可选参数的问题 请查看下面的控制器 GetMapping produces MediaType APPLICATION JSON VALUE public ResponseEntity
  • 无法解析插件 Java Spring

    我正在使用 IntelliJ IDEA 并且我尝试通过 maven 安装依赖项 但它给了我这些错误 Cannot resolve plugin org apache maven plugins maven clean plugin 3 0
  • 为什么HashMap不能保证map的顺序随着时间的推移保持不变

    我在这里阅读有关 Hashmap 和 Hashtable 之间的区别 http javarevisited blogspot sg 2010 10 difference Between hashmap and html http javar
  • 加密 JBoss 配置中的敏感信息

    JBoss 中的标准数据源配置要求数据库用户的用户名和密码位于 xxx ds xml 文件中 如果我将数据源定义为 c3p0 mbean 我会遇到同样的问题 是否有标准方法来加密用户和密码 保存密钥的好地方是什么 这当然也与 tomcat
  • Java Integer CompareTo() - 为什么使用比较与减法?

    我发现java lang Integer实施compareTo方法如下 public int compareTo Integer anotherInteger int thisVal this value int anotherVal an
  • 如何在 javadoc 中使用“<”和“>”而不进行格式化?

    如果我写
  • Google App Engine 如何预编译 Java?

    App Engine 对应用程序的 Java 字节码使用 预编译 过程 以增强应用程序在 Java 运行时环境中的性能 预编译代码的功能与原始字节码相同 有没有详细的信息这是做什么的 我在一个中找到了这个谷歌群组消息 http groups
  • Java列表的线程安全

    我有一个列表 它将在线程安全上下文或非线程安全上下文中使用 究竟会是哪一个 无法提前确定 在这种特殊情况下 每当列表进入非线程安全上下文时 我都会使用它来包装它 Collections synchronizedList 但如果不进入非线程安
  • 声明的包“”与预期的包不匹配

    我可以编译并运行我的代码 但 VSCode 中始终显示错误 早些时候有一个弹出窗口 我不记得是什么了 我点击了 全局应用 从那以后一直是这样 Output is there but so is the error The declared
  • simpleframework,将空元素反序列化为空字符串而不是 null

    我使用简单框架 http simple sourceforge net http simple sourceforge net 在一个项目中满足我的序列化 反序列化需求 但在处理空 空字符串值时它不能按预期工作 好吧 至少不是我所期望的 如
  • 在 Maven 依赖项中指定 jar 和 test-jar 类型

    我有一个名为 commons 的项目 其中包含运行时和测试的常见内容 在主项目中 我添加了公共资源的依赖项
  • 有没有办法为Java的字符集名称添加别名

    我收到一个异常 埋藏在第 3 方库中 消息如下 java io UnsupportedEncodingException BIG 5 我认为发生这种情况是因为 Java 没有定义这个名称java nio charset Charset Ch
  • 当我从 Netbeans 创建 Derby 数据库时,它存储在哪里?

    当我从 netbeans 创建 Derby 数据库时 它存储在哪里 如何将它与项目的其余部分合并到一个文件夹中 右键单击Databases gt JavaDB in the Service查看并选择Properties This will
  • JGit 检查分支是否已签出

    我正在使用 JGit 开发一个项目 我设法删除了一个分支 但我还想检查该分支是否已签出 我发现了一个变量CheckoutCommand但它是私有的 private boolean isCheckoutIndex return startCo

随机推荐

  • sonar.java.binaries的配置

    从sonarQube 4 12开始 sonar将会进行程序的动态检查 不配置sonar java binaries属性将会出错 From SonarJava version 4 12 binary files are required fo
  • 在 Mac 上使用 VMware 安装 Windows 11

    因为项目原因 需要在 windows 环境下测试一下 electron 的表现 于是就记录一下在 mac 虚拟机上安装 windows 的体验 总体来说难度不大 我电脑的情况 2020 款 macbook pro 16g 512g 前期准备
  • golang版本管理gvm

    今天小土带来一篇关于Go版本管理器gvm的小短文 废话不多说 开始安装 安装 如果你使用的mac mac 需要先安装xcode select 没安装过的同学可以按照如下命令进行执行安装 这里不做太多说明了 xcode select inst
  • 地震逃生【最大流模板题】

    题目链接 P1343 地震逃生 简单的最大流的模板 小心 0 的RE情况 读题 另外 写的是ISAP include
  • 微信小程序授权登录页面(有提示窗)

    微信小程序授权登录 有弹窗提示 1 效果显示 1 1 授权登录页面 1 2 授权登录提示弹窗 1 3 拒绝授权登录 1 4 允许登录后 跳转到小程序首页 2 代码 2 1 wxml 文件
  • 日志审计功能实现

    1 前言 日志审计功能就是将用户进行的增加 修改和删除操作内容 操作方法 操作人以及操作时间等统一格式后集中放入数据库存储 这样做是为了提高系统的安全性 方便系统发生事故后的溯源和恢复 2 日志审计实现 2 1 设计数据库 下图为数据库中的
  • react基础06--react综合案例-电商网站导航

    react基础06 react综合案例 电商网站导航 1 介绍 2 案例设计模块 2 1 分类导航数据模型设计 2 2 一级分类导航切换高亮效果 2 3 显示二级分类导航 2 4 路由跳转到二级导航的商品列表 2 5 商品搜索 3 注意事项
  • Go语言面试题--基础语法(29)

    文章目录 1 下面的代码有什么问题 2 下面代码最后一行输出什么 请说明原因 3 下面代码有什么问题 4 下面的代码输出什么 1 下面的代码有什么问题 func main data int 1 2 3 i 0 i fmt Println d
  • U-Boot启动流程详解

    参考 U Boot顶层目录链接脚本文件 u boot lds 介绍 作者 一只青木呀 发布时间 2020 10 23 13 52 23 网址 https blog csdn net weixin 45309916 article detai
  • VAR模型

    文章目录 一 VAR是什么 1 引入库 2 读入数据 3 执行程序 总结 一 VAR是什么 以金融价格为例 传统的时间序列模型比如ARIMA ARIMA GARCH等 只分析价格自身的变化 模型的形式为 其中称为自身的滞后项 但是VAR模型
  • Navicat安装教程

    众所周知 Navicat是一款轻量级的用于MySQL连接和管理的工具 非常好用 使用起来方便快捷 简洁 下面我会简单的讲一下其安装以及使用的方法 并且会附带相关的永久安装教程 简介 一般我们在开发过程中是离不开数据库的 Navicat是一款
  • svn: Can't find a temporary directory 问题解决

    Error Can t find temporary directory internal error 然后试了下其他的SVN源 发现均无法提交 并且update时也出现上面的错误信息 对比项目文件时出现 不能创建目录或文件 公司网站首页正
  • Nginx集群+websocket 获取websocket客户端的真实IP

    Nginx增加如下配置 proxy set header Host host proxy set header X Real IP remote addr proxy set header REMOTE HOST remote addr p
  • UMI多环境配置

    一般来说项目不止有dev和prod两个环境 umi可以通过环境变量 UMI ENV 区分不同环境来指定配置 需求 三套环境 gt 本地测试环境local 测试发布环境testbuild 正式环境probuild 1 在根目录新建 umirc
  • 云计算基础——云计算与移动互联网、物联网

    8 1 云计算与移动互联网 8 1 1 移动互联网的发展概况 移动互联网的发展概况 移动互联网是指以宽带IP为技术核心 可同时提供语音 数据 多媒体等业务服务的开什么是移动互联网 放式基础电信网络 从用户行为角度来看 移动互联网广义上是指用
  • shell命令以及运行原理(详解)

    Linux严格意义上说的是一个操作系统 我们称之为 核心 kernel 但我们一般用户 不能直接使用kernel 而是通过kernel的 外壳 程序 也就是所谓的shell 来与kernel沟通 1 从技术角度 Shell的最简单定义 命令
  • Redis实践(一):安装和部署

    memcache redis mongodb 是目前常用的内存数据库 他们应用的场景大致如下 redis 数据量较小的更性能操作和运算上 memcache 用于在动态系统中减少数据库负载 提升性能 做缓存 提高性能 适合读多写少 对于数据量
  • __builtin_expect, __builtin_unreachable和__builtin_prefetch

    builtin expect 该指令是gcc引入的 就是允许代码编写者把最有可能执行的分支告诉编译器 标准写法是 bultin expect exp n 意思是exp n的概率很大 这样编译器可以对代码进行优化 减少指令跳转带来的性能下降
  • elasticsearch bulk批量增删改(超详细)

    一 bulk的操作类型 1 1批量增 语法一 index操作 可以是创建文档 也可以是全量替换文档 类似于普通的put操作 POST bulk index index test index type test type id 12 scor
  • java调用串口,开箱即用

    作者 刘东标 撰写日期 2022 08 02 开发遇到问题 1 供应商提供的动态库各种底层代码有问题 指针也不对 参数也乱 加上长年不维护动态库 2 解决多个动态库问题 不同供应商提供动态库也不同 32位动态库和64位动态库 还有是供应商的