Java RXTX 实现串口通信

article/2025/10/6 21:30:08

目录

串口(通信)概述

串口调试助手

RXTX 下载与依赖

Java 开发实战


串口(通信)概述

1、串口通信是指串口按位(bit)发送和接收字节

2、串口通信可以在使用一根线发送数据的同时用另一根线接收数据

3、串口通信常用的协议包括 RS-232、RS-422 和 RS-485

4、串口通信,控制线长度可达1200 

5、串口通信最重要的参数是波特率数据位停止位奇偶校验,对于两个进行通信的端口,这些参数必须匹配。

6、串口对于普通用户来说很陌生,现在的计算机大都已经取消了这个插口,在工业上和电子行业中,这个端口使用的较为频繁。

7、注意串口与 VGA 插口的区别:串口通常为 9 针,2 排 4+5 排列;而 VGA 插口有15 针,3 排 5+5+5 排列

8、一般来说,带有原生串口的主板,其原生串口的串口号默认为 COM1,如果主板带有2个原生串口,则机箱后方的RS232插口为 COM1,主板上还有一个未能引出的串口插槽为 COM2。

9、如果电脑上没有串口,则一般要用 USB 转串口线进行连接,然后像连接键盘、鼠标一样,要安装USB转串口的驱动

如上所示发送数据时应该给 usb 转串口的 com3 发送

串口通信术语
波特率

1、衡量信号传输速率的参数
2、指的是信号被调制以后在单位时间内的变化,即单位时间内载波参数变化的次数,如每秒钟传送240个字符,而每个字符格式包含10位(1个起始位,1个停止位,8个数据位),这时的波特率为240Bd,比特率为10位*240个/秒=2400bps。一般调制速率大于波特率,比如曼彻斯特编码)
3、通常电话线的波特率为 14400,28800 和 36600,波特率可以远远大于这些值,但是波特率和距离成反比。高波特率常常用于放置的很近的仪器间的通信,典型的例子就是 GPIB 设备的通信。

数据位

1、衡量通信中实际数据位的参数
2、当计算机发送一个信息包,实际的数据往往不会是 8 位的,标准的值是 6、7 和 8 位。如何设置取决于你想传送的信息。比如,标准的 ASCII 码是 0~127(7位)。扩展的 ASCII 码是0~255(8位)
3、如果数据使用简单的文本(标准 ASCII码),那么每个数据包使用7位数据。每个包是指一个字节,包括开始/停止位,数据位和奇偶校验位。由于实际数据位取决于通信协议的选取,术语“包”指任何通信的情况。

停止位

1、用于表示单个包的最后一位,典型的值为 1,1.5 和 2 位
2、由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备间出现了小小的不同步。因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟同步的机会。适用于停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率同时也越慢。

奇偶校验位

1、串口通信中一种简单的检错方式
2、有四种检错方式:偶、奇、高和低,当然没有校验位也是可以的
3、对于偶和奇校验的情况,串口会设置校验位(数据位后面的一位),用一个值确保传输的数据有偶个或者奇个逻辑高位。例如,如果数据是011,那么对于偶校验,校验位为0,保证逻辑高的位数是偶数个。如果是奇校验,校验位为1,这样就有3个逻辑高位。高位和低位不真正的检查数据,简单置位逻辑高或者逻辑低校验。这样使得接收设备能够知道一个位的状态,有机会判断是否有噪声干扰了通信或者是否传输和接收数据是否不同步。

串口调试助手

1、如同 tcp、udp 通信可以先使用测试工具一样,串口通信也推荐先使用工具进行调试,因为至少要先确定被控制的硬件(如投影机、智能灯等)没有问题,否则如果控制失败,就无法指定到底是硬件的问题,还是自己软件的问题了。

2、使用调试助手控制成功后,则可以使用 Java 程序再进行控制。

3、可以使用如下的串口调试工具:Serial Port Utility(友善串口调试助手)

4、如果电脑有串口,则可以直接使用串口线连接硬件使用,如果电脑上没有串口,则可以使用 USB 转串口线进行转换,然后为 USB 转串口线安装好驱动即可。

5、通常一台电脑上的串口是有限的,比如一个串口,此时一个串口通过串口线连接到硬件后,只能控制一台硬件,如何一个串口控制多台硬件呢?可以去网上买一个串口分配器,它可以将一个串口输入分成多个串口输出,通常有 4个、8个等。

