使用Java实现串口通信

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

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

(0)

相关推荐

  • Java int与integer的对比区别

    Java int与 integer区别: int与integer的区别从大的方面来说就是基本数据类型与其包装类的区别: int 是基本类型,直接存数值,而integer是对象,用一个引用指向这个对象 1.Java 中的数据类型分为基本数据类型和复杂数据类型 int 是前者而integer 是后者(也就是一个类):因此在类进行初始化时int类的变量初始为0.而Integer的变量则初始化为null. 2.初始化时: int i =1:Integer i= new Integer(1);(要把int

  • javascript基础知识讲解

    本篇适合javascript新手或者学了前端一段时间,对js概念不清晰的同学~~. 学习目的 本文针对javascript基础薄弱的同学,可以加深对javascript的理解. 本文将讲述以下几点对于初学者开说javascript(有的是大部分语言都有的)的坑 讲解内容如下: 1. 连等 2. i++ 3. 包装对象 4. 引用类型 5. && 与 || 讲解部分 1. 连等 小试牛刀 连等是常见的表达式,但是并不是所有情况都适合连等,连等只适用于字面量并不适用于引用类型. // 字面量连

  • Java图片裁剪和生成缩略图的实例方法

    一.缩略图 在浏览相册的时候,可能需要生成相应的缩略图. 直接上代码: public class ImageUtil { private Logger log = LoggerFactory.getLogger(getClass()); private static String DEFAULT_PREVFIX = "thumb_"; private static Boolean DEFAULT_FORCE = false;//建议该值为false /** * <p>Tit

  • JavaScript BASE64算法实现(完美解决中文乱码)

    JavaScript 的 BASE64 算法 var BASE64={ enKey: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', deKey: new Array( -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -

  • 基于Java编写串口通信工具

    最近一门课要求编写一个上位机串口通信工具,我基于Java编写了一个带有图形界面的简单串口通信工具,下面详述一下过程,供大家参考 ^_^ 一: 首先,你需要下载一个额外的支持Java串口通信操作的jar包,由于java.comm比较老了,而且不支持64位系统,这里推荐Rxtx这个jar包(32位/64位均支持). 官方下载地址:http://fizzed.com/oss/rxtx-for-java (注:可能需要FQ才能下载) 不能FQ的童鞋,可以在这里下载: http://xiazai.jb51

  • java 串口通信详细及简单实例

    java 实现串口通信 最近做了一个与硬件相关的项目,刚开始听说用java和硬件打交道,着实下了一大跳.java也可以操作硬件? 后来接触到是用java通过串口通信控制硬件感觉使用起来还不错,也很方便. 特拿出来和大家一起分享一下. 准备工作: 首先到SUN官网下载一个zip包:javacomm20-win32.zip 其中重要的有这几个文件: win32com.dll comm.jar javax.comm.properties 按照说明配置好环境,如下: 将win32com.dll复制到<J

  • java 数据类型有哪些取值范围多少

    java 数据类型: 在Java中,数据类型分为两大种:基本数据类型(值类型)和包装类型(引用数据类型).基本数据类型不是对象,不能调用toString().hashCode().getClass().equals()等方法. 8种基本数据类型-----8种包装类型  整型: byte Byte [-128,127] 1个字节([-2的7次方,2的7次方-1]) 一个字节有8位 short Short [-32768,32767] 2个字节([-2的15次方,2的15次方-1]) 2*8-1 i

  • javascript常用经典算法详解

    阅读目录 冒泡排序 插入排序 希尔排序 归并排序 快速排序 选择排序 奇偶排序 总结 前言:在前端大全中看到这句话,以此共勉.基础决定你可能达到的高度, 而业务决定了你的最低瓶颈 其实javascript算法在平时的编码中用处不大,不过不妨碍我们学习它,学习一下这些算法的思想,锻炼一下自己的思维模式. 本文不会每种方法都介绍一下,只介绍一下七种,纯属为了学习而学习,如果觉得代码不是很好理解,可以将数组里面的内容代入函数里面. 不过刚开始理解的时候确实挺头疼的.废话少说,搞起来!! 冒泡排序 原理

  • 使用Java实现串口通信

    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_HO

  • Java实现的串口通信功能示例

    本文实例讲述了Java实现的串口通信功能.分享给大家供大家参考,具体如下: 用Java实现串口通信(windows系统下),需要用到sun提供的串口包 javacomm20-win32.zip.其中要用到三个文件,配置如下: 1.comm.jar放置到 JAVA_HOME/jre/lib/ext; 2.win32com.dll放置到 JAVA_HOME/bin; 3.javax.comm.properties 两个地方都要放     jre/lib(也就是在JAVA文件夹下的jre)    JA

  • 详细解读Java的串口编程

    常见问题 JavaComm 和 RxTX 安装时有一些与众不同的地方.强烈建议按照安装说明一点点的安装.如果安装说明要求一个jar文件或一个共享库必须在某一特定的文件夹下,那这就意味着需要严肃对待.如果说明要求一个特定的文件或设备需要拥有一个特定的所有权或访问权,这也意味着需要严肃处理.很多安装问题都只是因为没有按照安装说明要求的去做而引起的. 特别要注意的是一些版本的JavaComm会带有两个安装说明.一个用于java 1.2及以后的版本,一个用于java 1.1版本.使用错误的安装说明会导致

  • java 串口通信实现流程示例

    1.下载64位rxtx for java 链接:http://fizzed.com/oss/rxtx-for-java 2.下载下来的包解压后按照说明放到JAVA_HOME即JAVA的安装路径下面去 3.在maven的pom.xml下添加 <dependency> <groupId>org.rxtx</groupId> <artifactId>rxtx</artifactId> <version>2.1.7</version&g

  • java使用Rxtx实现串口通信调试工具

    本文实例为大家分享了java使用Rxtx实现串口通信调试工具的具体代码,供大家参考,具体内容如下 最终效果如下图: 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

  • 使用Java实现简单串口通信

    本博文参考自https://www.jb51.net/article/100269.htm www.jb51.net/article/100269.htm 没想到挺多人需要这个的,很高兴这篇文章能对大家有帮助,主要的工具类博文里已经有了,当然,要小工具源码的留言邮箱即可. 2019.09.05 最近接触到了串口及其读写,在此记录java进行串口读写的过程. 1.导入支持java串口通信的jar包: 在maven项目的pom.xml中添加RXTXcomm的依赖 或者 下载RXTXcomm.jar并

  • Android 串口通信编程及串口协议分析

    Android 串口通信编程:嵌入式编程和可穿戴设备及智能设备都会用到串口,这里就带大家分析下, 一,android串口通信 串口通信采用一个第三方开源项目,实现串口数据收发. 1. 使用了http://code.google.com/p/android-serialport-api/的项目的serialport api和jni: 2. 支持4串口同时收发,有定时自动发送功能,收发模式可选Txt或Hex模式: 3.  n,8,1,没得选: 4. 为减轻界面卡顿的情况,接收区的刷新采用单独的线程进

  • Android串口通信之串口读写实例

    在Android串口通信:基本知识梳理的基础上,我结合我项目中使用串口的实例,进行总结: Android使用jni直接进行串口设备的读写网上已经有开源项目了,本文是基于网上的开源项目在实际项目中的使用做的调整和优化: Google串口开源项目 下面是我项目中的相关代码及介绍: 1.SerialPort.cpp /* * Copyright 2009 Cedric Priscal * * Licensed under the Apache License, Version 2.0 (the "Li

随机推荐