SpringBoot接入RS-232串口通讯实现数据交互

目录

一、什么是RS-232?

先看看硬件通讯接口长啥样

RS-232 

二、方案一

1.前期准备

a.配置 RXTX

1)下载 RXTX 包并解压

2)拷贝动态库到对应的jdk目录下

·Windows平台

·Linux平台

3)在工程根目录下创建 lib 文件夹(与src平级)将 RXTXcomm.jar 放入该文件夹中

4)在 pom.xml 中引入本地 jar 包依赖

 2、编写Java配置代码

三、方案二

1、前期准备

a.配置pom.xml文件

2、编写Java配置代码

四、其他的方法


📢📢📢📣📣📣
哈喽!大家好,我是「Leen」。刚工作几年,想和大家一同进步🤝🤝
一位上进心十足的Java博主!😜😜😜
喜欢尝试一些新鲜的东西,平时比较喜欢研究一些新鲜技术和一些自己没有掌握的技术领域。能用程序解决的坚决不手动解决😜😜😜

目前已涉足Java、Python、数据库(MySQL、pgsql、MongoDB、Oracle...)、Linux、HTML、VUE、PHP、C(了解不多,主要是嵌入式编程方向做了一些)...(还在不断地学习,扩展自己的见识和技术领域中),希望可以和各位大佬们一起进步,共同学习🤝🤝

✨ 如果有对【Java】,或者喜欢看一些【实操笔记】感兴趣的【小可爱】,欢迎关注我

❤️❤️❤️感谢各位大可爱小可爱!❤️❤️❤️

今天给大家分享的是Java 连接 RS-232串口进行通讯,研究了好几个日夜,终于是走通了两条通道,实现了通讯,大家自己要实现这个这两个方案前需要硬件支持哦。

OK,接下来直接进入正题

一、什么是RS-232?

先看看硬件通讯接口长啥样

RS-232 

RS-232 是电子工业协会 (EIA) 定义的串行通信标准电气接口。RS-232 实际上有 3 种不同的风格(A、B 和 C),每种风格都为开和关电平定义了不同的电压范围。最常用的品种是RS-232C,它将标记(开)位定义为-3V至-12V之间的电压,将空格(关)位定义为+3V至+12V之间的电压。RS-232C 规范规定,这些信号在无法使用之前可以传播约 25 英尺(8 米)。只要波特率足够低,您通常可以发送比这更远的信号。

这一块,大家可以自行搜索去了解一下,这个地方我就不多介绍了

二、方案一

第一个方案,是原始方案,比较老的一种通讯方式,需要给jdk添加相应的ddl配置文件和驱动,并且现在这些配置文件不好找了(因为官网的配置地址找不到了,不存在),当然如果要是花点$,找到的可能性还是比较大的,反正我是没花钱找了一套配置哈哈哈

1.前期准备

a.配置 RXTX

1)下载 RXTX 包并解压

网址:http://fizzed.com/oss/rxtx-for-java

官网我找的时候暂时是没有的,可以等到后面的时候再去看看

2)拷贝动态库到对应的jdk目录下
·Windows平台

拷贝 rxtxSerial.dll —> <JAVA_HOME>\jre\bin
拷贝 rxtxParallel.dll —> <JAVA_HOME>\jre\bin

·Linux平台

拷贝 librxtxSerial.so —> <JAVA_HOME>/jre/lib/i386/
拷贝 librxtxParallel.so —> <JAVA_HOME>/jre/lib/i386/

3)在工程根目录下创建 lib 文件夹(与src平级)将 RXTXcomm.jar 放入该文件夹中

这个地方我建议是通过命令的方式将RXTXcomm.jar包导入到本地的Maven库中 

mvn install:install-file -Dfile="绝对路径/RXTXcomm.jar" -DgroupId="org.rxtx" -DartifactId="rxtx" -Dversion="2.2.0" -Dpackaging="jar"

当然也可以选择另外一种方式,直接导入

<dependency><groupId>gnu.io</groupId><artifactId>RXTXcomm</artifactId><scope>system</scope><systemPath>${project.basedir}/lib/RXTXcomm.jar</systemPath>
</dependency>
4)在 pom.xml 中引入本地 jar 包依赖

导入成功后,直接添加依赖即可

        <dependency><groupId>org.rxtx</groupId><artifactId>rxtx</artifactId><version>2.2.0</version></dependency>

 2、编写Java配置代码

