使用Java實(shí)現(xiàn)串口通信
本文實(shí)例為大家分享了Java實(shí)現(xiàn)串口通信的具體代碼,供大家參考,具體內(nèi)容如下
1.介紹
使用Java實(shí)現(xiàn)的串口通信程序,支持十六進(jìn)制數(shù)據(jù)的發(fā)送與接收。
源碼:SerialPortDemo
效果圖如下:

2.RXTXcomm
Java串口通信依賴的jar包RXTXcomm.jar
下載地址:http://download.csdn.net/detail/kong_gu_you_lan/9611334
內(nèi)含32位與64位版本
使用方法:
拷貝 RXTXcomm.jar 到 JAVA_HOME\jre\lib\ext目錄中;
拷貝 rxtxSerial.dll 到 JAVA_HOME\jre\bin目錄中;
拷貝 rxtxParallel.dll 到 JAVA_HOME\jre\bin目錄中;
JAVA_HOME為jdk安裝路徑
3.串口通信管理
SerialPortManager實(shí)現(xiàn)了對串口通信的管理,包括查找可用端口、打開關(guān)閉串口、發(fā)送接收數(shù)據(jù)。
package com.yang.serialport.manage;
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;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.TooManyListenersException;
import com.yang.serialport.exception.NoSuchPort;
import com.yang.serialport.exception.NotASerialPort;
import com.yang.serialport.exception.PortInUse;
import com.yang.serialport.exception.ReadDataFromSerialPortFailure;
import com.yang.serialport.exception.SendDataToSerialPortFailure;
import com.yang.serialport.exception.SerialPortInputStreamCloseFailure;
import com.yang.serialport.exception.SerialPortOutputStreamCloseFailure;
import com.yang.serialport.exception.SerialPortParameterFailure;
import com.yang.serialport.exception.TooManyListeners;
/**
* 串口管理
*
* @author yangle
*/
public class SerialPortManager {
/**
* 查找所有可用端口
*
* @return 可用端口名稱列表
*/
@SuppressWarnings("unchecked")
public static final ArrayList<String> findPort() {
// 獲得當(dāng)前所有可用串口
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 串口對象
* @throws SerialPortParameterFailure
* 設(shè)置串口參數(shù)失敗
* @throws NotASerialPort
* 端口指向設(shè)備不是串口類型
* @throws NoSuchPort
* 沒有該端口對應(yīng)的串口設(shè)備
* @throws PortInUse
* 端口已被占用
*/
public static final SerialPort openPort(String portName, int baudrate)
throws SerialPortParameterFailure, NotASerialPort, NoSuchPort,
PortInUse {
try {
// 通過端口名識別端口
CommPortIdentifier portIdentifier = CommPortIdentifier
.getPortIdentifier(portName);
// 打開端口,設(shè)置端口名與timeout(打開操作的超時時間)
CommPort commPort = portIdentifier.open(portName, 2000);
// 判斷是不是串口
if (commPort instanceof SerialPort) {
SerialPort serialPort = (SerialPort) commPort;
try {
// 設(shè)置串口的波特率等參數(shù)
serialPort.setSerialPortParams(baudrate,
SerialPort.DATABITS_8, SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
} catch (UnsupportedCommOperationException e) {
throw new SerialPortParameterFailure();
}
return serialPort;
} else {
// 不是串口
throw new NotASerialPort();
}
} catch (NoSuchPortException e1) {
throw new NoSuchPort();
} catch (PortInUseException e2) {
throw new PortInUse();
}
}
/**
* 關(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 SendDataToSerialPortFailure
* 向串口發(fā)送數(shù)據(jù)失敗
* @throws SerialPortOutputStreamCloseFailure
* 關(guān)閉串口對象的輸出流出錯
*/
public static void sendToPort(SerialPort serialPort, byte[] order)
throws SendDataToSerialPortFailure,
SerialPortOutputStreamCloseFailure {
OutputStream out = null;
try {
out = serialPort.getOutputStream();
out.write(order);
out.flush();
} catch (IOException e) {
throw new SendDataToSerialPortFailure();
} finally {
try {
if (out != null) {
out.close();
out = null;
}
} catch (IOException e) {
throw new SerialPortOutputStreamCloseFailure();
}
}
}
/**
* 從串口讀取數(shù)據(jù)
*
* @param serialPort
* 當(dāng)前已建立連接的SerialPort對象
* @return 讀取到的數(shù)據(jù)
* @throws ReadDataFromSerialPortFailure
* 從串口讀取數(shù)據(jù)時出錯
* @throws SerialPortInputStreamCloseFailure
* 關(guān)閉串口對象輸入流出錯
*/
public static byte[] readFromPort(SerialPort serialPort)
throws ReadDataFromSerialPortFailure,
SerialPortInputStreamCloseFailure {
InputStream in = null;
byte[] bytes = null;
try {
in = serialPort.getInputStream();
// 獲取buffer里的數(shù)據(jù)長度
int bufflenth = in.available();
while (bufflenth != 0) {
// 初始化byte數(shù)組為buffer中數(shù)據(jù)的長度
bytes = new byte[bufflenth];
in.read(bytes);
bufflenth = in.available();
}
} catch (IOException e) {
throw new ReadDataFromSerialPortFailure();
} finally {
try {
if (in != null) {
in.close();
in = null;
}
} catch (IOException e) {
throw new SerialPortInputStreamCloseFailure();
}
}
return bytes;
}
/**
* 添加監(jiān)聽器
*
* @param port
* 串口對象
* @param listener
* 串口監(jiān)聽器
* @throws TooManyListeners
* 監(jiān)聽類對象過多
*/
public static void addListener(SerialPort port,
SerialPortEventListener listener) throws TooManyListeners {
try {
// 給串口添加監(jiān)聽器
port.addEventListener(listener);
// 設(shè)置當(dāng)有數(shù)據(jù)到達(dá)時喚醒監(jiān)聽接收線程
port.notifyOnDataAvailable(true);
// 設(shè)置當(dāng)通信中斷時喚醒中斷線程
port.notifyOnBreakInterrupt(true);
} catch (TooManyListenersException e) {
throw new TooManyListeners();
}
}
}
4.程序主窗口
/*
* MainFrame.java
*
* Created on 2016.8.19
*/
package com.yang.serialport.ui;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import java.awt.Color;
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import com.yang.serialport.exception.NoSuchPort;
import com.yang.serialport.exception.NotASerialPort;
import com.yang.serialport.exception.PortInUse;
import com.yang.serialport.exception.SendDataToSerialPortFailure;
import com.yang.serialport.exception.SerialPortOutputStreamCloseFailure;
import com.yang.serialport.exception.SerialPortParameterFailure;
import com.yang.serialport.exception.TooManyListeners;
import com.yang.serialport.manage.SerialPortManager;
import com.yang.serialport.utils.ByteUtils;
import com.yang.serialport.utils.ShowUtils;
/**
* 主界面
*
* @author yangle
*/
public class MainFrame extends JFrame {
/**
* 程序界面寬度
*/
public static final int WIDTH = 500;
/**
* 程序界面高度
*/
public static final int HEIGHT = 360;
private JTextArea dataView = new JTextArea();
private JScrollPane scrollDataView = new JScrollPane(dataView);
// 串口設(shè)置面板
private JPanel serialPortPanel = new JPanel();
private JLabel serialPortLabel = new JLabel("串口");
private JLabel baudrateLabel = new JLabel("波特率");
private JComboBox commChoice = new JComboBox();
private JComboBox baudrateChoice = new JComboBox();
// 操作面板
private JPanel operatePanel = new JPanel();
private JTextField dataInput = new JTextField();
private JButton serialPortOperate = new JButton("打開串口");
private JButton sendData = new JButton("發(fā)送數(shù)據(jù)");
private List<String> commList = null;
private SerialPort serialport;
public MainFrame() {
initView();
initComponents();
actionListener();
initData();
}
private void initView() {
// 關(guān)閉程序
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
// 禁止窗口最大化
setResizable(false);
// 設(shè)置程序窗口居中顯示
Point p = GraphicsEnvironment.getLocalGraphicsEnvironment()
.getCenterPoint();
setBounds(p.x - WIDTH / 2, p.y - HEIGHT / 2, WIDTH, HEIGHT);
this.setLayout(null);
setTitle("串口通訊");
}
private void initComponents() {
// 數(shù)據(jù)顯示
dataView.setFocusable(false);
scrollDataView.setBounds(10, 10, 475, 200);
add(scrollDataView);
// 串口設(shè)置
serialPortPanel.setBorder(BorderFactory.createTitledBorder("串口設(shè)置"));
serialPortPanel.setBounds(10, 220, 170, 100);
serialPortPanel.setLayout(null);
add(serialPortPanel);
serialPortLabel.setForeground(Color.gray);
serialPortLabel.setBounds(10, 25, 40, 20);
serialPortPanel.add(serialPortLabel);
commChoice.setFocusable(false);
commChoice.setBounds(60, 25, 100, 20);
serialPortPanel.add(commChoice);
baudrateLabel.setForeground(Color.gray);
baudrateLabel.setBounds(10, 60, 40, 20);
serialPortPanel.add(baudrateLabel);
baudrateChoice.setFocusable(false);
baudrateChoice.setBounds(60, 60, 100, 20);
serialPortPanel.add(baudrateChoice);
// 操作
operatePanel.setBorder(BorderFactory.createTitledBorder("操作"));
operatePanel.setBounds(200, 220, 285, 100);
operatePanel.setLayout(null);
add(operatePanel);
dataInput.setBounds(25, 25, 235, 20);
operatePanel.add(dataInput);
serialPortOperate.setFocusable(false);
serialPortOperate.setBounds(45, 60, 90, 20);
operatePanel.add(serialPortOperate);
sendData.setFocusable(false);
sendData.setBounds(155, 60, 90, 20);
operatePanel.add(sendData);
}
@SuppressWarnings("unchecked")
private void initData() {
commList = SerialPortManager.findPort();
// 檢查是否有可用串口,有則加入選項(xiàng)中
if (commList == null || commList.size() < 1) {
ShowUtils.warningMessage("沒有搜索到有效串口!");
} else {
for (String s : commList) {
commChoice.addItem(s);
}
}
baudrateChoice.addItem("9600");
baudrateChoice.addItem("19200");
baudrateChoice.addItem("38400");
baudrateChoice.addItem("57600");
baudrateChoice.addItem("115200");
}
private void actionListener() {
serialPortOperate.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if ("打開串口".equals(serialPortOperate.getText())
&& serialport == null) {
openSerialPort(e);
} else {
closeSerialPort(e);
}
}
});
sendData.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
sendData(e);
}
});
}
/**
* 打開串口
*
* @param evt
* 點(diǎn)擊事件
*/
private void openSerialPort(java.awt.event.ActionEvent evt) {
// 獲取串口名稱
String commName = (String) commChoice.getSelectedItem();
// 獲取波特率
int baudrate = 9600;
String bps = (String) baudrateChoice.getSelectedItem();
baudrate = Integer.parseInt(bps);
// 檢查串口名稱是否獲取正確
if (commName == null || commName.equals("")) {
ShowUtils.warningMessage("沒有搜索到有效串口!");
} else {
try {
serialport = SerialPortManager.openPort(commName, baudrate);
if (serialport != null) {
dataView.setText("串口已打開" + "\r\n");
serialPortOperate.setText("關(guān)閉串口");
}
} catch (SerialPortParameterFailure e) {
e.printStackTrace();
} catch (NotASerialPort e) {
e.printStackTrace();
} catch (NoSuchPort e) {
e.printStackTrace();
} catch (PortInUse e) {
e.printStackTrace();
ShowUtils.warningMessage("串口已被占用!");
}
}
try {
SerialPortManager.addListener(serialport, new SerialListener());
} catch (TooManyListeners e) {
e.printStackTrace();
}
}
/**
* 關(guān)閉串口
*
* @param evt
* 點(diǎn)擊事件
*/
private void closeSerialPort(java.awt.event.ActionEvent evt) {
SerialPortManager.closePort(serialport);
dataView.setText("串口已關(guān)閉" + "\r\n");
serialPortOperate.setText("打開串口");
}
/**
* 發(fā)送數(shù)據(jù)
*
* @param evt
* 點(diǎn)擊事件
*/
private void sendData(java.awt.event.ActionEvent evt) {
// 輸入框直接輸入十六進(jìn)制字符,長度必須是偶數(shù)
String data = dataInput.getText().toString();
try {
SerialPortManager.sendToPort(serialport,
ByteUtils.hexStr2Byte(data));
} catch (SendDataToSerialPortFailure e) {
e.printStackTrace();
} catch (SerialPortOutputStreamCloseFailure e) {
e.printStackTrace();
}
}
private class SerialListener implements SerialPortEventListener {
/**
* 處理監(jiān)控到的串口事件
*/
public void serialEvent(SerialPortEvent serialPortEvent) {
switch (serialPortEvent.getEventType()) {
case SerialPortEvent.BI: // 10 通訊中斷
ShowUtils.errorMessage("與串口設(shè)備通訊中斷");
break;
case SerialPortEvent.OE: // 7 溢位(溢出)錯誤
case SerialPortEvent.FE: // 9 幀錯誤
case SerialPortEvent.PE: // 8 奇偶校驗(yàn)錯誤
case SerialPortEvent.CD: // 6 載波檢測
case SerialPortEvent.CTS: // 3 清除待發(fā)送數(shù)據(jù)
case SerialPortEvent.DSR: // 4 待發(fā)送數(shù)據(jù)準(zhǔn)備好了
case SerialPortEvent.RI: // 5 振鈴指示
case SerialPortEvent.OUTPUT_BUFFER_EMPTY: // 2 輸出緩沖區(qū)已清空
break;
case SerialPortEvent.DATA_AVAILABLE: // 1 串口存在可用數(shù)據(jù)
byte[] data = null;
try {
if (serialport == null) {
ShowUtils.errorMessage("串口對象為空!監(jiān)聽失?。?);
} else {
// 讀取串口數(shù)據(jù)
data = SerialPortManager.readFromPort(serialport);
dataView.append(ByteUtils.byteArrayToHexString(data,
true) + "\r\n");
}
} catch (Exception e) {
ShowUtils.errorMessage(e.toString());
// 發(fā)生讀取錯誤時顯示錯誤信息后退出系統(tǒng)
System.exit(0);
}
break;
}
}
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new MainFrame().setVisible(true);
}
});
}
}
5.寫在最后
源碼下載地址:SerialPortDemo
歡迎同學(xué)們吐槽評論,如果你覺得本篇博客對你有用,那么就留個言或者頂一下吧(^-^)
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot實(shí)現(xiàn)物品點(diǎn)贊功能
這篇文章主要介紹了SpringBoot物品點(diǎn)贊功能實(shí)現(xiàn),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-04-04
java如何使用fastjson修改多層嵌套的Objectjson數(shù)據(jù)
這篇文章主要介紹了java如何使用fastjson修改多層嵌套的Objectjson數(shù)據(jù)問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-05-05
完美解決springboot中使用mybatis字段不能進(jìn)行自動映射的問題
今天在springboot中使用mybatis的時候不能字段不能夠進(jìn)行自動映射,接下來給大家給帶來了完美解決springboot中使用mybatis字段不能進(jìn)行自動映射的問題,需要的朋友可以參考下2023-05-05
Android應(yīng)用開發(fā)之將SQLite和APK一起打包的方法
這篇文章主要介紹了Android應(yīng)用開發(fā)之將SQLite和APK一起打包的方法,文章時間較早,盡管現(xiàn)在開發(fā)環(huán)境已大都遷移至Android Studio上,但打包原理依然相同,需要的朋友可以參考下2015-08-08
Java微信掃碼登錄功能并實(shí)現(xiàn)認(rèn)證授權(quán)全過程
這篇文章主要給大家介紹了關(guān)于Java微信掃碼登錄功能并實(shí)現(xiàn)認(rèn)證授權(quán)的相關(guān)資料,要在Java中實(shí)現(xiàn)微信掃碼登錄,您可以按照以下步驟進(jìn)行操作,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-10-10
詳解Spring的兩種代理方式:JDK動態(tài)代理和CGLIB動態(tài)代理
這篇文章主要介紹了詳解Spring的兩種代理方式:JDK動態(tài)代理和CGLIB動態(tài)代理,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-04-04
解決@Autowired報錯Could not autowire. No bea
介紹了在IDEA中使用@Autowired報錯Couldnot autowire. No beans of 'XXX' type found的解決方法,原因是@Autowired在注入service時,由于service接口沒有實(shí)現(xiàn)類,而mybatis僅需提供Dao接口,導(dǎo)致@Autowired無法識別2024-12-12