RXTX 下载与依赖

1、虽然 Java 也有原生串口通信的 API ,但是使用不太方便,可以选择市面上人家封装好的第三方库,其中以 RXTX 较为常用。

2、rxtx.qbang 官网:http://fizzed.com/oss/rxtx-for-java

3、根据自己电脑系统选择下载:

VersionFileInformation
RXTX-2-2-20081207Windows-x64

Windows-x86
Windows-ia64
Linux-x86_64
Linux-i386

Based on CVS snapshot of RXTX taken on 2008-12-07

4、以 Windows-x64 为例,下载解压后如下:

5、其中的 Install.txt 中官方给出了使用说明,Windows 系统如下:

-----------------------Windows-----------------------------Choose your binary build - x64 or x86 (based on which version of
the JVM you are installing to)NOTE: You MUST match your architecture.  You can't install the i386
version on a 64-bit version of the JDK and vice-versa.For a JDK installation:Copy RXTXcomm.jar ---> <JAVA_HOME>\jre\lib\ext
Copy rxtxSerial.dll ---> <JAVA_HOME>\jre\bin
Copy rxtxParallel.dll ---> <JAVA_HOME>\jre\bin

1)RXTXcomm.jar :作为项目开发包如果已经导入到了项目中,则可以不必复制到 <JAVA_HOME>\jre\lib\ext 下

2)rxtxSerial.dll、rxtxParallel.dll 文件必须放到 <JAVA_HOME>\jre\bin 下,如果是 Windows 系统,则也可以放到 C:\Windows\System32 目录下,否则运行会报错如下:

java.lang.UnsatisfiedLinkError: no rxtxSerial in java.library.path] with root cause
java.lang.UnsatisfiedLinkError: no rxtxSerial in java.library.pathat java.lang.ClassLoader.loadLibrary(ClassLoader.java:1867)at java.lang.Runtime.loadLibrary0(Runtime.java:870)at java.lang.System.loadLibrary(System.java:1122)

Maven 依赖

1、如果是 Maven 应用,则可以 Maven 中央仓库获取 RXTX 依赖:

<!-- https://mvnrepository.com/artifact/org.bidib.jbidib.org.qbang.rxtx/rxtxcomm -->
<dependency><groupId>org.bidib.jbidib.org.qbang.rxtx</groupId><artifactId>rxtxcomm</artifactId><version>2.2</version>
</dependency>

Java 开发实战

1、使用也是很简单,分为三步:

1)打开串口

2)使用 java.io.OutputStream 发送数据,或 java.io.InputStream 读取数据

3)关闭串口

2、完整内容如下:

