Java实现串口通信

  • 串口通信
  • MODBUS
  • Java实现串口通信
  • RXTX串口通信开源框架(JAVA)
  • 获取设备可以串口
  • 打开指定串口
  • 设置监听
  • 往串口中发送数据
  • 从串口中读取数据
  • 关闭串口
  • 调试工具(自行百度)
  • 注意


串口通信

所谓串口,指的是串行通信接口(com),区别于并行通信,一次性可传输8位数据,不会发生数据位序混乱,但是比并行通信传输时间长得多,可以双向通信,主要用于设备与设备之间的通信,常用的主要有两类
1.RS232(一对一数据传输,适合本地设备之间的通信)
2.RS485(一对多数据传输,适合远程设备之间的通信)

MODBUS

应用层面的通信协议,Modbus可使用串口和网线(含光纤)方式进行传输

Java实现串口通信

流程:设置串口通信参数—》打开串口—》发送数据—》获得返回的数据—》解析数据—》关闭串口

RXTX串口通信开源框架(JAVA)

<dependency>
			<groupId>org.bidib.jbidib.org.qbang.rxtx</groupId>
			<artifactId>rxtxcomm</artifactId>
			<version>2.2</version>
		</dependency>

获取设备可以串口

Enumeration<CommPortIdentifier> portList = CommPortIdentifier.getPortIdentifiers();

打开指定串口

返回一个可用的SerialPort对象,通过这个对象发送数据,接收数据,关闭串口

1.端口名称,如 COM1,为 null 时,默认使用电脑中能用的端口中的第一个
2.波特率(baudrate),如 9600
3.数据位(datebits),如 SerialPort.DATABITS_8 = 8
4.停止位(stopbits),如 SerialPort.STOPBITS_1 = 1
5.校验位 (parity),如 SerialPort.PARITY_NONE = 0

/**
     * 打开电脑上指定的串口
     *
     * @param portName 端口名称,如 COM1,为 null 时,默认使用电脑中能用的端口中的第一个
     * @param b        波特率(baudrate),如 9600
     * @param d        数据位(datebits),如 SerialPort.DATABITS_8 = 8
     * @param s        停止位(stopbits),如 SerialPort.STOPBITS_1 = 1
     * @param p        校验位 (parity),如 SerialPort.PARITY_NONE = 0
     * @return 打开的串口对象,打开失败时,返回 null
     */
    public static final SerialPort openComPort(String portName, int b, int d, int s, int p) {
        CommPort commPort = null;
        try {
            //当没有传入可用的 com 口时,默认使用电脑中可用的 com 口中的第一个
            if (portName == null || "".equals(portName)) {
                List<String> comPortList = findSystemAllComPort();
                if (comPortList != null && comPortList.size() > 0) {
                    portName = comPortList.get(0);
                }
            }
            logger.info("开始打开串口:portName=" + portName + ",baudrate=" + b + ",datebits=" + d + ",stopbits=" + s + ",parity=" + p);

            //通过端口名称识别指定 COM 端口
            CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);
            /**
             * open(String TheOwner, int i):打开端口
             * TheOwner 自定义一个端口名称,随便自定义即可
             * i:打开的端口的超时时间,单位毫秒,超时则抛出异常:PortInUseException if in use.
             * 如果此时串口已经被占用,则抛出异常:gnu.io.PortInUseException: Unknown Application
             */
            commPort = portIdentifier.open(portName, 5000);
            /**
             * 判断端口是不是串口
             * public abstract class SerialPort extends CommPort
             */
            if (commPort instanceof SerialPort) {
                SerialPort serialPort = (SerialPort) commPort;
                /**
                 * 设置串口参数:setSerialPortParams( int b, int d, int s, int p )
                 * b:波特率(baudrate)
                 * d:数据位(datebits),SerialPort 支持 5,6,7,8
                 * s:停止位(stopbits),SerialPort 支持 1,2,3
                 * p:校验位 (parity),SerialPort 支持 0,1,2,3,4
                 * 如果参数设置错误,则抛出异常:gnu.io.UnsupportedCommOperationException: Invalid Parameter
                 * 此时必须关闭串口,否则下次 portIdentifier.open 时会打不开串口,因为已经被占用
                 */
                serialPort.setSerialPortParams(b, d, s, p);
                logger.info("打开串口 " + portName + " 成功...");
                return serialPort;
            } else {
                logger.error("当前端口 " + commPort.getName() + " 不是串口...");
            }
        } catch (NoSuchPortException e) {
            e.printStackTrace();
        } catch (PortInUseException e) {
            logger.warn("串口 " + portName + " 已经被占用,请先解除占用...");
            e.printStackTrace();
        } catch (UnsupportedCommOperationException e) {
            logger.warn("串口参数设置错误,关闭串口,数据位[5-8]、停止位[1-3]、验证位[0-4]...");
            e.printStackTrace();
            if (commPort != null) {//此时必须关闭串口,否则下次 portIdentifier.open 时会打不开串口,因为已经被占用
                commPort.close();
            }
        }
        logger.error("打开串口 " + portName + " 失败...");
        return null;
    }

