java使用Rxtx實現(xiàn)串口通信調(diào)試工具
本文實例為大家分享了java使用Rxtx實現(xiàn)串口通信調(diào)試工具的具體代碼,供大家參考,具體內(nèi)容如下
最終效果如下圖:

1、把rxtxParallel.dll、rxtxSerial.dll拷貝到:C:\WINDOWS\system32下。
2、RXTXcomm.jar 添加到項目類庫中。
代碼:
package serialPort;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
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.SerialPortEventListener;
import gnu.io.UnsupportedCommOperationException;
/**串口服務(wù)類,提供打開、關(guān)閉串口,讀取、發(fā)送串口數(shù)據(jù)等服務(wù)
*/
public class SerialTool {
private static SerialTool serialTool = null;
static {
//在該類被ClassLoader加載時就初始化一個SerialTool對象
if (serialTool == null) {
serialTool = new SerialTool();
}
}
//私有化SerialTool類的構(gòu)造方法,不允許其他類生成SerialTool對象
private SerialTool() {}
/**
* 獲取提供服務(wù)的SerialTool對象
* @return serialTool
*/
public static SerialTool getSerialTool() {
if (serialTool == null) {
serialTool = new SerialTool();
}
return serialTool;
}
/**
* 查找所有可用端口
* @return 可用端口名稱列表
*/
public static final List<String> findPort() {
//獲得當(dāng)前所有可用串口
@SuppressWarnings("unchecked")
Enumeration<CommPortIdentifier> portList = CommPortIdentifier.getPortIdentifiers();
List<String> portNameList = new ArrayList<>();
//將可用串口名添加到List并返回該List
while (portList.hasMoreElements()) {
String portName = portList.nextElement().getName();
portNameList.add(portName);
}
return portNameList;
}
/**
* 打開串口
* @param portName 端口名稱
* @param baudrate 波特率
* @return 串口對象
* @throws UnsupportedCommOperationException
* @throws PortInUseException
* @throws NoSuchPortException
*/
public static final SerialPort openPort(String portName, int baudrate) throws UnsupportedCommOperationException, PortInUseException, NoSuchPortException {
//通過端口名識別端口
CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);
//打開端口,并給端口名字和一個timeout(打開操作的超時時間)
CommPort commPort = portIdentifier.open(portName, 2000);
//判斷是不是串口
if (commPort instanceof SerialPort) {
SerialPort serialPort = (SerialPort) commPort;
//設(shè)置一下串口的波特率等參數(shù)
serialPort.setSerialPortParams(baudrate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
return serialPort;
}
return null;
}
/**
* 關(guān)閉串口
* @param serialport 待關(guān)閉的串口對象
*/
public static void closePort(SerialPort serialPort) {
if (serialPort != null) {
serialPort.close();
serialPort = null;
}
}
/**
* 往串口發(fā)送數(shù)據(jù)
* @param serialPort 串口對象
* @param order 待發(fā)送數(shù)據(jù)
* @throws IOException
*/
public static void sendToPort(SerialPort serialPort, byte[] order) throws IOException {
OutputStream out = null;
out = serialPort.getOutputStream();
out.write(order);
out.flush();
out.close();
}
/**
* 從串口讀取數(shù)據(jù)
* @param serialPort 當(dāng)前已建立連接的SerialPort對象
* @return 讀取到的數(shù)據(jù)
* @throws IOException
*/
public static byte[] readFromPort(SerialPort serialPort) throws IOException {
InputStream in = null;
byte[] bytes = null;
try {
in = serialPort.getInputStream();
int bufflenth = in.available(); //獲取buffer里的數(shù)據(jù)長度
while (bufflenth != 0) {
bytes = new byte[bufflenth]; //初始化byte數(shù)組為buffer中數(shù)據(jù)的長度
in.read(bytes);
bufflenth = in.available();
}
} catch (IOException e) {
throw e;
} finally {
if (in != null) {
in.close();
in = null;
}
}
return bytes;
}
/**添加監(jiān)聽器
* @param port 串口對象
* @param listener 串口監(jiān)聽器
* @throws TooManyListenersException
*/
public static void addListener(SerialPort port, SerialPortEventListener listener) throws TooManyListenersException {
//給串口添加監(jiān)聽器
port.addEventListener(listener);
//設(shè)置當(dāng)有數(shù)據(jù)到達(dá)時喚醒監(jiān)聽接收線程
port.notifyOnDataAvailable(true);
//設(shè)置當(dāng)通信中斷時喚醒中斷線程
port.notifyOnBreakInterrupt(true);
}
}
package serialPort;
import java.awt.Color;
import java.awt.Font;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.TooManyListenersException;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.border.TitledBorder;
import gnu.io.NoSuchPortException;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import gnu.io.UnsupportedCommOperationException;
/**
* 監(jiān)測數(shù)據(jù)顯示類
* @author Zhong
*
*/
public class SerialView extends JFrame {
/**
*/
private static final long serialVersionUID = 1L;
//設(shè)置window的icon
Toolkit toolKit = getToolkit();
Image icon = toolKit.getImage(SerialView.class.getResource("computer.png"));
DateTimeFormatter df= DateTimeFormatter.ofPattern("YYYY-MM-dd HH:mm:ss.SSS");
private JComboBox<String> commChoice;
private JComboBox<String> bpsChoice;
private JButton openSerialButton;
private JButton sendButton;
private JTextArea sendArea;
private JTextArea receiveArea;
private JButton closeSerialButton;
private List<String> commList = null; //保存可用端口號
private SerialPort serialPort = null; //保存串口對象
/**類的構(gòu)造方法
* @param client
*/
public SerialView() {
init();
TimerTask task = new TimerTask() {
@Override
public void run() {
commList = SerialTool.findPort(); //程序初始化時就掃描一次有效串口
//檢查是否有可用串口,有則加入選項中
if (commList == null || commList.size()<1) {
JOptionPane.showMessageDialog(null, "沒有搜索到有效串口!", "錯誤", JOptionPane.INFORMATION_MESSAGE);
}else{
commChoice.removeAllItems();
for (String s : commList) {
commChoice.addItem(s);
}
}
}
};
Timer timer = new Timer();
timer.scheduleAtFixedRate(task, 0, 10000);
listen();
}
/**
*/
private void listen(){
//打開串口連接
openSerialButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//獲取串口名稱
String commName = (String) commChoice.getSelectedItem();
//獲取波特率
String bpsStr = (String) bpsChoice.getSelectedItem();
//檢查串口名稱是否獲取正確
if (commName == null || commName.equals("")) {
JOptionPane.showMessageDialog(null, "沒有搜索到有效串口!", "錯誤", JOptionPane.INFORMATION_MESSAGE);
}else {
//檢查波特率是否獲取正確
if (bpsStr == null || bpsStr.equals("")) {
JOptionPane.showMessageDialog(null, "波特率獲取錯誤!", "錯誤", JOptionPane.INFORMATION_MESSAGE);
}else {
//串口名、波特率均獲取正確時
int bps = Integer.parseInt(bpsStr);
try {
//獲取指定端口名及波特率的串口對象
serialPort = SerialTool.openPort(commName, bps);
SerialTool.addListener(serialPort, new SerialListener());
if(serialPort==null) return;
//在該串口對象上添加監(jiān)聽器
closeSerialButton.setEnabled(true);
sendButton.setEnabled(true);
openSerialButton.setEnabled(false);
String time=df.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis()),ZoneId.of("Asia/Shanghai")));
receiveArea.append(time+" ["+serialPort.getName().split("/")[3]+"] : "+" 連接成功..."+"\r\n");
receiveArea.setCaretPosition(receiveArea.getText().length());
} catch (UnsupportedCommOperationException | PortInUseException | NoSuchPortException | TooManyListenersException e1) {
e1.printStackTrace();
}
}
}
}
});
//發(fā)送數(shù)據(jù)
sendButton.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if(!sendButton.isEnabled())return;
String message= sendArea.getText();
//"FE0400030001D5C5"
try {
SerialTool.sendToPort(serialPort, hex2byte(message));
} catch (IOException e1) {
e1.printStackTrace();
}
}
});
//關(guān)閉串口連接
closeSerialButton.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if(!closeSerialButton.isEnabled())return;
SerialTool.closePort(serialPort);
String time=df.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis()),ZoneId.of("Asia/Shanghai")));
receiveArea.append(time+" ["+serialPort.getName().split("/")[3]+"] : "+" 斷開連接"+"\r\n");
receiveArea.setCaretPosition(receiveArea.getText().length());
openSerialButton.setEnabled(true);
closeSerialButton.setEnabled(false);
sendButton.setEnabled(false);
}
});
}
/**
* 主菜單窗口顯示;
* 添加JLabel、按鈕、下拉條及相關(guān)事件監(jiān)聽;
*/
private void init() {
this.setBounds(WellcomView.LOC_X, WellcomView.LOC_Y, WellcomView.WIDTH, WellcomView.HEIGHT);
this.setTitle("串口調(diào)試");
this.setIconImage(icon);
this.setBackground(Color.gray);
this.setLayout(null);
Font font =new Font("微軟雅黑", Font.BOLD, 16);
receiveArea=new JTextArea(18, 30);
receiveArea.setEditable(false);
JScrollPane receiveScroll = new JScrollPane(receiveArea);
receiveScroll.setBorder(new TitledBorder("接收區(qū)"));
//滾動條自動出現(xiàn) FE0400030001D5C5
receiveScroll.setHorizontalScrollBarPolicy(
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
receiveScroll.setVerticalScrollBarPolicy(
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
receiveScroll.setBounds(52, 20, 680,340);
this.add(receiveScroll);
JLabel chuankou=new JLabel(" 串口選擇: ");
chuankou.setFont(font);
chuankou.setBounds(50, 380, 100,50);
this.add(chuankou);
JLabel botelv=new JLabel(" 波 特 率: ");
botelv.setFont(font);
botelv.setBounds(290, 380, 100,50);
this.add(botelv);
//添加串口選擇選項
commChoice = new JComboBox<String>(); //串口選擇(下拉框)
commChoice.setBounds(145, 390, 100, 30);
this.add(commChoice);
//添加波特率選項
bpsChoice = new JComboBox<String>(); //波特率選擇
bpsChoice.setBounds(380, 390, 100, 30);
bpsChoice.addItem("1500");
bpsChoice.addItem("2400");
bpsChoice.addItem("4800");
bpsChoice.addItem("9600");
bpsChoice.addItem("14400");
bpsChoice.addItem("19500");
bpsChoice.addItem("115500");
this.add(bpsChoice);
//添加打開串口按鈕
openSerialButton = new JButton("連接");
openSerialButton.setBounds(540, 390, 80, 30);
openSerialButton.setFont(font);
openSerialButton.setForeground(Color.darkGray);
this.add(openSerialButton);
//添加關(guān)閉串口按鈕
closeSerialButton = new JButton("關(guān)閉");
closeSerialButton.setEnabled(false);
closeSerialButton.setBounds(650, 390, 80, 30);
closeSerialButton.setFont(font);
closeSerialButton.setForeground(Color.darkGray);
this.add(closeSerialButton);
sendArea=new JTextArea(30,20);
JScrollPane sendScroll = new JScrollPane(sendArea);
sendScroll.setBorder(new TitledBorder("發(fā)送區(qū)"));
//滾動條自動出現(xiàn)
sendScroll.setHorizontalScrollBarPolicy(
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
sendScroll.setVerticalScrollBarPolicy(
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
sendScroll.setBounds(52, 450, 500,100);
this.add(sendScroll);
sendButton = new JButton("發(fā) 送");
sendButton.setBounds(610, 520, 120, 30);
sendButton.setFont(font);
sendButton.setForeground(Color.darkGray);
sendButton.setEnabled(false);
this.add(sendButton);
this.setResizable(false); //窗口大小不可更改
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
/**字符串轉(zhuǎn)16進(jìn)制
* @param hex
* @return
*/
private byte[] hex2byte(String hex) {
String digital = "0123456789ABCDEF";
String hex1 = hex.replace(" ", "");
char[] hex2char = hex1.toCharArray();
byte[] bytes = new byte[hex1.length() / 2];
byte temp;
for (int p = 0; p < bytes.length; p++) {
temp = (byte) (digital.indexOf(hex2char[2 * p]) * 16);
temp += digital.indexOf(hex2char[2 * p + 1]);
bytes[p] = (byte) (temp & 0xff);
}
return bytes;
}
/**字節(jié)數(shù)組轉(zhuǎn)16進(jìn)制
* @param b
* @return
*/
private String printHexString(byte[] b) {
StringBuffer sbf=new StringBuffer();
for (int i = 0; i < b.length; i++) {
String hex = Integer.toHexString(b[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
sbf.append(hex.toUpperCase()+" ");
}
return sbf.toString().trim();
}
/**
* 以內(nèi)部類形式創(chuàng)建一個串口監(jiān)聽類
* @author zhong
*/
class SerialListener implements SerialPortEventListener {
/**
* 處理監(jiān)控到的串口事件
*/
public void serialEvent(SerialPortEvent serialPortEvent) {
switch (serialPortEvent.getEventType()) {
case SerialPortEvent.BI: // 10 通訊中斷
JOptionPane.showMessageDialog(null, "與串口設(shè)備通訊中斷", "錯誤", JOptionPane.INFORMATION_MESSAGE);
break;
case SerialPortEvent.OE: // 7 溢位(溢出)錯誤
break;
case SerialPortEvent.FE: // 9 幀錯誤
break;
case SerialPortEvent.PE: // 8 奇偶校驗錯誤
break;
case SerialPortEvent.CD: // 6 載波檢測
break;
case SerialPortEvent.CTS: // 3 清除待發(fā)送數(shù)據(jù)
break;
case SerialPortEvent.DSR: // 4 待發(fā)送數(shù)據(jù)準(zhǔn)備好了
break;
case SerialPortEvent.RI: // 5 振鈴指示
break;
case SerialPortEvent.OUTPUT_BUFFER_EMPTY: // 2 輸出緩沖區(qū)已清空
break;
case SerialPortEvent.DATA_AVAILABLE: // 1 串口存在可用數(shù)據(jù)
String time=df.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis()),ZoneId.of("Asia/Shanghai")));
byte[] data;//FE0400030001D5C5
try {
data = SerialTool.readFromPort(serialPort);
receiveArea.append(time+" ["+serialPort.getName().split("/")[3]+"] : "+ printHexString(data)+"\r\n");
receiveArea.setCaretPosition(receiveArea.getText().length());
} catch (IOException e) {
e.printStackTrace();
}
break;
default:
break;
}
}
}
}
package serialPort;
import java.awt.Color;
import java.awt.Font;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
/**
* @author bh
* 如果運行過程中拋出 java.lang.UnsatisfiedLinkError 錯誤,
* 請將rxtx解壓包中的 rxtxParallel.dll,rxtxSerial.dll 這兩個文件復(fù)制到 C:\Windows\System32 目錄下即可解決該錯誤。
*/
public class WellcomView {
/** 程序界面寬度*/
public static final int WIDTH = 800;
/** 程序界面高度*/
public static final int HEIGHT = 620;
/** 程序界面出現(xiàn)位置(橫坐標(biāo)) */
public static final int LOC_X = 200;
/** 程序界面出現(xiàn)位置(縱坐標(biāo))*/
public static final int LOC_Y = 70;
private JFrame jFrame;
/**主方法
* @param args //
*/
public static void main(String[] args) {
new WellcomView();
}
public WellcomView() {
init();
listen();
}
/**
*/
private void listen() {
//添加鍵盤監(jiān)聽器
jFrame.addKeyListener(new KeyAdapter() {
public void keyReleased(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_ENTER) { //當(dāng)監(jiān)聽到用戶敲擊鍵盤enter鍵后執(zhí)行下面的操作
jFrame.setVisible(false); //隱去歡迎界面
new SerialView(); //主界面類(顯示監(jiān)控數(shù)據(jù)主面板)
}
}
});
}
/**
* 顯示主界面
*/
private void init() {
jFrame=new JFrame("串口調(diào)試");
jFrame.setBounds(LOC_X, LOC_Y, WIDTH, HEIGHT); //設(shè)定程序在桌面出現(xiàn)的位置
jFrame.setLayout(null);
//設(shè)置window的icon(這里我自定義了一下Windows窗口的icon圖標(biāo),因為實在覺得哪個小咖啡圖標(biāo)不好看 = =)
Toolkit toolKit = jFrame.getToolkit();
Image icon = toolKit.getImage(WellcomView.class.getResource("computer.png"));
jFrame.setIconImage(icon);
jFrame.setBackground(Color.white); //設(shè)置背景色
JLabel huanyin=new JLabel("歡迎使用串口調(diào)試工具");
huanyin.setBounds(170, 80,600,50);
huanyin.setFont(new Font("微軟雅黑", Font.BOLD, 40));
jFrame.add(huanyin);
JLabel banben=new JLabel("Version:1.0 Powered By:cyq");
banben.setBounds(180, 390,500,50);
banben.setFont(new Font("微軟雅黑", Font.ITALIC, 26));
jFrame.add(banben);
JLabel enter=new JLabel("————點擊Enter鍵進(jìn)入主界面————");
enter.setBounds(100, 480,600,50);
enter.setFont(new Font("微軟雅黑", Font.BOLD, 30));
jFrame.add(enter);
jFrame.setResizable(false); //窗口大小不可更改
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.setVisible(true); //顯示窗口
}
}
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
nacos客戶端一致性hash負(fù)載需求實現(xiàn)
這篇文章主要介紹了nacos客戶端一致性hash負(fù)載的需求實現(xiàn)過程及步驟詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-02-02
SpringMVC空指針異常NullPointerException解決及原理解析
這篇文章主要介紹了SpringMVC空指針異常NullPointerException解決及原理解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08
Spring?Boot如何接入Security權(quán)限認(rèn)證服務(wù)
Spring Security?是一個高度可定制的身份驗證和訪問控制的框架,提供了完善的認(rèn)證機制和方法級的授權(quán)功能,本文通過案例將Spring Security整合到SpringBoot中,要實現(xiàn)的功能就是在認(rèn)證服務(wù)器上登錄,然后獲取Token,再訪問資源服務(wù)器中的資源,感興趣的朋友一起看看吧2024-07-07
如何用Intellij idea2020打包jar的方法步驟
這篇文章主要介紹了如何用Intellij idea 2020打包jar的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04
java:程序包org.apache.ibatis.annotations不存在報錯解決
這篇文章主要給大家介紹了關(guān)于java:程序包org.apache.ibatis.annotations不存在報錯的解決方法,這個錯誤是我在直接導(dǎo)入springboot項目的時候報錯的,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-04-04

