java串口通信demo

这篇我将自己的源码放上来供大家参考。
准备工作1:
下载Virtual Serial Port Driver ,我用的是7.2版本,打开如图


image.png
image.png

这里我已经创建好虚拟端口COM1和COM2了,就不在新建端口了

准备工作2:

下载rxtx框架,http://fizzed.com/oss/rxtx-for-java

image.png

下载下来是可用的是一个jar包和两个dll


image.png

注意dll要放到jre的bin目录下,rxtx除了要引入工程中,还要放在jdk/jre/lib/ext文件夹一份,详情去看rxtx正确的使用方式

3.串口调试助手
我用的是友善串口调试助手,网上应该很好下,打开即用,界面如下。串口调试助手用来验证你的发送和接收数据是否成功。


image.png

做好这些,准备工作就完成啦,我们开始建工程。
下图是工程目录,别被这么多源文件吓到了,大部分是自定义异常(我要知道连不上串口或者发不出信息或者接收不到信息的原因在哪),真正有用的类是SerialTool.java(工具类)和client.java(测试类)


image.png

下面上源码,首先是工具类:

package 测试串口;
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 gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.NoSuchPortException;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import gnu.io.UnsupportedCommOperationException;
public class SerialTool {

     /**
     * 查找所有可用端口
     * @return 可用端口名称列表
     */
     public static final ArrayList findPort() {
     
     //获得当前所有可用串口
     @SuppressWarnings("unchecked")
    Enumeration portList = CommPortIdentifier.getPortIdentifiers(); 
     ArrayList portNameList = new ArrayList(); 
     //将可用串口名添加到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);    
       /*serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);*/
      } catch (UnsupportedCommOperationException e) { 
       throw new SerialPortParameterFailure();
      }
       
      System.out.println("Open " + portName + " successfully !");
      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();
      System.out.println("写入成功");
       
     } 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();
      int bufflenth = in.available(); //获取buffer里的数据长度
       
      while (bufflenth != 0) {    
      bytes = new byte[bufflenth]; //初始化byte数组为buffer中数据的长度
      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();
      }
     
     }
     System.out.println("读取成功");
     return bytes;
     
     }
      
     /**
     * 添加监听器
     * @param port 串口对象
     * @param listener 串口监听器
     * @throws TooManyListeners 监听类对象过多
     */
     public static void addListener(SerialPort port, DataAvailableListener listener) throws TooManyListeners {
     
     try {
       
      //给串口添加监听器
      port.addEventListener(new SerialPortListener(listener));
      //设置当有数据到达时唤醒监听接收线程
      port.notifyOnDataAvailable(true);
      //设置当通信中断时唤醒中断线程
      port.notifyOnBreakInterrupt(true);
     
     } catch (TooManyListenersException e) {
      throw new TooManyListeners();
     }
     }
     /**
         * 串口监听
         */
        public static class SerialPortListener implements SerialPortEventListener {

            private DataAvailableListener mDataAvailableListener;

            public SerialPortListener(DataAvailableListener mDataAvailableListener) {
                this.mDataAvailableListener = mDataAvailableListener;
            }

            public void serialEvent(SerialPortEvent serialPortEvent) {
                switch (serialPortEvent.getEventType()) {
                case SerialPortEvent.DATA_AVAILABLE: // 1.串口存在有效数据
                    if (mDataAvailableListener != null) {
                        mDataAvailableListener.dataAvailable();
                    }
                    break;

                case SerialPortEvent.OUTPUT_BUFFER_EMPTY: // 2.输出缓冲区已清空
                    break;

                case SerialPortEvent.CTS: // 3.清除待发送数据
                    break;

                case SerialPortEvent.DSR: // 4.待发送数据准备好了
                    break;

                case SerialPortEvent.RI: // 5.振铃指示
                    break;

                case SerialPortEvent.CD: // 6.载波检测
                    break;

                case SerialPortEvent.OE: // 7.溢位(溢出)错误
                    break;

                case SerialPortEvent.PE: // 8.奇偶校验错误
                    break;

                case SerialPortEvent.FE: // 9.帧错误
                    break;

                case SerialPortEvent.BI: // 10.通讯中断
                    System.out.println("与串口设备通讯中断");
                    break;

                default:
                    break;
                }
            }
        }

        /**
         * 串口存在有效数据监听
         */
        public interface DataAvailableListener {
            /**
             * 串口存在有效数据
             */
            void dataAvailable();
        }
      
      
    }

