项目中, 需要用到通过串口读取扫码枪扫描出来的内容。在网上找了很多资料,都不是很理想。直到找到Java实现串口通信 - 掘金的内容,怕以后找不到,记录一下。方便以后查询。
环境准备
1、硬件环境准备,这里我用到的是霍尼韦尔的1900C扫码枪。需要安装扫码枪的驱动,并且需要将USB模拟串口输出。
代码配置
1、首选通过maven配置依赖包,如下图:
<!-- 串口内容读取 -->
<dependency>
<groupId>org.bidib.jbidib.org.qbang.rxtx</groupId>
<artifactId>rxtxcomm</artifactId>
<version>2.2</version>
</dependency>
然后,将制定的两个文件
放到对应的目录里面,
文件下载地址为:
链接:https://pan.baidu.com/s/1YBsxGLJKEVEKNiepweF5Aw?pwd=1234
提取码:1234
然后就是测试代码:
创建文件:
PortInit.java
package com.zy.autologin.autologin.pojo.vo;/**
* 一些声明信息
* Description:
* date: 2022/8/18 14:23
*
* @author CL
* @version
* @company zt
*/
import com.zy.autologin.autologin.service.impl.MyLister;
import com.zy.autologin.autologin.unitl.SerialPortUtil;
import gnu.io.SerialPort;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
/**
* ClassName: PortInit
* Description: // TODO
* date: 2022/8/18 14:23
* @author: CL
* @group: zy
*/
@Component
public class PortInit implements ApplicationRunner {
public static SerialPort serialPort = null;
@Override
public void run(ApplicationArguments args)
{
String portName = "COM3";
//查看所有串口
SerialPortUtil serialPortUtil = SerialPortUtil.getSerialPortUtil();
ArrayList<String> port = serialPortUtil.findPort();
System.out.println("发现全部串口:" + port);
System.out.println("打开指定portName:" + portName);
//打开该对应portName名字的串口
PortInit.serialPort = serialPortUtil.openPort(
portName,
9600,
SerialPort.DATABITS_8,
SerialPort.PARITY_NONE,
SerialPort.PARITY_ODD);
//给对应的serialPort添加监听器
serialPortUtil.addListener(PortInit.serialPort, new MyLister());
}
}
创建
MyLister.java
package com.zy.autologin.autologin.service.impl;/**
* 一些声明信息
* Description:
* date: 2022/8/18 14:34
*
* @author CL
* @version
* @company zt
*/
import com.zy.autologin.autologin.pojo.vo.PortInit;
import com.zy.autologin.autologin.unitl.SerialPortUtil;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.Date;
/**
* ClassName: MyLister
* Description: // TODO
* date: 2022/8/18 14:34
* @author: CL
* @group: zy
*/
@Service
@Slf4j
public class MyLister implements SerialPortEventListener {
@Override
public void serialEvent(SerialPortEvent event)
{
switch (event.getEventType())
{
//串口存在有效数据
case SerialPortEvent.DATA_AVAILABLE:
byte[] bytes = SerialPortUtil.getSerialPortUtil().readFromPort(PortInit.serialPort);
String byteStr = new String(bytes, 0, bytes.length).trim();
System.out.println("===========start===========");
System.out.println(new Date() + "【读到的字符串】:-----" + byteStr);
System.out.println(new Date() + "【字节数组转16进制字符串】:-----" + printHexString(bytes));
System.out.println("===========end===========");
break;
// 2.输出缓冲区已清空
case SerialPortEvent.OUTPUT_BUFFER_EMPTY:
log.error("输出缓冲区已清空");
break;
// 3.清除待发送数据
case SerialPortEvent.CTS:
log.error("清除待发送数据");
break;
// 4.待发送数据准备好了
case SerialPortEvent.DSR:
log.error("待发送数据准备好了");
break;
// 10.通讯中断
case SerialPortEvent.BI:
log.error("与串口设备通讯中断");
break;
default:
break;
}
}
/**
* 字节数组转16进制字符串
*
* @param b 字节数组
* @return 16进制字符串
*/
public static String printHexString(byte[] b)
{
StringBuilder sbf = new StringBuilder();
for (byte value : b)
{
String hex = Integer.toHexString(value & 0xFF);
if (hex.length() == 1)
{
hex = '0' + hex;
}
sbf.append(hex.toUpperCase()).append(" ");
}
return sbf.toString().trim();
}
/**
* 16进制字符串转字节数组
*
* @param hex 16进制字符串
* @return 字节数组
*/
public static byte[] hex2byte(String hex)
{
if (!isHexString(hex))
{
return null;
}
char[] arr = hex.toCharArray();
byte[] b = new byte[hex.length() / 2];
for (int i = 0, j = 0, l = hex.length(); i < l; i++, j++)
{
String swap = "" + arr[i++] + arr[i];
int byteint = Integer.parseInt(swap, 16) & 0xFF;
b[j] = new Integer(byteint).byteValue();
}
return b;
}
/**
* 校验是否是16进制字符串
*
* @param hex
* @return
*/
public static boolean isHexString(String hex)
{
if (hex == null || hex.length() % 2 != 0)
{
return false;
}
for (int i = 0; i < hex.length(); i++)
{
char c = hex.charAt(i);
if (!isHexChar(c))
{
return false;
}
}
return true;
}
/**
* 校验是否是16进制字符
*
* @param c
* @return
*/
private static boolean isHexChar(char c)
{
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
}
}
创建
SerialPortUtil.java
package com.zy.autologin.autologin.unitl;/**
* 一些声明信息
* Description:
* date: 2022/8/18 14:27
*
* @author CL
* @version
* @company zt
*/
import gnu.io.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.TooManyListenersException;
/**
* ClassName: SerialPortUtil
* Description: // TODO
* date: 2022/8/18 14:27
* @author: CL
* @group: zy
*/
@Service
@Slf4j
public class SerialPortUtil {
// private static final Logger logger = LoggerFactory.getLogger(SerialPortUtil.class);
private static SerialPortUtil serialPortUtil = null;
static
{
//在该类被ClassLoader加载时就初始化一个SerialTool对象
serialPortUtil = new SerialPortUtil();
}
//私有化SerialTool类的构造方法,不允许其他类生成SerialTool对象
private SerialPortUtil()
{
}
/**
* 获取提供服务的SerialTool对象
*
* @return serialPortUtil
*/
public static SerialPortUtil getSerialPortUtil()
{
if (serialPortUtil == null)
{
serialPortUtil = new SerialPortUtil();
}
return serialPortUtil;
}
/**
* 查找所有可用端口
*
* @return 可用端口名称列表
*/
public ArrayList<String> findPort()
{
//获得当前所有可用串口
Enumeration<CommPortIdentifier> portList = CommPortIdentifier.getPortIdentifiers();
ArrayList<String> portNameList = new ArrayList<>();
//将可用串口名添加到List并返回该List
while (portList.hasMoreElements())
{
String portName = portList.nextElement().getName();
portNameList.add(portName);
}
return portNameList;
}
/**
* 打开串口
*
* @param portName 端口名称
* @param baudrate 波特率 19200
* @param databits 数据位 8
* @param parity 校验位(奇偶位) NONE :0
* @param stopbits 停止位 1
* @return 串口对象
* // * @throws SerialPortParameterFailure 设置串口参数失败
* // * @throws NotASerialPort 端口指向设备不是串口类型
* // * @throws NoSuchPort 没有该端口对应的串口设备
* // * @throws PortInUse 端口已被占用
*/
public SerialPort openPort(String portName, int baudrate, int databits, int parity, int stopbits)
{
try
{
//通过端口名识别端口
CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);
//打开端口,并给端口名字和一个timeout(打开操作的超时时间)
CommPort commPort = portIdentifier.open(portName, 2000);
//判断是不是串口
if (commPort instanceof SerialPort)
{
SerialPort serialPort = (SerialPort) commPort;
//设置一下串口的波特率等参数
serialPort.setSerialPortParams(baudrate, databits, stopbits, parity);
System.out.println("Open " + portName + " sucessfully !");
return serialPort;
}
else
{
log.error("不是串口");
}
}
catch (NoSuchPortException e1)
{
log.error("没有找到端口");
e1.printStackTrace();
}
catch (PortInUseException e2)
{
log.error("端口被占用");
e2.printStackTrace();
}
catch (UnsupportedCommOperationException e)
{
e.printStackTrace();
}
return null;
}
/**
* 关闭串口
*
* @param serialPort 待关闭的串口对象
*/
public void closePort(SerialPort serialPort)
{
if (serialPort != null)
{
serialPort.close();
}
}
/**
* 往串口发送数据
*
* @param serialPort 串口对象
* @param order 待发送数据
* // * @throws SendDataToSerialPortFailure 向串口发送数据失败
* // * @throws SerialPortOutputStreamCloseFailure 关闭串口对象的输出流出错
*/
public void sendToPort(SerialPort serialPort, byte[] order)
{
OutputStream out = null;
try
{
out = serialPort.getOutputStream();
out.write(order);
out.flush();
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
try
{
if (out != null)
{
out.close();
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
/**
* 从串口读取数据
*
* @param serialPort 当前已建立连接的SerialPort对象
* @return 读取到的数据
* // * @throws ReadDataFromSerialPortFailure 从串口读取数据时出错
* // * @throws SerialPortInputStreamCloseFailure 关闭串口对象输入流出错
*/
public byte[] readFromPort(SerialPort serialPort)
{
InputStream in = null;
byte[] bytes = null;
try
{
Thread.sleep(500);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
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)
{
e.printStackTrace();
}
finally
{
try
{
if (in != null)
{
in.close();
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
return bytes;
}
/**
* 添加监听器
*
* @param port 串口对象
* @param listener 串口监听器
* // * @throws TooManyListeners 监听类对象过多
*/
public void addListener(SerialPort port, SerialPortEventListener listener)
{
try
{
//给串口添加监听器
port.addEventListener(listener);
//设置当有数据到达时唤醒监听接收线程
port.notifyOnDataAvailable(true);
//设置当通信中断时唤醒中断线程
port.notifyOnBreakInterrupt(true);
}
catch (TooManyListenersException e)
{
log.error("太多监听器");
e.printStackTrace();
}
}
/**
* 删除监听器
*
* @param port 串口对象
* @param listener 串口监听器
* // * @throws TooManyListeners 监听类对象过多
*/
public void removeListener(SerialPort port, SerialPortEventListener listener)
{
//删除串口监听器
port.removeEventListener();
}
/**
* 设置串口的Listener
*
* @param serialPort
* @param listener
* @author mar
* @date 2021/8/20 11:04
*/
public static void setListenerToSerialPort(SerialPort serialPort, SerialPortEventListener listener)
{
try
{
//给串口添加事件监听
serialPort.addEventListener(listener);
}
catch (TooManyListenersException e)
{
e.printStackTrace();
}
//串口有数据监听
serialPort.notifyOnDataAvailable(true);
//中断事件监听
serialPort.notifyOnBreakInterrupt(true);
}
}
然后启动测试,使用扫码枪测试就好
以上文章内容来自:Java实现串口通信 - 掘金