java RXTX 串口编程入门完整体验

  有句话说的是"程序员的肚是杂货铺,什么都得有",近期项目中有使用到串口通讯,what ? 串口是什么鬼???感觉应该不是新技术吧? 对于现在整天使用框架、架构、构件什么的,突然要搞串口这个问题感到有些棘手,但是呢,牢骚、废话都没用,接下来开始搞。

  首先了解一下什么是串口,找到了这么一个解释: 串口全称为串行接口,一般指COM接口,是采用串行通信方式的扩展接口。其特点是数据位的传送按位顺序进行,最少只需一根传输线即可完成,成本低但传送速度慢。由于串口(COM)不支持热插拔及传输速率较低,目前部分新主板和大部分便携电脑已取消该接口。现在串口多用于工业控制和测量设备以及部分通信设备中。 嗯 确实是现在使用串口的地方有些少了 , 但是项目中既然涉及到了就要简单了解一下 , 所以又给自己补了一下课,串口的图片是这样子的:

java RXTX 串口编程入门完整体验

对于串口的了解就到这里吧 , 至于再有什么RS-485、RS-232就再自行百度吧 !!! 毕竟这篇的重点是要做一个简单的串口通讯程序。

工欲善其事必先利其器 , 那么接下来干活来了 , 想编程得有趁手的工具 , 所需工具如下 :

1. Virtual Serial Port Driver 用来创建虚拟的串口 , 此工具的使用请自行百度,很简单

2. 串口调试助手 , 用来辅助调试程序 , 此工具的使用也请自行百度 , so easy

3. RXTX 串口编程利器 , 官方还是很可以的 , 下载包中有操作文档说明 , 需要注意的是下载时要匹配自己的电脑系统,区分32bit 和 64bit的

接下来要快速上手 , 不搞概念什么的 

1. 将RXTX下载包中的 RXTXcomm.jar 添加到项目中可以让java类使用

2. 给你提供一个带注释的串口工具类

import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;
import gnu.io.SerialPortEventListener;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Enumeration;

public class SerialPortUtil {

    private static SerialPortUtil serialPortUtil = null;

    static{
        // 在该类被classLoader加载时就初始化一个SerialPortUtil对象
        if(serialPortUtil == null){
            serialPortUtil = new SerialPortUtil();
        }
    }

    private SerialPortUtil(){
    }

    public static SerialPortUtil getInstance(){
        if(serialPortUtil == null){
            serialPortUtil = new SerialPortUtil();
        }
        return serialPortUtil;
    }

    /**
     * 查找可用的串口
     * @return 可用串口的名称列表
     */
    public static final ArrayList<String> findPort(){
        Enumeration<CommPortIdentifier> portList = CommPortIdentifier.getPortIdentifiers();

        ArrayList<String> result = new ArrayList<>();
        while (portList.hasMoreElements()){
            String portName = portList.nextElement().getName();
            result.add(portName);
        }
        return result;
    }


    /**
     * 打开端口
     * @param portName 端口名称
     * @param baudRate 波特率
     * @param dataBits 数据位
     * @param parity 检验位(奇偶位)
     * @param stopBits 停止位
     * @return 串口对象
     */
    public static final SerialPort openPort(String portName,Integer baudRate,Integer dataBits,Integer parity,Integer stopBits){

        try{
            // 通过端口名称识别端口
            CommPortIdentifier commPortIdentifier = CommPortIdentifier.getPortIdentifier(portName);

            // 打开端口 , 并给端口名称和一个超时时间
            CommPort commPort = commPortIdentifier.open(portName,2000);

            // 判断是不是串口
            if(commPort instanceof SerialPort){
                SerialPort serialPort = (SerialPort)commPort;

                serialPort.setSerialPortParams(baudRate,dataBits,stopBits,parity);

                return serialPort;
            }else{
                return null;
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 关闭串口
     * @param serialPort 串口对象
     */
    public static void closePort(SerialPort serialPort){
        if(serialPort !=null){
            serialPort.close();
            serialPort = null;
        }
    }

    /**
     * 给串口发送数据
     * @param serialPort 串口对象
     * @param data 待发送的数据
     */
    public static void sendToPort(SerialPort serialPort,byte[] data){
        OutputStream os = null;

        try{
            os = serialPort.getOutputStream();
            os.write(data);
            os.flush();
        }catch (Exception e){
            e.printStackTrace();
        }finally{
            try{
                if(os !=null){
                    os.close();
                    os = null;
                }
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }

    /**
     * 从串口读取数据
     * @param serialPort  当前已经建立连接的SerialPort对象
     * @return 读取到的数据
     */
    public static byte[] readFromPort(SerialPort serialPort){
        InputStream is = null;
        byte[] result = null;
        try{
            is = serialPort.getInputStream();
            int bufferLength = is.available();

            while (bufferLength != 0){
                result = new byte[bufferLength];  // 初始化byte数组为buffer中数据的长度
                is.read(result);
                bufferLength = is.available();
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try{
                if(is!=null){
                    is.close();
                    is = null;
                }
            }catch (IOException e){
                e.printStackTrace();
            }
        }
        return result;
    }

    /**
     * 添加监听器
     * @param serialPort  串口对象
     * @param listener 串口监听器
     */
    public static void addListener(SerialPort serialPort, SerialPortEventListener listener){
        try{
            // 给串口添加监视器
            serialPort.addEventListener(listener);
            // 设置当有数据到达时唤醒监听接收进程
            serialPort.notifyOnDataAvailable(true);
            // 设置当通讯中断时唤醒中断线程
            serialPort.notifyOnBreakInterrupt(true);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 删除监听器
     * @param serialPort 串口对象
     */
    public static void removeListener(SerialPort serialPort){
        serialPort.removeEventListener();
    }    
}

3. 添加发送数据的测试类

import gnu.io.SerialPort;
public class RXTXtest {


    public static void main(String[] args) {
        ArrayList<String> allPorts = SerialPortUtil.findPort();
        System.out.println("获取到的串口有:");
        for (String portName : allPorts) {
            System.out.println(portName);
        }
        System.out.println("获取全部串口方法执行完成");

        final SerialPort serialPort = SerialPortUtil.openPort("COM2", 9600, 8, 0, 1);

        String str = "hello port";
        byte[] bytes = str.getBytes();
        SerialPortUtil.sendToPort(serialPort, bytes);

    }

}

4. 添加接收数据的测试类

import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;


public class RXTXtest1 {

    private static String res = null;

    public static void main(String[] args) {
        final SerialPort serialPort = SerialPortUtil.openPort("COM3", 9600, 8, 0, 1);


        SerialPortUtil.addListener(serialPort, new SerialPortEventListener() {
            @Override
            public void serialEvent(SerialPortEvent serialPortEvent) {
                if (serialPortEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) {  //如果是数据通知
                    byte[] bytes = SerialPortUtil.readFromPort(serialPort);
                    res = new String(bytes);
                    System.out.println("获取到的数据长度是: " + bytes.length);
                    System.out.println("收到的数据是: " + res);
                }
            }
        });
    }

}

5. 需要注意的是 RXTXtest1中的 COM3 和 RXTXtest中的 COM2 是通过Virtual Serial Port Driver工具虚拟出来的一对串口

6. 接下来就可以运行看效果了 , 运行RXTXtest1 , 再运行RXTXtest , 就可以去看控制台的输出了

程序所需的工具也都上传了百度网盘, 链接如下:

链接:https://pan.baidu.com/s/1G2k7_bkk6TlENI8MNlJ85Q 
提取码:cf39 

至此 java串口编程入门的完整体验分享结束 , 做个记录 !