package com.leen.test.test2024.test530;import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;/*** Author:Leen* Date: 2024/6/3 0003 22:45*/public class SerialCommSendData implements SerialPortEventListener {private SerialPort serialPort; // 串口对象private InputStream input; // 输入流,用于读取串口数据private OutputStream output; // 输出流,用于向串口写入数据private static final int TIME_OUT = 2000; // 端口打开的超时时间private static final int DATA_RATE = 9600; // 串口的波特率// 初始化串口public void initialize() {CommPortIdentifier portId = null;Enumeration portEnum = CommPortIdentifier.getPortIdentifiers();// 枚举系统中的所有端口并尝试找到指定的端口while (portEnum.hasMoreElements()) {CommPortIdentifier currPortId = (CommPortIdentifier) portEnum.nextElement();if (currPortId.getName().equals("COM3")) { // 将这里的 "COM3" 修改为你的端口名portId = currPortId;break;}}if (portId == null) {System.out.println("Could not find COM port.");return;}try {// 打开串口,使用类名作为应用程序名serialPort = (SerialPort) portId.open(this.getClass().getName(), TIME_OUT);// 设置串口参数serialPort.setSerialPortParams(DATA_RATE,SerialPort.DATABITS_8,SerialPort.STOPBITS_1,SerialPort.PARITY_NONE);// 打开输入输出流input = serialPort.getInputStream();output = serialPort.getOutputStream();// 添加事件监听器serialPort.addEventListener(this);serialPort.notifyOnDataAvailable(true);} catch (Exception e) {System.err.println(e.toString());}}// 关闭串口public synchronized void close() {if (serialPort != null) {serialPort.removeEventListener();serialPort.close();}}// 事件处理器,当串口有数据可用时触发@Overridepublic synchronized void serialEvent(SerialPortEvent oEvent) {if (oEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) {try {int available = input.available();byte[] chunk = new byte[available];input.read(chunk, 0, available);// 显示结果,具体字符编码依赖于系统设置System.out.print(new String(chunk));
//                processData(chunk); // 处理接收到的数据} catch (Exception e) {System.err.println(e.toString());}}}// 发送数据的方法public void sendData(String data) {try {output.write(data.getBytes());output.flush();System.out.println("Data sent: " + data);} catch (Exception e) {System.err.println(e.toString());}}// 处理接收到的数据的方法private void processData(byte[] data) {// 可以在这里处理接收到的数据String receivedData = new String(data);System.out.println("Received: " + receivedData);}// 主方法,程序入口public static void main(String[] args) {SerialCommSendData main = new SerialCommSendData();main.initialize(); // 初始化并打开串口System.out.println("Started");// 发送数据示例main.sendData("Hello ,I'm Leen ! I'd like to communicate with you");//测试接收数据byte[] data = "TEST communicate with RS-232".getBytes();main.processData(data);try {Thread.sleep(1000000); // 保持程序运行一段时间} catch (InterruptedException ie) {// 处理中断异常}main.close(); // 关闭串口}
}

启动main方法后,就可以和硬件串口进行通讯了

这个方法可以通讯,但是需要不适用于团队开发和切环境运行,只适合自己玩一下。咱们可以看看第二个方案

三、方案二

说实话,方案二操作起来非常的简单,唯二的难点之一是需要花时间找依赖;另一点就是正式通讯的时候封装通讯语言

1、前期准备

a.配置pom.xml文件

<dependency><groupId>org.scream3r</groupId><artifactId>jssc</artifactId><version>2.8.0</version>
</dependency>

2、编写Java配置代码