自定义异常贴两个就行了,其他异常你们仿写下,异常类的名字都在工具类里。
不匹配异常

package 测试串口;

public class NoSuchPort extends Exception {
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    @Override
     public String toString() {
     return "没有该端口对应的串口设备!";
     }
}

串口设置异常

package 测试串口;

public class SerialPortParameterFailure extends Exception {
     /**
     * 
     */
     private static final long serialVersionUID = 1L;
     
     public SerialPortParameterFailure() {}
     
     @Override
     public String toString() {
     return "设置串口参数失败!打开串口操作未完成!";
     }
}

最后贴下测试类和运行结果

package 测试串口;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Locale;
import gnu.io.SerialPort;

public class client {
    
    public static void main(String[] args) throws SerialPortParameterFailure, NotASerialPort, NoSuchPort, PortInUse, SendDataToSerialPortFailure, SerialPortOutputStreamCloseFailure, ReadDataFromSerialPortFailure, SerialPortInputStreamCloseFailure, TooManyListeners {
        ArrayList findPort = SerialTool.findPort();
        System.out.println("可用串口");
        for(String f:findPort) {
            System.out.println(f);
        }       
        System.out.println();
        //设定发送字符串
        byte[] bs = hex2Bytes("AA");
        System.out.println(Arrays.toString(bs));//打印字符串
        System.out.println(findPort.get(0));//找到COM1串口
        SerialPort Port = SerialTool.openPort("COM1", 9600);//打开串口
        System.out.println(Port.getName());//获取串口名
        SerialTool.addListener(Port, new SerialTool.DataAvailableListener() {
            @SuppressWarnings("unused")
            @Override
            public void dataAvailable() {
                byte[] data = null;
                try {
                    if (Port == null) {
                        System.out.println("串口对象为空,监听失败!");
                    } else {
                        // 读取串口数据
                        data = SerialTool.readFromPort(Port);
                        /*System.out.println("打印"+data);*/
                        String resultHEX = byteArrayToHexString(data);
                        System.out.println(resultHEX);
                    }
            } catch (Exception e) {
                System.out.println("错误");
            }
            }
            });
        SerialTool.sendToPort(Port, bs);//写入,写入应该在监听器打开之后而不是之前
        
        
        
        /*byte[] readFromPort = SerialTool.readFromPort(Port);
        System.out.println(readFromPort);*/
        /*SerialTool.closePort(Port);*/
    }
    
    public static byte[] hex2Bytes(String hex) {
        if (hex == null || hex.length() == 0) {
            return null;
        }

        char[] hexChars = hex.toCharArray();
        byte[] bytes = new byte[hexChars.length / 2];   // 如果 hex 中的字符不是偶数个, 则忽略最后一个

        for (int i = 0; i < bytes.length; i++) {
            bytes[i] = (byte) Integer.parseInt("" + hexChars[i * 2] + hexChars[i * 2 + 1], 16);
        }

        return bytes;
    }
    /**
     * byte[]转十六进制字符串
     * 
     * @param array
     *            byte[]
     * @return 十六进制字符串
     */
    public static String byteArrayToHexString(byte[] array) {
        if (array == null) {
            return "";
        }
        StringBuffer buffer = new StringBuffer();
        for (int i = 0; i < array.length; i++) {
            buffer.append(byteToHex(array[i]));
        }
        return buffer.toString();
    }
    /**
     * byte转十六进制字符
     * 
     * @param b
     *            byte
     * @return 十六进制字符
     */
    public static String byteToHex(byte b) {
        String hex = Integer.toHexString(b & 0xFF);
        if (hex.length() == 1) {
            hex = '0' + hex;
        }
        return hex.toUpperCase(Locale.getDefault());
    }

}

测试结果:

image.png
image.png

如果有帮助,点个❤吧

image.png

你可能感兴趣的:(java串口通信demo)