/教程/编程/ 使用Java实现串口通信

使用Java实现串口通信

编程4332018-05-14

1.介绍

使用Java实现的串口通信程序,支持十六进制数据的发送与接收。
源码下载地址:http://download.csdn.net/detail/kong_gu_you_lan/9611343

效果图如下:

2.RXTXcomm

Java串口通信依赖的jar包RXTXcomm.jar
下载地址:http://download.csdn.net/detail/kong_gu_you_lan/9611334

内含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实现了对串口通信的管理,包括查找可用端口、打开关闭串口、发送接收数据。

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, 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();
  // 检查是否有可用串口,有则加入选项中
  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("串口已打开" + "\r\n");
     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("串口已关闭" + "\r\n");
  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) + "\r\n");
     }
    } 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

欢迎同学们吐槽评论,如果你觉得本篇博客对你有用,那么就留个言或者顶一下吧(^-^)

感谢:http://www.jb51.net/article/100269.htm

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持淘代码。

标签: Java 

有什么新鲜事想告诉大家?

发表