最近笔者接触到串口编程,网上搜了些资料,顺便整理一下。网上都在推荐使用Java RXTX开源类库,它提供了Windows、Linux等不同操作系统下的串口和并口通信实现,遵循GNU LGPL协议。看起来不错,写个例子试试。

准备运行环境

下载RXTX

RXTX下载地址是:http://fizzed.com/oss/rxtx-for-java

笔者操作系统是Windows10,下载对应版本的压缩包,解压后复制RXTXcomm.jar到D:\Program Files\Java\jdk1.8.0_152\jre\lib\ext目录下;复制rxtxParallel.dll和rxtxSerial.dll到D:\Program Files\Java\jdk1.8.0_152\jre\bin目录下。

注意:安装jdk时可能也顺便装了jre,需要复制到jdk的jre目录下。

下载Virtual Serial Port Driver

Virtual Serial Port Driver是一款非常好用的虚拟串口模拟软件,可以在计算机模拟串口,方便开发和测试。安装后打开界面如下:

可以看到右侧默认出现COM1和COM2的串口,点击Add pair就可以创建这两个串口了,打开计算机管理,可以看到本机多了这两个端口,如下图所示:

创建项目

创建serialPort项目,如下图所示:

串口工具类

现在可以写一个串口工具类,方便开发和测试,代码如下:

public class SerialPortUtils {

private static Logger log = LoggerFactory.getLogger(SerialPortUtils.class);

/**

* 打卡串口

* @param portName 串口名

* @param baudRate 波特率

* @param dataBits 数据位

* @param stopBits 停止位

* @param parity 校验位

* @return 串口对象

*/

public static SerialPort open(String portName, Integer baudRate, Integer dataBits,

Integer stopBits, Integer parity) {

SerialPort result = null;

try {

// 通过端口名识别端口

CommPortIdentifier identifier = CommPortIdentifier.getPortIdentifier(portName);

// 打开端口,并给端口名字和一个timeout(打开操作的超时时间)

CommPort commPort = identifier.open(portName, 2000);

// 判断是不是串口

if (commPort instanceof SerialPort) {

result = (SerialPort) commPort;

// 设置一下串口的波特率等参数

result.setSerialPortParams(baudRate, dataBits, stopBits, parity);

log.info("打开串口{}成功", portName);

}else{

log.info("{}不是串口", portName);

}

} catch (Exception e) {

log.error("打开串口{}错误", portName, e);

}

return result;

}

/**

* 串口增加数据可用监听器

* @param serialPort

* @param listener

*/

public static void addListener(SerialPort serialPort, DataAvailableListener listener) {

if(serialPort == null){

return;

}

try {

// 给串口添加监听器

serialPort.addEventListener(new SerialPortListener(listener));

// 设置当有数据到达时唤醒监听接收线程

serialPort.notifyOnDataAvailable(Boolean.TRUE);

// 设置当通信中断时唤醒中断线程

serialPort.notifyOnBreakInterrupt(Boolean.TRUE);

} catch (TooManyListenersException e) {

log.error("串口{}增加数据可用监听器错误", serialPort.getName(), e);

}

}

/**

* 从串口读取数据

* @param serialPort

* @return

*/

public static byte[] read(SerialPort serialPort) {

byte[] result = {};

if(serialPort == null){

return result;

}

InputStream inputStream = null;

try {

inputStream = serialPort.getInputStream();

// 缓冲区大小为1个字节,可根据实际需求修改

byte[] readBuffer = new byte[1];

while (inputStream.available() > 0) {

inputStream.read(readBuffer);

result = ArrayUtil.addAll(result, readBuffer);

}

} catch (IOException e) {

log.error("串口{}读取数据错误", serialPort.getName(), e);

} finally {

IoUtil.close(inputStream);

}

return result;

}

/**

* 往串口发送数据

* @param serialPort

* @param data

*/

public static void write(SerialPort serialPort, byte[] data) {

if(serialPort == null){

return;

}

OutputStream outputStream = null;

try {

outputStream = serialPort.getOutputStream();

outputStream.write(data);

outputStream.flush();

} catch (Exception e) {

log.error("串口{}发送数据错误", serialPort.getName(), e);

} finally {

IoUtil.close(outputStream);

}

}

/**

* 关闭串口

* @param serialPort

*/

public static void close(SerialPort serialPort) {

if (serialPort != null) {

serialPort.close();

log.warn("串口{}关闭", serialPort.getName());

}

}

/**

* 查询可用端口

* @return 串口名List

*/

public static List listPortName() {

List result = new ArrayList<>();

// 获得当前所有可用端口

Enumeration serialPorts = CommPortIdentifier.getPortIdentifiers();

if(serialPorts == null){

return result;

}

// 将可用端口名添加到List并返回该List

while (serialPorts.hasMoreElements()) {

result.add(serialPorts.nextElement().getName());

}

return result;

}

}

测试代码

测试代码如下,先不要着急运行,下一步打开串口调试助手协助测试。

public class SerialPortTest {

public static void main(String[] args) throws Exception{

// 打开串口

SerialPort serialPort = SerialPortUtils.open("COM1", 9600, SerialPort.DATABITS_8,

SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);

// 监听串口读取数据

SerialPortUtils.addListener(serialPort, () -> {

byte[] data = SerialPortUtils.read(serialPort);

System.out.println(HexUtil.encodeHexStr(data));

});

// 往串口发送数据

byte[] data = {1, 2, 3};

SerialPortUtils.write(serialPort, data);

/*// 关闭串口

Thread.sleep(2000);

SerialPortUtils.close(serialPort);*/

// 测试可用端口

//SerialPortUtils.listPortName().forEach(o -> System.out.println(o));

}

}