package com.leen.test.test2024.test530;import jssc.SerialPort;
import jssc.SerialPortException;
import jssc.SerialPortEvent;
import jssc.SerialPortEventListener;
import org.apache.commons.lang3.StringUtils;/*** Author:Leen* Date: 2024/6/4 0004 11:28*/
public class SerialCommTwo {private SerialPort serialPort; // 串口对象private static SerialCommTwo instance; // 单例实例private StringBuilder receivedDataBuffer = new StringBuilder(); // 缓存接收到的数据// 私有构造函数private SerialCommTwo(String portName) {serialPort = new SerialPort(portName);}// 获取单例实例的方法public static SerialCommTwo getInstance(String portName) {if (instance == null) {instance = new SerialCommTwo(portName);}return instance;}// 初始化串口public void initialize() {try {serialPort.openPort(); // 打开串口serialPort.setParams(SerialPort.BAUDRATE_9600,SerialPort.DATABITS_8,SerialPort.STOPBITS_1,SerialPort.PARITY_NONE); // 设置串口参数serialPort.addEventListener(new SerialPortEventListener() {public void serialEvent(SerialPortEvent event) {if (event.isRXCHAR()) { // 如果串口有数据可用try {byte[] buffer = serialPort.readBytes(); // 读取数据
//                            System.out.print(new String(buffer)); // 打印数据// 缓存接收到的数据if (StringUtils.isNotEmpty(new String(buffer))) {receivedDataBuffer.append(new String(buffer));}// 在这里处理接收到的完整报文,例如检查结束标志processReceivedData();} catch (SerialPortException e) {e.printStackTrace(); // 捕捉异常}}}// 处理接收到的数据的方法private void processReceivedData() {String receivedData = receivedDataBuffer.toString();// 检查报文是否完整,例如检查结束标志ETXif (receivedData.contains("\u0003")) { // ETX结束标志System.out.println("Received complete message:\n" + receivedData);// 提取第四行到结束标志中间的内容String[] lines = receivedData.split("\r\n|\n");if (lines.length >= 4) {StringBuilder extractedData = new StringBuilder();for (int i = 3; i < lines.length; i++) {if (lines[i].contains("\u0003")) { // 如果包含结束标志,停止提取break;}extractedData.append(lines[i]).append("\n");}System.out.println("Extracted data: \n" + extractedData.toString());}// 处理完成的报文后,清空缓存receivedDataBuffer.setLength(0);}}});} catch (SerialPortException e) {e.printStackTrace(); // 捕捉异常}}// 发送数据的方法public void sendData(String data) {try {serialPort.writeBytes(data.getBytes()); // 发送数据System.out.println("Sent: " + data); // 打印已发送的数据} catch (SerialPortException e) {e.printStackTrace(); // 捕捉异常}}// 关闭串口public void close() {try {if (serialPort != null) {serialPort.removeEventListener(); // 移除事件监听器serialPort.closePort(); // 关闭串口}} catch (SerialPortException e) {e.printStackTrace(); // 捕捉异常}}public static void main(String[] args) {SerialCommTwo serialComm = SerialCommTwo.getInstance("COM3"); // 替换为你的串口名serialComm.initialize(); // 初始化串口System.out.println("Started");// 发送测试数据String startChar = "\u0001"; // SOH 开始字符String endChar = "\u0003"; // ETX 结束字符serialComm.sendData(startChar +"Hello ,I'm Leen ! I'd like to communicate with you \n" +endChar);try {Thread.sleep(1000000); // 保持程序运行一段时间以接收数据} catch (InterruptedException ie) {ie.printStackTrace(); // 捕捉异常}serialComm.close(); // 关闭串口}
}

 启动main方法后,就可以和硬件串口进行通讯了

四、其他的方法

这个方法在这里不适用,可能对于别的地方有适用的

