本文主要实现读取员工刷卡信息
将淘宝买的刷卡IC卡读取器插入Windows笔记本的USB接口,安装驱动,设备管理器会自动添加一个模拟的COM3串口
本次使用的Java环境为
java version “1.8.0_112”
Java™ SE Runtime Environment (build 1.8.0_112-b15)
Java HotSpot™ 64-Bit Server VM (build 25.112-b15, mixed mode)
rxtxParallel.dll
,rxtxSerial.dll
copy to C:\Program Files\Java\jdk1.8.0_112\jre\bin
我使用的是创建一个JavaFX项目,因为只是写一个Demo,JavaFX和Java项目区别不大
在项目中创建一个lib包,将下载的RXTXcomm.jar
文件放入lib包中,将lib包设置为项目资源
IDEA设置:右键RXTXcomm.jar
,选择Add as Library...
即可
SerialTool
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Locale;
import java.util.TooManyListenersException;
import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.NoSuchPortException;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import gnu.io.UnsupportedCommOperationException;
public class SerialTool {
/**
* 查找所有可用端口
* @return 可用端口名称列表
*/
public static final ArrayList<String> findPort() {
//获得当前所有可用串口
@SuppressWarnings("unchecked")
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) {
try {
//通过端口名识别端口
CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);
//打开端口,并给端口名字和一个timeout(打开操作的超时时间)
CommPort commPort = portIdentifier.open(portName, 2000);
//判断是不是串口
if (commPort instanceof SerialPort) {
SerialPort serialPort = (SerialPort) commPort;
try {
//设置一下串口的波特率等参数
serialPort.setSerialPortParams(baudrate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
} catch (UnsupportedCommOperationException e) {
throw new RuntimeException("设置串口参数失败!打开串口操作未完成!");
}
System.out.println("Open " + portName + " successfully !");
return serialPort;
}
else {
//不是串口
throw new RuntimeException("端口指向设备不是串口类型");
}
} catch (NoSuchPortException e1) {
throw new RuntimeException("没有该端口对应的串口设备");
} catch (PortInUseException e2) {
throw new RuntimeException("端口已被占用");
}
}
/**
* 关闭串口
* @param serialPort 待关闭的串口对象
*/
public static void closePort(SerialPort serialPort) {
if (serialPort != null) {
serialPort.close();
serialPort = null;
}
}
/**
* 往串口发送数据
* @param serialPort 串口对象
* @param order 待发送数据
*/
public static void sendToPort(SerialPort serialPort, byte[] order) {
try (OutputStream out = serialPort.getOutputStream()){
out.write(order);
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 从串口读取数据
* @param serialPort 当前已建立连接的SerialPort对象
* @return 读取到的数据
*/
public static byte[] readFromPort(SerialPort serialPort) {
InputStream in = null;
byte[] bytes = null;
try {
in = serialPort.getInputStream();
int bufflenth = in.available(); //获取buffer里的数据长度
while (bufflenth != 0) {
bytes = new byte[bufflenth]; //初始化byte数组为buffer中数据的长度
in.read(bytes);
bufflenth = in.available();
}
} catch (IOException e) {
e.printStackTrace();
System.err.println("从串口读取数据时出错");
} finally {
try {
if (in != null) {
in.close();
in = null;
}
} catch(IOException e) {
e.printStackTrace();
System.err.println("关闭串口对象输入流出错");
}
}
System.out.println("读取成功");
return bytes;
}
/**
* 添加监听器
* @param port 串口对象
* @param listener 串口监听器
*/
public static void addListener(SerialPort port, DataAvailableListener listener){
try {
//给串口添加监听器
port.addEventListener(new SerialPortListener(listener));
//设置当有数据到达时唤醒监听接收线程
port.notifyOnDataAvailable(true);
//设置当通信中断时唤醒中断线程
port.notifyOnBreakInterrupt(true);
} catch (TooManyListenersException e) {
e.printStackTrace();
System.err.println("监听类对象过多");
}
}
/**
* 串口监听
*/
public static class SerialPortListener implements SerialPortEventListener {
private DataAvailableListener mDataAvailableListener;
public SerialPortListener(DataAvailableListener mDataAvailableListener) {
this.mDataAvailableListener = mDataAvailableListener;
}
public void serialEvent(SerialPortEvent serialPortEvent) {
switch (serialPortEvent.getEventType()) {
case SerialPortEvent.DATA_AVAILABLE: // 1.串口存在有效数据
if (mDataAvailableListener != null) {
mDataAvailableListener.dataAvailable();
}
break;
case SerialPortEvent.OUTPUT_BUFFER_EMPTY: // 2.输出缓冲区已清空
break;
case SerialPortEvent.CTS: // 3.清除待发送数据
break;
case SerialPortEvent.DSR: // 4.待发送数据准备好了
break;
case SerialPortEvent.RI: // 5.振铃指示
break;
case SerialPortEvent.CD: // 6.载波检测
break;
case SerialPortEvent.OE: // 7.溢位(溢出)错误
break;
case SerialPortEvent.PE: // 8.奇偶校验错误
break;
case SerialPortEvent.FE: // 9.帧错误
break;
case SerialPortEvent.BI: // 10.通讯中断
System.out.println("与串口设备通讯中断");
break;
default:
break;
}
}
}
/**
* 串口存在有效数据监听
*/
public interface DataAvailableListener {
/**
* 串口存在有效数据
*/
void dataAvailable();
}
public static byte[] hex2Bytes(String hex) {
if (hex == null || hex.length() == 0) {
return null;
}
char[] hexChars = hex.toCharArray();
byte[] bytes = new byte[hexChars.length / 2]; // 如果 hex 中的字符不是偶数个, 则忽略最后一个
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) Integer.parseInt("" + hexChars[i * 2] + hexChars[i * 2 + 1], 16);
}
return bytes;
}
/**
* byte[]转十六进制字符串
*
* @param array
* byte[]
* @return 十六进制字符串
*/
public static String byteArrayToHexString(byte[] array) {
if (array == null) {
return "";
}
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < array.length; i++) {
buffer.append(byteToHex(array[i]));
}
return buffer.toString();
}
/**
* byte转十六进制字符
*
* @param b
* byte
* @return 十六进制字符
*/
public static String byteToHex(byte b) {
String hex = Integer.toHexString(b & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
return hex.toUpperCase(Locale.getDefault());
}
public static String stringToAscii(String value)
{
StringBuffer sbu = new StringBuffer();
char[] chars = value.toCharArray();
for (int i = 0; i < chars.length; i++) {
if(i != chars.length - 1)
{
sbu.append((int)chars[i]).append(",");
}
else {
sbu.append((int)chars[i]);
}
}
return sbu.toString();
}
}
import gnu.io.SerialPort;
import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import sample.utils.*;
import java.util.ArrayList;
public class Controller {
@FXML
Button writeButton;
@FXML
TextArea readTextarea;
@FXML
TextArea writeTextarea;
@FXML
TextField comName;
// 串口
SerialPort port = null;
/** 开启串口
*
*/
@FXML
public void startCom() {
if(port != null){
Alert alert = new Alert(Alert.AlertType.CONFIRMATION, "串口已经打开:" + port.getName());
alert.show();
return;
}
ArrayList<String> findPorts = SerialTool.findPort();
if(findPorts.isEmpty()){
Alert alert = new Alert(Alert.AlertType.CONFIRMATION, "未找到串口信息!");
alert.show();
return;
}
String portName = findPorts.get(0);//默认打开第一个串口
// 设置使用的串口
comName.setText(portName);
try {
port = SerialTool.openPort(portName, 9600);//打开串口
} catch (RuntimeException e){
Alert alert = new Alert(Alert.AlertType.ERROR, e.getMessage());
alert.show();
return;
}
SerialTool.addListener(port, () -> {
byte[] data = null;
try {
if (port == null) {
System.out.println("串口对象为空,监听失败!");
} else {
// 读取串口数据
data = SerialTool.readFromPort(port);
String resultHEX = SerialTool.byteArrayToHexString(data);
readTextarea.setText(resultHEX);
}
} catch (Exception e) {
Alert alert = new Alert(Alert.AlertType.ERROR, "发生了一个异常:".concat(e.getMessage()));
alert.show();
}
});
Alert alert = new Alert(Alert.AlertType.CONFIRMATION, "串口开启成功!");
alert.show();
}
/** 写入串口数据
*
*/
@FXML
public void writeCom() {
if(port == null){
Alert alert = new Alert(Alert.AlertType.CONFIRMATION, "请先开启串口!");
alert.show();
return;
}
String content = writeTextarea.getText();
if(content == null || content.trim().length() <=0){
Alert alert = new Alert(Alert.AlertType.CONFIRMATION, "请填写写入的数据!");
alert.show();
return;
}
//设定发送字符串
byte[] bs = SerialTool.hex2Bytes(content);
SerialTool.sendToPort(port, bs);//写入,写入应该在监听器打开之后而不是之前
Alert alert = new Alert(Alert.AlertType.CONFIRMATION, "写入成功!");
alert.show();
}
}
我写的demo源码地址
源码网盘下载地址 提取码:pz8i
参考文档-java串口通信demo