串口调试助手

UartAssist是一款很好用的串口调试助手,先运行串口调试助手,接收设置和发送设置都选择HEX,串口号选择COM2->COM1(测试代码使用的COM1),其他默认,点击打开串口,然后运行测试代码SerialPortTest,效果如下图所示:

运行测试代码后,串口调试助手显示收到01 02 03,然后串口调试助手点击发送,idea控制台也会显示收到11223344556677,说明COM1和COM2串口互相发送和接收数据成功。

粘包/拆包的解决方案

在实际应用中,有些功能复杂的串口通信可能会发生粘包/拆包的情况,这时可以自建一个缓冲区,用来缓冲数据并处理数据。《Netty权威指南第2版》中,有TCP粘包/拆包问题的解决之道,原理可供参考,需要自己写代码实现,推荐使用Netty的缓冲区ByteBuf,功能强大。

参考资料

面向串口编程java_Java串口编程例子相关推荐

  1. 多线程编程java_Java多线程编程

    Java给多线程编程提供了内置的支持.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务. 多线程是多任务的一种特别的形式,但多线程使用了更小的资源开销. ...

  2. 多线程编程 java_java多线程编程

    一.多线程的优缺点 多线程的优点: 1)资源利用率更好 2)程序设计在某些情况下更简单 3)程序响应更快 多线程的代价: 1)设计更复杂 虽然有一些多线程应用程序比单线程的应用程序要简单,但其他的一般 ...

  3. 猴子爬山编程java_Java趣味编程100例

    第1章 变幻多姿的图表(教学视频:69分钟) 1.1 金字塔图案 1.2 九九乘法表 1.3 余弦曲线 1.4 奥运五环旗 1.5 杨辉三角 1.6 国际象棋棋盘 1.7 心形图 1.8 回型矩阵 1 ...

  4. 单片机 串口编程之串口通信仿真实验

    单片机 串口编程之串口通信仿真实验 一.简述        记--简单的使能串口,串口收发数据的例子.(使用Proteus仿真+虚拟串口调试)        代码,仿真文件打包:链接: https:/ ...

  5. Esp8266 进阶之路25【高级篇】深聊下esp8266的串口 Uart 通讯中断编程,为您准备好了 NONOS 版本 和 RTOS 系统的串口驱动文件。(附带Demo)

    本系列博客学习由非官方人员 半颗心脏 潜心所力所写,不做开发板.仅仅做个人技术交流分享,不做任何商业用途.如有不对之处,请留言,本人及时更改. 序号 SDK版本 内容 链接 1 nonos2.0 搭建 ...

  6. Linux系统编程:串口编程

    Linux系统编程:串口编程 Linux下的串口概述 Linux串口编程 代码解析 编译和测试 代码中的常量介绍 Linux下的串口概述 常见的数据通信的基本方式分为并行通信和串行通信. 1.并行通信 ...

  7. Linux——Linux系统编程之串口编程总结(串口的初始化、读写操作实践)

    目录 0 引言 1 串口编程的流程 1.1 打开串口 1.2 初始化串口 1.2.1 termios结构体 1.2.2 关键函数 1.2.3 初始化串口代码 2 串口的读写测试例程 0 引言 串口大家 ...

  8. c8051f020C语言程序,C8051F020编程UART串口收发数据

    C8051F020编程UART串口收发数据 我编了一个 老是编译不过去 求高手改正 我用的是UART0端口 方式2 程序如下 //>>UART0串口编程--向PC发送和接受字符串<& ...

  9. (串口通信编程) 开源串口调试助手Common (Com Monitor)

    原文地址为: (串口通信编程) 开源串口调试助手Common (Com Monitor) 最新的文档见这里:http://blog.twofei.com/566/ 我写的串口调试助手程序以及源代码. ...

最新文章

  1. 在Solaris系统中,查看tcp/ip配置
  2. qt 拖拽 修改大小
  3. PHP常用功能块_错误和异常处理 — php(32)
  4. Linux C/C++ 如何输出彩色字体
  5. 小技巧:用python迅速打印Java写 的Flink代码中的hive建表语句
  6. python中函数的可变参数_Python中函数的参数定义和可变参数
  7. Unity C# 设计模式(五)建造者模式
  8. swift获取图片像素颜色值
  9. matlab simulink汽车巡航时的速度模糊pid控制
  10. windows中查看端口占用情况以及删除端口
  11. 网易云豆瓣数据分析——爬虫(结尾附代码
  12. 移动硬盘更改驱动器号和路径_如何在Windows 10中更改默认硬盘驱动器以保存文档和应用程序...
  13. 2010武汉IT环境~
  14. Xmanager 5 远程连接linux图形界面
  15. 管理人员如何有效应用表扬与批评进行反馈
  16. S32K144烧写程序记录
  17. 在ts文件中使用require报错解决
  18. 黑马程序员——网络编程
  19. 阿里月薪50k招数据分析师,这个要求过分吗?
  20. android settings$,android settings命令

热门文章

  1. python之入门,你好,中国
  2. Mybatis在Maven项目中使用
  3. Java中可以声明一个类为Static吗?
  4. 6 Django系列之关于models的sql语句日常用法总结
  5. 用jquery在必填表单字段前加红星总结
  6. urb传输的代码分析【转】
  7. 一种非常简单的静态网页生成方法介绍
  8. (转)EF三种编程方式详细图文教程(C#+EF)之Database First
  9. light7在微信ios下input点击困难
  10. [源码和文档分享]基于C#和MYSQL数据库实现的课程自动考试系统