设置监听

每当事件响应进行对应操作

//设置串口监听
        SerialPortTool.setListenerToSerialPort(serialPort, new SerialPortEventListener() {

            @Override
            public void serialEvent(SerialPortEvent serialPortEvent) {
                switch (serialPortEvent.getEventType()) {
                    case SerialPortEvent.DATA_AVAILABLE: // 1.串口存在有效数据
                        try {
                            //读取串口数据
                            SerialPortTool.readData(serialPort);
                        } catch (Exception e) {
                         }
                        break;

                    case SerialPortEvent.OUTPUT_BUFFER_EMPTY: // 2.输出缓冲区已清空
                        logger.error("输出缓冲区已清空");
                        break;

                    case SerialPortEvent.CTS: // 3.清除待发送数据
                        logger.error("清除待发送数据");
                        break;

                    case SerialPortEvent.DSR: // 4.待发送数据准备好了
                        logger.error("待发送数据准备好了");
                        break;

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

                    default:
                        break;

                }
            }

        });

往串口中发送数据

serialPort全局对象发送,参数为byte[]数组(16进制)

/**
     * 往串口发送数据
     *
     * @param serialPort 串口对象
     */
    public static void sendDataToComPort(SerialPort serialPort, byte[] orders) {
        OutputStream outputStream = null;
        try {
            if (serialPort != null) {
                outputStream = serialPort.getOutputStream();
                outputStream.write(orders);
                outputStream.flush();
                logger.info("往串口 " + serialPort.getName() + " 发送数据:" + Arrays.toString(orders) + " 完成...");
            } else {
                logger.error("gnu.io.SerialPort 为null,取消数据发送...");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

从串口中读取数据

serialPort全局对象获取

// 从串口读取数据
    public static byte[] readData(SerialPort serialPort) {
        InputStream is = null;
        byte[] bytes = null;
        try {

            //获得串口的输入流
            is = serialPort.getInputStream();
            // 通过输入流对象的available方法获取数组字节长度
            byte[] readBuffer = new byte[is.available()];
            // 从线路上读取数据流
            int len = 0;
            while ((len = is.read(readBuffer)) != -1) {
                // 直接获取到的数据
                String a=new String(readBuffer, 0, len);
                }
                break;
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {

            try {
                if (is != null) {
                    is.close();
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return bytes;
    }

关闭串口

/**
     * 关闭串口
     *
     * @param serialPort 待关闭的串口对象
     */
    public static void closeComPort(SerialPort serialPort) {
        if (serialPort != null) {
            serialPort.close();
            logger.info("关闭串口 " + serialPort.getName());
        }
    }

调试工具(自行百度)

笔记本电脑可以使用usb转串口线,安装转串口驱动就可以使用了

java 串口发送 java串口编程_java 串口发送

注意

串口占用,连接线断开,中文字符乱码处理(字符超过框架设定的字节,比如中文字符)自行转码,接口文档找厂家要。数据转化为16进制再发送。长时间通信就不用关闭串口