import gnu.io.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
/*** Created by Administrator on 2019/3/18 0018.* 串口工具类*/
public class SerialPortTool {private static final Logger logger = LoggerFactory.getLogger(SerialPortTool.class);//slf4j 日志记录器/*** 查找电脑上所有可用 com 端口** @return 可用端口名称列表,没有时 列表为空*/public static final ArrayList<String> findSystemAllComPort() {/***  getPortIdentifiers:获得电脑主板当前所有可用串口*/Enumeration<CommPortIdentifier> portList = CommPortIdentifier.getPortIdentifiers();ArrayList<String> portNameList = new ArrayList<>();/***  将可用串口名添加到 List 列表*/while (portList.hasMoreElements()) {String portName = portList.nextElement().getName();//名称如 COM1、COM2....portNameList.add(portName);}return portNameList;}/*** 打开电脑上指定的串口** @param portName 端口名称,如 COM1,为 null 时,默认使用电脑中能用的端口中的第一个* @param b        波特率(baudrate),如 9600* @param d        数据位(datebits),如 SerialPort.DATABITS_8 = 8* @param s        停止位(stopbits),如 SerialPort.STOPBITS_1 = 1* @param p        校验位 (parity),如 SerialPort.PARITY_NONE = 0* @return 打开的串口对象,打开失败时,返回 null*/public static final SerialPort openComPort(String portName, int b, int d, int s, int p) {CommPort commPort = null;try {//当没有传入可用的 com 口时,默认使用电脑中可用的 com 口中的第一个if (portName == null || "".equals(portName)) {List<String> comPortList = findSystemAllComPort();if (comPortList != null && comPortList.size() > 0) {portName = comPortList.get(0);}}logger.info("开始打开串口:portName=" + portName + ",baudrate=" + b + ",datebits=" + d + ",stopbits=" + s + ",parity=" + p);//通过端口名称识别指定 COM 端口CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);/*** open(String TheOwner, int i):打开端口* TheOwner 自定义一个端口名称,随便自定义即可* i:打开的端口的超时时间,单位毫秒,超时则抛出异常:PortInUseException if in use.* 如果此时串口已经被占用,则抛出异常:gnu.io.PortInUseException: Unknown Application*/commPort = portIdentifier.open(portName, 5000);/*** 判断端口是不是串口* public abstract class SerialPort extends CommPort*/if (commPort instanceof SerialPort) {SerialPort serialPort = (SerialPort) commPort;/*** 设置串口参数:setSerialPortParams( int b, int d, int s, int p )* b:波特率(baudrate)* d:数据位(datebits),SerialPort 支持 5,6,7,8* s:停止位(stopbits),SerialPort 支持 1,2,3* p:校验位 (parity),SerialPort 支持 0,1,2,3,4* 如果参数设置错误,则抛出异常:gnu.io.UnsupportedCommOperationException: Invalid Parameter* 此时必须关闭串口,否则下次 portIdentifier.open 时会打不开串口,因为已经被占用*/serialPort.setSerialPortParams(b, d, s, p);logger.info("打开串口 " + portName + " 成功...");return serialPort;} else {logger.error("当前端口 " + commPort.getName() + " 不是串口...");}} catch (NoSuchPortException e) {e.printStackTrace();} catch (PortInUseException e) {logger.warn("串口 " + portName + " 已经被占用,请先解除占用...");e.printStackTrace();} catch (UnsupportedCommOperationException e) {logger.warn("串口参数设置错误,关闭串口,数据位[5-8]、停止位[1-3]、验证位[0-4]...");e.printStackTrace();if (commPort != null) {//此时必须关闭串口,否则下次 portIdentifier.open 时会打不开串口,因为已经被占用commPort.close();}}logger.error("打开串口 " + portName + " 失败...");return null;}/*** 往串口发送数据** @param serialPort 串口对象* @param order      待发送数据*/public static void sendDataToComPort(SerialPort serialPort, byte[] orders) {OutputStream outputStream = null;try {if (serialPort != null) {outputStream = serialPort.getOutputStream();outputStream.write(orders);outputStream.flush();logger.info("往串口 " + serialPort.getName() + " 发送数据:" + Arrays.toString(orders) + " 完成...");} else {logger.error("gnu.io.SerialPort 为null,取消数据发送...");}} catch (IOException e) {e.printStackTrace();} finally {if (outputStream != null) {try {outputStream.close();} catch (IOException e) {e.printStackTrace();}}}}/*** 关闭串口** @param serialport 待关闭的串口对象*/public static void closeComPort(SerialPort serialPort) {if (serialPort != null) {serialPort.close();logger.info("关闭串口 " + serialPort.getName());}}/*** 16进制字符串转十进制字节数组* 这是常用的方法,如某些硬件的通信指令就是提供的16进制字符串,发送时需要转为字节数组再进行发送** @param strSource 16进制字符串,如 "455A432F5600",每两位对应字节数组中的一个10进制元素*                  默认会去除参数字符串中的空格,所以参数 "45 5A 43 2F 56 00" 也是可以的* @return 十进制字节数组, 如 [69, 90, 67, 47, 86, 0]*/public static byte[] hexString2Bytes(String strSource) {if (strSource == null || "".equals(strSource.trim())) {System.out.println("hexString2Bytes 参数为空,放弃转换.");return null;}strSource = strSource.replace(" ", "");int l = strSource.length() / 2;byte[] ret = new byte[l];for (int i = 0; i < l; i++) {ret[i] = Integer.valueOf(strSource.substring(i * 2, i * 2 + 2), 16).byteValue();}return ret;}public static void main(String[] args) {//发送普通数据byte[] bytes = new byte[]{1, 2, 3, 4, 5};SerialPort serialPort = SerialPortTool.openComPort(null, 38400, 8, 1, 0);SerialPortTool.sendDataToComPort(serialPort, bytes);SerialPortTool.closeComPort(serialPort);//发送16进制数据——实际应用中串口通信传输的数据,大都是 16 进制String hexStrCode = "455A432F5600";serialPort = SerialPortTool.openComPort(null, 38400, 8, 1, 0);SerialPortTool.sendDataToComPort(serialPort, hexString2Bytes(hexStrCode));SerialPortTool.closeComPort(serialPort);}
}