package com.leen.test.test2024.test530;import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;/*** Author:Leen* Date: 2024/5/30 0030 21:01*/
public class NPortClient {private static final String SERVER_IP = "192.168.1.100";  // NPort的IP地址private static final int SERVER_PORT = 4001;  // NPort的端口号public static void main(String[] args) {try (Socket socket = new Socket(SERVER_IP, SERVER_PORT);BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) {System.out.println("Connected to NPort at " + SERVER_IP + ":" + SERVER_PORT);// 发送数据到NPort(可选)out.println("Hello NPort!");// 接收来自NPort的数据String response;while ((response = in.readLine()) != null) {System.out.println("Received from NPort: " + response);// 可以在这里处理接收到的数据}} catch (Exception e) {e.printStackTrace();}}
}
package com.leen.test.test2024.test530;import java.io.*;
import java.net.Socket;
import java.net.SocketException;
import java.util.Properties;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.logging.Level;
import java.util.logging.Logger;
/*** Author:Leen* Date: 2024/5/30 0030 21:05*/
public class NPortClient2 {/*** 可放配置文件* server.ip=192.168.1.100* server.port=4001* reconnect.delay=5000  # 重连间隔时间(毫秒)*/private static final Logger LOGGER = Logger.getLogger(NPortClient.class.getName());private static String serverIp;private static int serverPort;private static int reconnectDelay;private static boolean running = true;public static void main(String[] args) {loadConfig();ExecutorService executor = Executors.newFixedThreadPool(2);while (running) {try (Socket socket = new Socket(serverIp, serverPort);BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) {LOGGER.info("Connected to NPort at " + serverIp + ":" + serverPort);// 启动接收数据线程executor.submit(() -> receiveData(in));// 发送数据示例(可根据需要调整)out.println("Hello NPort!");} catch (Exception e) {LOGGER.log(Level.WARNING, "Connection failed, retrying in " + reconnectDelay + "ms", e);try {Thread.sleep(reconnectDelay);} catch (InterruptedException ie) {Thread.currentThread().interrupt();}}}executor.shutdown();}private static void receiveData(BufferedReader in) {String response;try {while ((response = in.readLine()) != null) {LOGGER.info("Received from NPort: " + response);// 根据需要解析数据}} catch (SocketException e) {LOGGER.warning("Connection reset by peer, attempting to reconnect.");} catch (IOException e) {LOGGER.log(Level.SEVERE, "I/O error occurred", e);}}private static void loadConfig() {try (InputStream input = NPortClient.class.getClassLoader().getResourceAsStream("config.properties")) {Properties prop = new Properties();if (input == null) {LOGGER.severe("Sorry, unable to find config.properties");return;}prop.load(input);serverIp = prop.getProperty("server.ip");serverPort = Integer.parseInt(prop.getProperty("server.port"));reconnectDelay = Integer.parseInt(prop.getProperty("reconnect.delay"));} catch (IOException ex) {LOGGER.log(Level.SEVERE, "Error loading configuration", ex);}}
}

欢迎大家在评论区讨论,今天的干货分享就到此结束了,如果觉得对您有帮助,麻烦给个三连!

以上内容为本人的经验总结和平时操作的笔记。若有错误和重复请联系作者删除!!感谢支持!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/852079.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Whisper语音识别 -- 自回归解码分析

前言 Whisper 是由 OpenAI 开发的一种先进语音识别系统。它采用深度学习技术&#xff0c;能够高效、准确地将语音转换为文本。Whisper 支持多种语言和口音&#xff0c;并且在处理背景噪音和语音变异方面表现出色。其广泛应用于语音助手、翻译服务、字幕生成等领域&#xff0c;为…

树莓派 linux ARM 如何更新libc库

在进行嵌入是开发的时候,如果碰到 应用程序报告以下错误, 那么说明,你的嵌入式的系统 LIBC库版本过低。 这时候该怎么解决呢? 我再进行live555 开发的过程中就碰到了。 这时候,你可能需要选择比较低版本的交叉编译器,或者要选择低版本的开源库。 但是除了以上方法之…

unidbg讲解V1

前言 unidbg是什么? unidbg是一个Java项目,可以帮助我们去模拟一个安卓或IOS设备,用于去执行so文件中的算法,从而不需要再去逆向他内部的算法。最终会产出一个jar包,可以被python进行调用。 如何使用unidbg? 下载github上开源的项目:https://github.com/zhkl0228/un…

HTML的a标签如何做返回顶部的功能

在HTML中&#xff0c;<a> 标签通常用于创建超链接。要实现返回顶部的功能&#xff0c;你可以使用 <a> 标签结合JavaScript的 scrollTo() 方法&#xff08;尽管在大多数情况下&#xff0c;我们更常用 window.scrollTo(0, 0) 或 window.scroll(0, 0)&#xff09;&…

【因果推断python】32_合成控制2

目录 合成控制作为线性回归的一种实现​编辑 合成控制作为线性回归的一种实现 为了估计综合控制的治疗效果&#xff0c;我们将尝试构建一个类似于干预期之前的治疗单元的“假单元”。然后&#xff0c;我们将看到这个“假单位”在干预后的表现。合成控制和它所模仿的单位之间的…

OpenGauss常操作

OpenGauss官网已经有很详细的说明了,但是对于新手而言还有一些需要注意的地方; 安装 yum一键安装; yum -y install libaio-devel yum -y install readline-devel yum -y install libnsl 单独创建用户和组; groupadd dbgroup useradd -g dbgroup omm passwd omm 取消打开文…

关于学习Token、JWT、Cookie等验证授权方式的总结

目录 一、为什么Cookie无法防止CSRF攻击&#xff0c;而Token可以&#xff1f; 二、为什么无论采用Cookie-session的方式&#xff0c;还是Token&#xff08;JWT&#xff09;的方式&#xff0c;在一个浏览器里&#xff0c;同一个网站只能保证一个用户处于登录状态&#xff1f; …

韩顺平0基础学java——第22天

p441-459 异常exception 选中代码块&#xff0c;快捷键ctraltt6&#xff0c;即trt-catch 如果进行了异常处理&#xff0c;那么即使出现了异常&#xff0c;但是会继续执行 程序过程中发生的异常事件分为两大类&#xff1a; 异常体系图※ 常见的运行异常&#xff1a;类型转换…

vs2019 c++20规范 STL 库中头文件 <atomic> 源码注释及探讨几个知识点

&#xff08;1 探讨一&#xff09; 模板类 atomic 的继承关系与数据结构如下&#xff1a; (2 探讨二 ) 可见 atomic 的 fetch_xx 函数&#xff0c;返回的都是 atomic 中存储的旧值。测试如下&#xff1a; 谢谢

【MySQL】mysql中常见的内置函数(日期、字符串、数学函数)

文章目录 案例表日期函数字符串函数数学函数其他函数 案例表 emp students 表 exam_result 表 日期函数 注意current_time和now的区别 案例一&#xff1a; 创建一张表用来记录生日&#xff0c;表结构如下 添加日期&#xff1a; insert tmp (birthday) values (2003-01-3…

永磁同步电机滞环电流控制(PI双闭环)matlab仿真模型

微♥“电击小子程高兴的MATLAB小屋”获取模型 1.滞环电流控制的原理 将给定的电流信号与反馈的电流信号进行比较&#xff0c;然后控制它俩之间的差值稳定在一个滞环范围内&#xff0c;若超出范围&#xff0c;则进行相应的调节操作。 操作如下叙述&#xff1a;假设以三相中的A相…

【Android面试八股文】Thread.sleep()方法被调用之后可以被中断吗?

面试官:你能告诉我 Thread.sleep() 方法是否是可中断的吗?如果是,能解释一下如何中断它吗? 候选人:是的,Thread.sleep() 方法是可中断的。当一个线程正在调用 sleep() 方法时,如果另一个线程调用了这个睡眠线程的 interrupt() 方法,那么正在睡眠的线程会抛出 Interrup…

unDraw —— 免费且可定制的插画库,为您的设计注入灵魂

&#x1f3a8; unDraw —— 免费且可定制的插画库&#xff0c;为您的设计注入灵魂 在寻找能够完美融入您品牌风格的插画吗&#xff1f;unDraw&#xff0c;一个提供大量免费插画资源的网站&#xff0c;可能是您的理想选择&#xff01; &#x1f310; 网站特色 免费且开源 unDraw…

站易WordPress

站易WordPress是一家专业提供网站建设和运营服务的公司。他们提供的服务包括企业官方网站建设、网站运营维护、网站托管、网站优化、跨境独立站建站、外贸网站建设以及海外多语言网站建设等。 此外&#xff0c;站易还提供使用现成的WordPress模板&#xff0c;这样可以快速且低…

项目太大导致报错:JavaScript堆内存已满

1.问题 启动一个Vue项目的时候遇到了如下的报错 Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory 无效的标记压缩导致接近了堆上限&#xff0c;分配失败 - JavaScript内存不足 2.解决方法 我查阅了网上的资料&#xff0c;似乎…

udp协议下的socket函数

目录 1.网络协议 2.网络字节序 3.socket编译接口 4.sockaddr结构体 5.模拟实现 1.socket函数 2.bind函数&#xff08;绑定&#xff09; 1.讲解 1.如何快速的将 整数ip<->字符串 2.ip地址的注意事项 3.端口号的注意事项 3.recvfrom函数 4.sendto函数 5.代码呈…

不测评不知道,该这款主食冻干嚣张!PR、希喂、扑呀真实测评

主食冻干喂养越来越火了&#xff0c;除了知名的“四大金刚”K9、VE、SC、PR之外&#xff0c;也有像希喂、扑呀这类以营养、高肉含量为切入点的新锐品牌&#xff0c;各大猫粮商更是纷纷推出了自家的主食冻干产品。目前关于主食冻干的讨论也很多&#xff0c;但大多数还是以科普和…

江苏哪些行业需要服务器托管?

服务器托管顾名思义就是用户委托具有完善设备的机房、良好网络和丰富运营经验的服务商管理其计算机系统&#xff0c;使企业的服务器能够更加安全、稳定和高效的运行&#xff0c;那在江苏都有哪些行业需要服务器托管服务呢&#xff1f;本文就来大概介绍一下。 首先让我们来一起了…

spring管理的对象通过@Init注解修饰的方法不会在new对象的时候触发

Spring 管理的对象的初始化(init)函数并不会在 new 对象的时候自动触发,而是在 Spring 容器创建和初始化对象的时候触发。 Spring 容器管理对象的初始化过程包括以下几个步骤: 1 实例化对象 - Spring 容器使用构造函数或工厂方法创建对象实例。 注入属性 - Spring 容器会自动…

活久见!谁想的这种办法让大模型PK

文&#xff5c;白 鸽 编&#xff5c;王一粟 “每个大模型看起来都差不多&#xff0c;只能谁便宜先用谁的。但用下来之后&#xff0c;不合适再换&#xff0c;又费钱又费力”&#xff0c;一位AI 招聘公司的创始人对光锥智能抱怨道。 2024年&#xff0c;大模型正在加速走向行…