使用Java实现串口通信
1.介绍 使用Java实现的串口通信程序,支持十六进制数据的发送与接收。 效果图如下: 2.RXTXcomm Java串口通信依赖的jar包RXTXcomm.jar 内含32位与64位版本 3.串口通信管理 SerialPortManager实现了对串口通信的管理,包括查找可用端口、打开关闭串口、发送接收数据。 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() { // 获得当前所有可用串口 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 * 设置串口参数失败 * @throws NotASerialPort * 端口指向设备不是串口类型 * @throws NoSuchPort * 没有该端口对应的串口设备 * @throws PortInUse * 端口已被占用 */ public static final SerialPort openPort(String portName,int baudrate) throws SerialPortParameterFailure,NotASerialPort,NoSuchPort,PortInUse { 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 SerialPortParameterFailure(); } return serialPort; } else { // 不是串口 throw new NotASerialPort(); } } catch (NoSuchPortException e1) { throw new NoSuchPort(); } catch (PortInUseException e2) { throw new PortInUse(); } } /** * 关闭串口 * * @param serialport * 待关闭的串口对象 */ public static void closePort(SerialPort serialPort) { if (serialPort != null) { serialPort.close(); serialPort = null; } } /** * 向串口发送数据 * * @param serialPort * 串口对象 * @param order * 待发送数据 * @throws SendDataToSerialPortFailure * 向串口发送数据失败 * @throws SerialPortOutputStreamCloseFailure * 关闭串口对象的输出流出错 */ 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(); } } } /** * 从串口读取数据 * * @param serialPort * 当前已建立连接的SerialPort对象 * @return 读取到的数据 * @throws ReadDataFromSerialPortFailure * 从串口读取数据时出错 * @throws SerialPortInputStreamCloseFailure * 关闭串口对象输入流出错 */ public static byte[] readFromPort(SerialPort serialPort) throws ReadDataFromSerialPortFailure,SerialPortInputStreamCloseFailure { InputStream in = null; byte[] bytes = null; 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) { throw new ReadDataFromSerialPortFailure(); } finally { try { if (in != null) { in.close(); in = null; } } catch (IOException e) { throw new SerialPortInputStreamCloseFailure(); } } return bytes; } /** * 添加监听器 * * @param port * 串口对象 * @param listener * 串口监听器 * @throws TooManyListeners * 监听类对象过多 */ public static void addListener(SerialPort port,SerialPortEventListener listener) throws TooManyListeners { try { // 给串口添加监听器 port.addEventListener(listener); // 设置当有数据到达时唤醒监听接收线程 port.notifyOnDataAvailable(true); // 设置当通信中断时唤醒中断线程 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); // 串口设置面板 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("发送数据"); private List<String> commList = null; private SerialPort serialport; public MainFrame() { initView(); initComponents(); actionListener(); initData(); } private void initView() { // 关闭程序 setDefaultCloSEOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); // 禁止窗口最大化 setResizable(false); // 设置程序窗口居中显示 Point p = GraphicsEnvironment.getLocalGraphicsEnvironment() .getCenterPoint(); setBounds(p.x - WIDTH / 2,p.y - HEIGHT / 2,WIDTH,HEIGHT); this.setLayout(null); setTitle("串口通讯"); } private void initComponents() { // 数据显示 dataView.setFocusable(false); scrollDataView.setBounds(10,10,475,200); add(scrollDataView); // 串口设置 serialPortPanel.setBorder(BorderFactory.createTitledBorder("串口设置")); 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,100,20); serialPortPanel.add(commChoice); baudrateLabel.setForeground(Color.gray); baudrateLabel.setBounds(10,60,20); serialPortPanel.add(baudrateLabel); baudrateChoice.setFocusable(false); baudrateChoice.setBounds(60,20); serialPortPanel.add(baudrateChoice); // 操作 operatePanel.setBorder(BorderFactory.createTitledBorder("操作")); operatePanel.setBounds(200,285,100); operatePanel.setLayout(null); add(operatePanel); dataInput.setBounds(25,235,20); operatePanel.add(dataInput); serialPortOperate.setFocusable(false); serialPortOperate.setBounds(45,90,20); operatePanel.add(serialPortOperate); sendData.setFocusable(false); sendData.setBounds(155,20); operatePanel.add(sendData); } @SuppressWarnings("unchecked") private void initData() { commList = SerialPortManager.findPort(); // 检查是否有可用串口,有则加入选项中 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 * 点击事件 */ 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("串口已打开" + "rn"); serialPortOperate.setText("关闭串口"); } } 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(); } } /** * 关闭串口 * * @param evt * 点击事件 */ private void closeSerialPort(java.awt.event.ActionEvent evt) { SerialPortManager.closePort(serialport); dataView.setText("串口已关闭" + "rn"); serialPortOperate.setText("打开串口"); } /** * 发送数据 * * @param evt * 点击事件 */ private void sendData(java.awt.event.ActionEvent evt) { // 输入框直接输入十六进制字符,长度必须是偶数 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 { /** * 处理监控到的串口事件 */ public void serialEvent(SerialPortEvent serialPortEvent) { switch (serialPortEvent.getEventType()) { case SerialPortEvent.BI: // 10 通讯中断 ShowUtils.errorMessage("与串口设备通讯中断"); break; case SerialPortEvent.OE: // 7 溢位(溢出)错误 case SerialPortEvent.FE: // 9 帧错误 case SerialPortEvent.PE: // 8 奇偶校验错误 case SerialPortEvent.CD: // 6 载波检测 case SerialPortEvent.CTS: // 3 清除待发送数据 case SerialPortEvent.DSR: // 4 待发送数据准备好了 case SerialPortEvent.RI: // 5 振铃指示 case SerialPortEvent.OUTPUT_BUFFER_EMPTY: // 2 输出缓冲区已清空 break; case SerialPortEvent.DATA_AVAILABLE: // 1 串口存在可用数据 byte[] data = null; try { if (serialport == null) { ShowUtils.errorMessage("串口对象为空!监听失败!"); } else { // 读取串口数据 data = SerialPortManager.readFromPort(serialport); dataView.append(ByteUtils.byteArrayToHexString(data,true) + "rn"); } } catch (Exception e) { ShowUtils.errorMessage(e.toString()); // 发生读取错误时显示错误信息后退出系统 System.exit(0); } break; } } } public static void main(String args[]) { java.awt.EventQueue.invokeLater(new Runnable() { public void run() { new MainFrame().setVisible(true); } }); } } 5.写在最后 源码下载地址:http://download.csdn.net/detail/kong_gu_you_lan/9611343 欢迎同学们吐槽评论,如果你觉得本篇博客对你有用,那么就留个言或者顶一下吧(^-^) 感谢:https://www.oudahe.com/p/12047/ 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- 结对编程(Java实现)
- 【异常】Phoenix异常:java.lang.ArithmeticException: Roun
- java – 使用JTextField – 无法将值转换为int
- Java实现文件的归档和解档
- java – Android SlidingUpPanelLayout上滑事件
- HashMap、Hashtable
- java – 使用lambda保持线程安全
- Flyweight Design Pattern
- java.lang.IllegalArgumentException:未知参数名称:custo
- java – PropertyModel Expression的异常:org.apache.wick