上面虽然只有发送数据,但是读取也是同理的,无非就是获取输入流进行读取即可。因为读取没有切实的真实测试使用场景,所以就不贴出了。


http://chatgpt.dhexx.cn/article/xier8EqK.shtml

相关文章

串口通信原理

并行通信是指数据的各个位用多条数据线同时进行传输 优点&#xff1a;传输速度快 缺点&#xff1a;占用引脚资源多 串行通信是将数据分成一位一位的形式在一条传输线上逐个传输 优点&#xff1a;通信线路简单、占用引脚资源少 缺点&#xff1a;传输速度慢 同步通信&#xf…

串口通讯基本原理 【详细】

串口通信的基本知识 本文介绍了串口通讯的基本概念、数据格式、通讯方式、典型的串口通讯标准等内容。 串口通讯&#xff0c;RS232,RS485&#xff0c;停止位&#xff0c;奇校验&#xff0c;偶校验 1 串口通讯 串口通讯(Serial Communication)&#xff0c;是指外设和计算…

串口通信的基本原理详解

目录 串口通信 串口通信的两种基本方式 异步数据的数据发送过程 异步通信的数据接收过程 9针串口&#xff08;DB9&#xff09; TTL与RS232区别 TTL: RS232&#xff1a; 串口通信的数据格式 通讯方式 偶校验与奇校验 停止位 波特率&#xff08;波特率就是每秒钟传输…

串口通信原理详解

串口通信是一种串行异步通信&#xff0c;通信双方以字符帧作为数据传输单位&#xff0c;字符帧按位依次传输&#xff0c;每个位占固定的时间长度。两个字符帧之间的传输时间间隔可以是任意的&#xff0c;即传输完一个字符帧之后&#xff0c;可以间隔任意时间再传输下一个字符帧…

14_串口通信原理

通信方式的两种: 并行通讯: 传输原理:数据各个位同时传输。 优点:速度快 缺点:占用引脚资源多 串行通信: 传输原理:数据按位顺序传输。 优点:占用引脚资源少 缺点:速度相对较慢 串行通信: 按照数据传送方向,分为: 单工:数据传输只支持数据在一个方向上传输。 半双工:…

【Linux】基于美信串行解串器实现UART串口通信

文章目录 前言一、环境介绍二、硬件配置1. MAX967632. MAX96752F 三、串口通信协议1. 帧格式2. 同步帧3. 应答帧4. 包格式&#xff08;包由帧组成&#xff09; 四、内核模块实现 前言 车载项目中串行/解串器是十分常见的外设&#xff0c;目前常用的有两种标准&#xff1a;GMSL…

毫米波雷达图解算法原理(基于TI雷达)

毫米波雷达数据处理原理 前言基础bin文件解读 以下我们取1帧进行操作&#xff1a;对数据矩阵进行操作前的转换——开始计算结果矩阵一维FFT&#xff08;距离&#xff09;二维FFT&#xff08;速度&#xff09;角度维FFT &#xff08;假设利用结果已经获取目标&#xff09;对目标…

【阵列信号处理】DOA估计算法

DOA估计中的ESPRIT算法 ESPRIT算法时一种利用子空间旋转法估计DOA参数的方法&#xff0c;其算法的基本思想是将阵列在结构上分成两个完全一致的子列&#xff0c;两个子列相应阵元偏移的距离相等&#xff0c;也就是说阵列的阵元被分成一对对的形式&#xff0c;而且每一对之间具…

Hector SLAM 原理详解、算法解析

目录 1.原理详解 2.算法解析 1.原理详解 Hector整体算法很直接&#xff0c;就是将激光点与已有的地图“对齐”&#xff0c;即扫描匹配。扫描匹配就是使用当前帧与已经有的地图数据构建误差函数&#xff0c;使用高斯牛顿法得到最优解和偏差量。其工作是实现激光点到栅格地图的转…

MPU 6050姿态角度融合算法

