使用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)了對(duì)串口通信的管理,包括查找可用端口、打開(kāi)關(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; } /** * 打開(kāi)串口 * * @param portName * 端口名稱 * @param baudrate * 波特率 * @return 串口對(duì)象 * @throws SerialPortParameterFailure * 設(shè)置串口參數(shù)失敗 * @throws NotASerialPort * 端口指向設(shè)備不是串口類型 * @throws NoSuchPort * 沒(méi)有該端口對(duì)應(yīng)的串口設(shè)備 * @throws PortInUse * 端口已被占用 */ public static final SerialPort openPort(String portName, int baudrate) throws SerialPortParameterFailure, NotASerialPort, NoSuchPort, PortInUse { try { // 通過(guò)端口名識(shí)別端口 CommPortIdentifier portIdentifier = CommPortIdentifier .getPortIdentifier(portName); // 打開(kāi)端口,設(shè)置端口名與timeout(打開(kāi)操作的超時(shí)時(shí)間) 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)閉的串口對(duì)象 */ public static void closePort(SerialPort serialPort) { if (serialPort != null) { serialPort.close(); serialPort = null; } } /** * 向串口發(fā)送數(shù)據(jù) * * @param serialPort * 串口對(duì)象 * @param order * 待發(fā)送數(shù)據(jù) * @throws SendDataToSerialPortFailure * 向串口發(fā)送數(shù)據(jù)失敗 * @throws SerialPortOutputStreamCloseFailure * 關(guān)閉串口對(duì)象的輸出流出錯(cuò) */ 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對(duì)象 * @return 讀取到的數(shù)據(jù) * @throws ReadDataFromSerialPortFailure * 從串口讀取數(shù)據(jù)時(shí)出錯(cuò) * @throws SerialPortInputStreamCloseFailure * 關(guān)閉串口對(duì)象輸入流出錯(cuò) */ public static byte[] readFromPort(SerialPort serialPort) throws ReadDataFromSerialPortFailure, SerialPortInputStreamCloseFailure { InputStream in = null; byte[] bytes = null; try { in = serialPort.getInputStream(); // 獲取buffer里的數(shù)據(jù)長(zhǎng)度 int bufflenth = in.available(); while (bufflenth != 0) { // 初始化byte數(shù)組為buffer中數(shù)據(jù)的長(zhǎng)度 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)聽(tīng)器 * * @param port * 串口對(duì)象 * @param listener * 串口監(jiān)聽(tīng)器 * @throws TooManyListeners * 監(jiān)聽(tīng)類對(duì)象過(guò)多 */ public static void addListener(SerialPort port, SerialPortEventListener listener) throws TooManyListeners { try { // 給串口添加監(jiān)聽(tīng)器 port.addEventListener(listener); // 設(shè)置當(dāng)有數(shù)據(jù)到達(dá)時(shí)喚醒監(jiān)聽(tīng)接收線程 port.notifyOnDataAvailable(true); // 設(shè)置當(dāng)通信中斷時(shí)喚醒中斷線程 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("打開(kāi)串口"); 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("沒(méi)有搜索到有效串口!"); } 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 ("打開(kāi)串口".equals(serialPortOperate.getText()) && serialport == null) { openSerialPort(e); } else { closeSerialPort(e); } } }); sendData.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { sendData(e); } }); } /** * 打開(kāi)串口 * * @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("沒(méi)有搜索到有效串口!"); } else { try { serialport = SerialPortManager.openPort(commName, baudrate); if (serialport != null) { dataView.setText("串口已打開(kāi)" + "\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("打開(kāi)串口"); } /** * 發(fā)送數(shù)據(jù) * * @param evt * 點(diǎn)擊事件 */ private void sendData(java.awt.event.ActionEvent evt) { // 輸入框直接輸入十六進(jìn)制字符,長(zhǎng)度必須是偶數(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 溢位(溢出)錯(cuò)誤 case SerialPortEvent.FE: // 9 幀錯(cuò)誤 case SerialPortEvent.PE: // 8 奇偶校驗(yàn)錯(cuò)誤 case SerialPortEvent.CD: // 6 載波檢測(cè) 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("串口對(duì)象為空!監(jiān)聽(tīng)失??!"); } else { // 讀取串口數(shù)據(jù) data = SerialPortManager.readFromPort(serialport); dataView.append(ByteUtils.byteArrayToHexString(data, true) + "\r\n"); } } catch (Exception e) { ShowUtils.errorMessage(e.toString()); // 發(fā)生讀取錯(cuò)誤時(shí)顯示錯(cuò)誤信息后退出系統(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.寫(xiě)在最后
源碼下載地址:SerialPortDemo
歡迎同學(xué)們吐槽評(píng)論,如果你覺(jué)得本篇博客對(duì)你有用,那么就留個(gè)言或者頂一下吧(^-^)
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot實(shí)現(xiàn)物品點(diǎn)贊功能
這篇文章主要介紹了SpringBoot物品點(diǎn)贊功能實(shí)現(xiàn),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04java如何使用fastjson修改多層嵌套的Objectjson數(shù)據(jù)
這篇文章主要介紹了java如何使用fastjson修改多層嵌套的Objectjson數(shù)據(jù)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-05-05Java驗(yàn)證日期時(shí)間字符串是否合法的三種方式
判斷日期經(jīng)常合法出現(xiàn)在IO場(chǎng)景下,下面將盡量使用簡(jiǎn)練的思路和代碼呈現(xiàn)給大伙,這篇文章主要給大家介紹了關(guān)于Java驗(yàn)證日期時(shí)間字符串是否合法的三種方式,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-11-11完美解決springboot中使用mybatis字段不能進(jìn)行自動(dòng)映射的問(wèn)題
今天在springboot中使用mybatis的時(shí)候不能字段不能夠進(jìn)行自動(dòng)映射,接下來(lái)給大家給帶來(lái)了完美解決springboot中使用mybatis字段不能進(jìn)行自動(dòng)映射的問(wèn)題,需要的朋友可以參考下2023-05-05Android應(yīng)用開(kāi)發(fā)之將SQLite和APK一起打包的方法
這篇文章主要介紹了Android應(yīng)用開(kāi)發(fā)之將SQLite和APK一起打包的方法,文章時(shí)間較早,盡管現(xiàn)在開(kāi)發(fā)環(huán)境已大都遷移至Android Studio上,但打包原理依然相同,需要的朋友可以參考下2015-08-08Java微信掃碼登錄功能并實(shí)現(xiàn)認(rèn)證授權(quán)全過(guò)程
這篇文章主要給大家介紹了關(guān)于Java微信掃碼登錄功能并實(shí)現(xiàn)認(rèn)證授權(quán)的相關(guān)資料,要在Java中實(shí)現(xiàn)微信掃碼登錄,您可以按照以下步驟進(jìn)行操作,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-10-10詳解Spring的兩種代理方式:JDK動(dòng)態(tài)代理和CGLIB動(dòng)態(tài)代理
這篇文章主要介紹了詳解Spring的兩種代理方式:JDK動(dòng)態(tài)代理和CGLIB動(dòng)態(tài)代理,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-04-04解決@Autowired報(bào)錯(cuò)Could not autowire. No bea
介紹了在IDEA中使用@Autowired報(bào)錯(cuò)Couldnot autowire. No beans of 'XXX' type found的解決方法,原因是@Autowired在注入service時(shí),由于service接口沒(méi)有實(shí)現(xiàn)類,而mybatis僅需提供Dao接口,導(dǎo)致@Autowired無(wú)法識(shí)別2024-12-12