1、介绍 1.1 姿态角&#xff08;Euler角&#xff09;pitch yaw roll介绍 飞行器的姿态角并不是指哪个角度&#xff0c;是三个角度的统称。它们是&#xff1a;俯仰、滚转、偏航。你可以想象是飞机围绕XYZ三个轴分别转动形成的夹角。 地面坐标系&#xff08;earth-surface inert…

linemod算法过程理解

一、提取模板 1、预处理 使用高斯模糊预处理将要作为模板的RGB图 2、模板梯度计算 分别计算RGB三个通道中每个像素点x和y方向的梯度&#xff08;sobel算子&#xff09;&#xff0c;取幅值最大的作为该像素的梯度&#xff0c;若梯度幅度值小于阈值&#xff0c;则被舍弃 3、梯度离…

MATLAB函数angle、unwrap

一、angle 相位角 语法 P angle&#xff08;Z&#xff09;描述 P angle&#xff08;Z&#xff09;返回复数数组Z的每个元素的相角&#xff08;以弧度为单位&#xff09;。角度介于π之间。对于复数Z&#xff0c;幅值R和相角theta由下式给出 R 绝对值&#xff08;Z&#xff0…

fbp算法matlab实现,matlab实现fbp算法

matlab提供大量函数,可以方便的完成fbp算法 1)fbp算法原理: 中心切片定理 (CST) : 原数据投影的一维傅立叶变换等于原数据的二维傅立叶变换 投影 --> 一维傅立叶变换 --> 滤波 --> 二维傅立叶反变换 经过上述过程应该得到原始数据 2)投影相关知识 2.1)正投影:对…

一种简单的图形旋转算法

图形旋转好玩又有实用性, 这里介绍一种简单的图形旋转算法. 具体步骤如下: 1. 首先将原图和旋转图的坐标原点都变换到图形的中心位置处. 2. 历遍旋转图形中的每一个pixel, 将pixel的坐标(j,i)反向旋转映射到原图, 得到原图对应的坐标值(Xr,Yr). 3. 考虑到旋转图的尺寸可能大于…

多目标跟踪之数据关联算法——匈牙利算法

零、Track和Detection的cost matrix,distance metric。距离计算的方式有如下几种: 距离cost distance metric,track和detection的距离矩阵。 外观距离appearance distance,来自检测切片ROI的网络特征提取;——余弦距离 运动模型距离 马氏距离,来自检测-跟踪的kalman校正…

EAST算法简单解析

前言 最近写了很多算法代码的解析&#xff0c;但是却很少写原理的解析&#xff0c;这段时间学得快忘得也快&#xff0c;所以寻思这几天写几篇学过算法的原理&#xff0c;可能不是很详细但是一定很简单&#xff0c;利于理解。 算法介绍 EAST: An Efficient and Accurate Scen…

定位算法初探

定位算法初探 一、指纹定位算法介绍 指纹定位(finger-printing localization)算法&#xff0c;是基于室内环境复杂&#xff0c;信号反射折射所形成的在不同位置形成的不同的信号强度信息而提出的一套算法。 指纹算法能很好的利用了反射折射所形成的信号信息&#xff0c;离线首…

使用python模拟实现PID控制算法

使用python模拟实现PID控制算法 PID控制算法是工业应用中最广泛算法之一&#xff0c;在闭环系统的控制中&#xff0c;可自动对控制系统进行准确且迅速的校正。 P、I、D分别是“比例&#xff08;proportional&#xff09;、积分&#xff08;integral&#xff09;、微分&#xff…

TCP Nagle算法简述

TCP/IP协议中&#xff0c;无论发送多少数据&#xff0c;总是要在数据前面加上协议头&#xff0c;同时&#xff0c;对方接收到数据&#xff0c;也需要发送ACK表示确认。为了尽可能的利用网络带宽&#xff0c;TCP总是希望尽可能的发送足够大的数据。 &#xff08;一个连接会设置M…

倒角算法推导

推导原理基本很简单&#xff1a; 已知AB&#xff0c; BC两条线段&#xff0c;且交于B点&#xff0c;求倒角半径为 L&#xff0c;AB&#xff0c;BC的倒角 以最短边&#xff08;假定为AB&#xff09;长 LAB&#xff0c; 在BC中&#xff0c;以B为起点&#xff0c;找出与LAB同长度…