当前位置:   article > 正文

Java串口通信_java 串口通信

java 串口通信

Java串口通信介绍

概述:用Java的方式和我们的硬件(传感器)通过串口(COM3)实现数据交互等功能,基于UART协议实现

串口(串行端口)通信

Java串口通讯是指使用Java编程语言与串行端口(串口)进行数据通讯的过程,通过数据信号线 、地线、控制线等,按位进行传输数据的一种通讯方式(注意,是一位一位的传输,区别于并口通讯,传输慢)。这种通信方式使用的数据线少,在远距离通信中可以节约通信成本,但其传输速度比并行传输低。虽然说慢,不如并,但不代表就要抛弃,某些项目还是很有用的,例如公司最近营养探索馆的一个血压探测仪,就是串口通讯,需要开发串口。

优点:

  1. 适用性广泛: 串口通讯通常用于连接各种外部设备,如传感器、控制器、调制解调器等,因此适用性非常广泛。
  2. 线缆简单: 串口通讯只需要少量的线缆就能实现数据传输,因此在布线和连接方面比较简单。
  3. 长距离传输: 串口通讯可以通过串口转以太网等设备实现远程通讯,支持长距离传输。

缺点:

  1. 速度相对较慢: 串口通讯的传输速度通常比较慢,受到硬件限制,无法满足高速数据传输的需求。
  2. 连接设备数量有限: 串口通讯通常只支持连接少量外部设备,无法承载大规模设备连接的需求。

并口通信

并口通讯是通过计算机的并行接口(并口)进行数据传输的方式。并口通讯可以同时传输多个比特(通常是8位或更多),因此传输速度相对较快。并口通讯通常用于连接一些需要高速数据传输的外部设备,如打印机、扫描仪等。并口通讯所需的线缆较为复杂,包括大量的数据线和控制线,连接和布线相对复杂。

优点:

  1. 高速传输: 并口通讯支持并行传输,因此传输速度相对较快,在某些应用场景下能够满足高速数据传输的需求。
  2. 多设备连接: 并口通讯通常支持连接多个外部设备,能够满足一定规模的设备连接需求。

缺点:

  1. 线缆复杂: 并口通讯所需的线缆较为复杂,包括大量的数据线和控制线,因此在布线和连接方面相对复杂。
  2. 不易远程传输: 由于线缆复杂和传输方式的限制,通常不能实现远程数据传输。

综合来看,串口通讯适用性广泛、连接简单,但传输速度较慢;而并口通讯传输速度快,能够连接多个设备,但线缆复杂且不易远程传输。因此在实际应用中,选择串口通讯还是并口通讯取决于具体的应用场景和需求。

实现方式

1.通过comm.jar实现太老了,对jdk版本有要求(jdk 1.8 32bit),也要配置dll文件

2.通过RXTXcomm.jar实现(更新慢),需要配置dll文件,打包可能会出错

3.通过jserialcomm实现(推荐)跨平台,兼容性好

1.通过comm.jar实现

准备工作

1.下载comm.jar相关资源,将javax.comm.properties,win32com.dll配置文件放到jdk的bin和lib目录

2.准备好一个串口工具,和模拟串口的工具,便于测试

关于依赖引用问题:

当maven拉取不到相关依赖时,有两种解决方案

1.作为资源文件夹内的资源引用

我们可以选择将该依赖的jar包下载下来,通过创建lib文件夹的方式将依赖添加到项目中

		<dependency>
            <groupId>gun.io</groupId>
            <artifactId>rxtx</artifactId>
            <version>1.0.0</version>
            <!--system,类似provided,需要显式提供依赖的jar以后,Maven就不会在Repository中查找它-->
            <scope>system</scope>
            <systemPath>${project.basedir}/lib/RXTXcomm.jar</systemPath>
        </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

2.将jar包手动安装到maven仓库

实现步骤

1.用Configure Virtual Serial Port Driver虚拟串口工具模拟2个串口号

2.导入相应依赖 comm.jar包并添加到项目中,jdk版本为1.8 32bit

3.通过comm.jar包提供的方法和串口建立通讯

4.通过CommPortIdentifier.getPortIdentifiers()方法获取可用串口

5.选择合适端口,通过该commPort.open()方法打开该端口

6.设置常用参数,如波特率,停止位,校验位等 serialPort.setSerialPortParams()

7.端口打开后,可用通过serialPort.addEventListener()方法添加监听器监听我们之前打开的端口

8.通过程序向端口发送数据,核心是基于流的形式,通过outputStream.write()发送数据

相关代码

package com.xxxx.ckcomm.utils;

import javax.comm.*;
import java.io.*;
import java.util.*;

public class DSerialPort implements Runnable, SerialPortEventListener {

    private String appName = "串口通讯测试";
    private int timeout = 2000;// open 端口时的等待时间,延迟时间(毫秒数)
    private int threadTime = 0;

    private CommPortIdentifier commPort;
    private SerialPort serialPort;
    private InputStream inputStream;
    private OutputStream outputStream;
    //当前接收COM口的数据
    public static String receiptDataString = "";
    //当前已取的数组下标
    public static int nowDataIndex = 0;
    //当前接收COM口的数据自动切割成StringList
    public static ArrayList<String> receiptDataList = new ArrayList<String>();


    static {
        String driverName = "com.sun.comm.Win32Driver";
        CommDriver driver;
        try {
            driver = (CommDriver) Class.forName(driverName).newInstance();
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
        driver.initialize();
    }


    /**
     * @方法名称 :listPort
     * @功能描述 :列出所有可用的串口
     * @返回值类型 :List<String>
     */
    @SuppressWarnings("rawtypes")
    public List<String> listPort() {
        //获得当前所有可用串口
        Enumeration<CommPortIdentifier> portList = CommPortIdentifier.getPortIdentifiers();
        ArrayList<String> portNameList = new ArrayList<>();
        //将可用串口名添加到List并返回该List
        while (portList.hasMoreElements()) {
            String portName = portList.nextElement().getName();
            portNameList.add(portName);
        }
        return portNameList;
    }

    /**
     * @param portName
     * @方法名称 :selectPort
     * @功能描述 :选择一个端口,比如:COM1
     * @返回值类型 :void
     */
    @SuppressWarnings("rawtypes")
    public void selectPort(String portName) {

        this.commPort = null;
        CommPortIdentifier cpid;
        Enumeration portList = CommPortIdentifier.getPortIdentifiers();
        while (portList.hasMoreElements()) {
            System.out.println("串口接口调用成功");
            cpid = (CommPortIdentifier) portList.nextElement();
            if (cpid.getPortType() == CommPortIdentifier.PORT_SERIAL && cpid.getName().equals(portName)) {
                this.commPort = cpid;
                break;
            }
        }
        openPort();
    }

    /**
     * @方法名称 :openPort
     * @功能描述 :打开SerialPort
     * @返回值类型 :void
     */
    private void openPort() {
        if (commPort == null)
            log("无法找到串口!");
        else {
            log("端口选择成功,当前端口:" + commPort.getName() + ",现在实例化 SerialPort:");

            try {
                serialPort = (SerialPort) commPort.open(appName, timeout);//打开端口
                serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
                //设置参数
                log("实例 SerialPort 成功!");
            } catch (PortInUseException e) {
                throw new RuntimeException(String.format("端口'%1$s'正在使用中!", commPort.getName()));
            } catch (UnsupportedCommOperationException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * @方法名称 :checkPort
     * @功能描述 :检查端口是否正确连接
     * @返回值类型 :void
     */
    public void checkPort() {
        if (commPort == null)
            throw new RuntimeException("没有选择端口,请使用 " + "selectPort(String portName) 方法选择端口");

        if (serialPort == null) {
            throw new RuntimeException("SerialPort 对象无效!");
        }
    }

    /**
     * @方法名称 :write
     * @功能描述 :向端口发送数据,请在调用此方法前 先选择端口,并确定SerialPort正常打开!
     * @返回值类型 :void
     */
    public void write(String message) {
        checkPort();

        try {
            outputStream = new BufferedOutputStream(serialPort.getOutputStream());
        } catch (IOException e) {
            throw new RuntimeException("获取端口的OutputStream出错:" + e.getMessage());
        }

        try {
            outputStream.write(message.getBytes());
            log("信息发送成功!");
        } catch (IOException e) {
            throw new RuntimeException("向端口发送信息时出错:" + e.getMessage());
        } finally {
            try {
                outputStream.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public void write(byte[] message) {
        checkPort();

        try {
            outputStream = new BufferedOutputStream(serialPort.getOutputStream());
        } catch (IOException e) {
            throw new RuntimeException("获取端口的OutputStream出错:" + e.getMessage());
        }

        try {
            outputStream.write(message);
            log("信息发送成功!");
        } catch (IOException e) {
            throw new RuntimeException("向端口发送信息时出错:" + e.getMessage());
        } finally {
            try {
                outputStream.close();
            } catch (Exception e) {
            }
        }
    }

    /**
     * @param time 监听程序的存活时间,单位为秒,0 则是一直监听
     * @方法名称 :startRead
     * @功能描述 :开始监听从端口中接收的数据
     * @返回值类型 :void
     */
    public void startRead(int time) {
        checkPort();

        try {
            inputStream = new BufferedInputStream(serialPort.getInputStream());
        } catch (IOException e) {
            throw new RuntimeException("获取端口的InputStream出错:" + e.getMessage());
        }

        try {
            serialPort.addEventListener(this);//向SerialPort对象中添加串口事件监听器
        } catch (TooManyListenersException e) {
            throw new RuntimeException(e.getMessage());
        }

        serialPort.notifyOnDataAvailable(true);//设置串口有数据的事件true有效,false无效

        log(String.format("开始监听来自'%1$s'的数据--------------", commPort.getName()));
        if (time > 0) {
            this.threadTime = time * 1000;
            Thread t = new Thread(this);
            t.start();
            log(String.format("监听程序将在%1$d秒后关闭。。。。", threadTime));
        }
    }

    /**
     * @方法名称 :close
     * @功能描述 :关闭 SerialPort
     * @返回值类型 :void
     */
    public void close() {
        serialPort.close();
        serialPort = null;
        commPort = null;
    }

    public void log(String msg) {
        System.out.println(appName + " --> " + msg);
    }

    /**
     * 数据接收的监听处理函数
     */
    @Override
    public void serialEvent(SerialPortEvent arg0) {
        switch (arg0.getEventType()) {
            case SerialPortEvent.BI:/* Break interrupt,通讯中断 */
            case SerialPortEvent.OE:/* Overrun error,溢位错误 */
            case SerialPortEvent.FE:/* Framing error,传帧错误 */
            case SerialPortEvent.PE:/* Parity error,校验错误 */
            case SerialPortEvent.CD:/* Carrier detect,载波检测 */
            case SerialPortEvent.CTS:/* Clear to send,清除发送 */
            case SerialPortEvent.DSR:/* Data set ready,数据设备就绪 */
            case SerialPortEvent.RI:/* Ring indicator,响铃指示 */
            case SerialPortEvent.OUTPUT_BUFFER_EMPTY:/*
             * Output buffer is
             * empty,输出缓冲区清空
             */
                break;
            case SerialPortEvent.DATA_AVAILABLE:/*
             * Data available at the serial
             * port,端口有可用数据。读到缓冲数组,输出到终端
             */
                byte[] readBuffer = new byte[1024];
                StringBuilder readStr = new StringBuilder();
                String s2 = "";
                try {
                    while (inputStream.available() > 0) {
                        inputStream.read(readBuffer);
                        readStr.append(new String(readBuffer).trim());
                    }
                    s2 = new String(readBuffer).trim();
                    //接收的精华再这里
                    //1。readStr为当次读入的,一般设备是1位1位读,模拟的时候就很多位,但是不重要
                    //2。receiptDataString是用来缓存输入字符串的
                    //3。receiptDataString.length()==XX这里可以设定你要接受的长度,然后接收指定数据
                    //4。超长或者不符合长度,你可以看情况抛弃数据或者清空,或者累加
                    //5。接受成功的数据,放入receiptDataList供获取调用
                    //6。nowDataIndex是当前数组的下标,可以参考PortController中对数据获取的方法
                    log("接收端口COM->返回数据(长度为" + readStr.length() + "):数据" + s2);
                    receiptDataString += readStr;
                    log("receiptDataString->长度" + receiptDataString.length() + "),数据" + receiptDataString);
                    if (receiptDataString.length() == 58) {
                        receiptDataList.add(receiptDataString);
                        receiptDataString = "";
                        log("校验通过,数据接收成功");
                    } else if (receiptDataString.length() > 100) {
                        receiptDataString = "";
                    }
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
        }
    }

    @Override
    public void run() {
        try {
            timerTest(threadTime);
            serialPort.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //监听串口指定时间,以秒为单位
    public void timerTest(int minutes){
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            int secondsLeft = minutes ;
            public void run() {
                if (secondsLeft > 0) {
                    secondsLeft--;
                } else {
                    log(String.format("端口'%1$s'监听关闭了!", commPort.getName()));
                    timer.cancel(); // 结束计时器
                }
            }
        }, 0, 1000); // 每隔一秒执行一次
    }



    public static void main(String[] args) {

        DSerialPort sp = new DSerialPort();
        sp.listPort();
        sp.selectPort("COM3");
        sp.write("2");
        sp.startRead(120);
        sp.close();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309

2.通过RXTXcomm.jar实现

准备工作

1.下载RXTXcomm的资源包

2.将rxtxParallel.dll和rxtxSerial.dll两个文件放到jdk下jre的bin目录

实现步骤

1.导入RXTXcomm.jar的依赖

2.建立连接,通过CommPortIdentifier.getPortIdentifier(portName)方法可用获取到对应端口的对象

3.打开端口,portIdentifier.open(portName, timeout);/portName:端口名 timeout:超时时间

4.判断该端口是否为串口,如果是设置串口的参数,如波特率,停止位,数据位,检验位

serialPort.setSerialPortParams(baudRate, SerialPort.*DATABITS_8*, SerialPort.*STOPBITS_1*,SerialPort.*PARITY_NONE*);
  • 1

5.添加监听器,监听我们打开的端口,用于获取传感器向我们发送的数据

serialPort.addEventListener(this);
serialPort.notifyOnDataAvailable(true);//设置串口数据时间有效(可监听)
  • 1
  • 2

6.关闭串口,serialPort.close();

相关代码

SeriaTool.class

package com.xxxx.rxtxcomm.utils;

import com.alibaba.fastjson.JSON;
import com.xxxx.rxtxcomm.entity.SmCommMsg;
import com.xxxx.rxtxcomm.exception.BusinessException;
import com.xxxx.rxtxcomm.mqtt.MqttUtil;
import com.xxxx.rxtxcomm.response.ResultCode;
import com.xxxx.rxtxcomm.service.CommService;
import gnu.io.*;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author Long
 */
public class SerialTool implements SerialPortEventListener {

    private static SerialPort serialPort;
    private static InputStream input;
    private static OutputStream output;
    private static volatile SerialTool serialTool;

    /**
     * 获取提供服务的SerialTool对象
     *
     * @return serialTool
     */
    public static SerialTool getInstance() {
        if (serialTool == null) {
            synchronized (SerialTool.class) {    //使用同步锁进行双重确认,防止生成两个实例
                if (serialTool == null) {
                    serialTool = new SerialTool();
                }
            }
        }
        return serialTool;
    }

    //私有化SerialTool类的构造方法,不允许其他类生成SerialTool对象
    private SerialTool() {
    }

    /**
     * 查找所有可用串口
     *
     * @return 可用端口名称列表
     */
    public List<String> findPort() {
        //获取系统中所有通讯端口
        Enumeration<CommPortIdentifier> portList = CommPortIdentifier.getPortIdentifiers();
        List<String> portNameList = new ArrayList<>();
        //将可用串口名添加到List并返回该List
        while (portList.hasMoreElements()) {
            CommPortIdentifier commPortIdentifier = portList.nextElement();
            //判断是否是串行端口
            if (commPortIdentifier.getPortType() == CommPortIdentifier.PORT_SERIAL) {
                String portName = commPortIdentifier.getName();
                portNameList.add(portName);
            }
        }
        return portNameList;
    }

    /**
     * 打开串口
     *
     * @param portName 端口名称
     * @param baudRate 波特率
     */
    public void openPort(String portName, int baudRate) {
        try {
            //通过端口名识别端口
            CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);
            //打开端口,并给端口名字和一个timeout(打开操作的超时时间)
            CommPort commPort = portIdentifier.open(portName, 2000);
            //判断是不是串口
            if (commPort instanceof SerialPort) {
                serialPort = (SerialPort) commPort;
                try {
                    //设置一下串口的波特率等参数
                    serialPort.setSerialPortParams(baudRate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
                    input = serialPort.getInputStream();
                    output = serialPort.getOutputStream();
                    serialPort.addEventListener(this);
                    //设置当有数据到达时唤醒监听接收线程
                    serialPort.notifyOnDataAvailable(true);
                    //设置当通信中断时唤醒中断线程
                    serialPort.notifyOnBreakInterrupt(true);
                } catch (UnsupportedCommOperationException e) {
                    throw new BusinessException(ResultCode.PARAM_NOT_COMPLETE.getCode(), ResultCode.PARAM_NOT_VALID.getMessage());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                } catch (TooManyListenersException e) {
                    throw new BusinessException(ResultCode.COMM_PORT_LISTENERS_MANY.getCode(), ResultCode.COMM_PORT_LISTENERS_MANY.getMessage());
                }
                System.out.println("Open " + portName + " successfully !");
                System.out.println("-- 开始监听 " + portName + " 端口的数据 --");
            } else {
                throw new BusinessException(ResultCode.COMM_PORT_NOT_PORT.getCode(), ResultCode.COMM_PORT_NOT_PORT.getMessage());
            }
        } catch (Exception e1) {
            try {
                throw new Exception();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 关闭串口
     */
    public void closePort() {
        if (serialPort != null) {
            serialPort.close();
        }
        if (input != null) {
            try {
                input.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        if (output != null) {
            try {
                output.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 往串口发送数据
     *
     * @param order 待发送数据
     */
    public void sendToPort(String message) {
        try {
            output = serialPort.getOutputStream();
            output.write(message);
            output.flush();
            System.out.println("成功发送数据,发送的数据为:" + message);
            System.out.println("========================================================================");
            System.out.println();
        } catch (IOException e) {
            try {
                throw new Exception();
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        }
    }


    @Override
    public synchronized void serialEvent(SerialPortEvent oEvent) {
        try {
            //让该线程延迟一会,保证输出的顺序性,先发数据,在接收数据
            Thread.sleep(100);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        switch (oEvent.getEventType()) {
            case SerialPortEvent.BI: // 通讯中断
            case SerialPortEvent.OE: // 溢位错误
            case SerialPortEvent.FE: // 帧错误
            case SerialPortEvent.PE: // 奇偶校验错误
            case SerialPortEvent.CD: // 载波检测
            case SerialPortEvent.CTS: // 清除发送
            case SerialPortEvent.DSR: // 数据设备准备好
            case SerialPortEvent.RI: // 响铃侦测
            case SerialPortEvent.OUTPUT_BUFFER_EMPTY: // 输出缓冲区已清空
                break;
            case SerialPortEvent.DATA_AVAILABLE: // 有数据到达
                // 调用读取数据的方法
                readData();
                break;
            default:
                break;
        }
    }

    public void readData() {
        try {
            String strMsg = "";
            int len = input.available();
            byte[] buffer = new byte[len];
            input.read(buffer, 0, len);
            String data = DataChangeUtil.byteArrayToHexString(buffer);
            // 处理接收到的数据
            System.out.println("接收到的数据为==> " + data);
            System.out.println("========================================================================");
            System.out.println();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
package com.xxxx.rxtxcomm.controller;


import com.xxxx.rxtxcomm.response.R;
import com.xxxx.rxtxcomm.service.CommService;
import com.xxxx.rxtxcomm.utils.SerialTool;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;


@RestController
@Api(value = "Java串口通讯测试")
public class CommController {

    public static SerialTool serialTool = SerialTool.getInstance();

    @ApiOperation(value = "初始化串口")
    @PostMapping("/init")
    public R init(String portName, int baudRate) {
        serialTool.openPort(portName, baudRate);
        return R.ok();
    }

    @ApiOperation(value = "向传感器发送消息")
    @PostMapping("/sendMsg")
    public R sendMsg(String message) {
        serialTool.sendToPort(message);
        return R.ok();
    }


    @ApiOperation(value = "释放资源,关闭串口")
    @PostMapping("/closePort")
    public R closePort() {
        serialTool.closePort();
        return R.ok();
    }


}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

3.通过jserialcomm实现

实现步骤

1.引入依赖

		<dependency>
            <groupId>com.fazecast</groupId>
            <artifactId>jSerialComm</artifactId>
            <version>[2.0.0,3.0.0)</version>
        </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

2.和模块建立连接

SerialPort serialPort=SerialPort.getCommPort(portName)  //portName:端口名  例如:COM3
  • 1

3.通过SerialPort的实例化对象添加一个监听器

serialPort.addDataListener(new DataListener());(DataListenner为自定义类)
  • 1

4.开始向模块发送指令,如读取传感器监测气体类型

serialPort.writeBytes(data, data.length);
  • 1

5.如果传感器有回传数据,此时我们的监听器会监听并记录

@Override
        public void serialEvent(SerialPortEvent event) {
            if (event.getEventType() != SerialPort.LISTENING_EVENT_DATA_AVAILABLE) return;
            SerialPort comPort = event.getSerialPort();
            byte[] newData = new byte[comPort.bytesAvailable()];
            comPort.readBytes(newData, newData.length);
            readData(newData);
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

6.释放资源,关闭端口

serialPort.closePort();
  • 1

相关代码

package com.xxxx.jserialcomm.utils;

import com.fazecast.jSerialComm.SerialPort;
import com.fazecast.jSerialComm.SerialPortDataListener;
import com.fazecast.jSerialComm.SerialPortEvent;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class SerialCommUtil {
    private SerialPort serialPort;

    private static SerialCommUtil serialCommUtil;

    public static SerialCommUtil getSerialCommUtil() {
        if (serialCommUtil == null) {
            synchronized (SerialCommUtil.class) {
                if (serialCommUtil == null) {
                    serialCommUtil = new SerialCommUtil();
                }
            }
        }
        return serialCommUtil;
    }


    /**
     * 打开串口
     *
     * @param portName 串口名称(例如 "COM3" 或 "/dev/ttyUSB0")
     * @param baudRate 波特率
     * @return 是否成功打开
     */
    public boolean openPort(String portName, int baudRate) {
        serialPort = SerialPort.getCommPort(portName);
        serialPort.setBaudRate(baudRate);
        serialPort.setNumDataBits(8);
        serialPort.setNumStopBits(SerialPort.ONE_STOP_BIT);
        serialPort.setParity(SerialPort.NO_PARITY);
        boolean flag = serialPort.openPort();
        serialPort.addDataListener(new DataListener());
        return flag;
    }

    /**
     * 关闭串口
     */
    public void closePort() {
        if (serialPort != null && serialPort.isOpen()) {
            serialPort.closePort();
        }
    }

    /**
     * 发送数据
     *
     * @param data 要发送的数据
     * @return 是否成功发送
     */
    public boolean sendData(byte[] data) {
        if (serialPort == null || !serialPort.isOpen()) {
            return false;
        }

        int bytesSent = serialPort.writeBytes(data, data.length);
        return bytesSent == data.length;
    }

    // 数据监听器
    private static class DataListener implements SerialPortDataListener {
        @Override
        public int getListeningEvents() {
            return SerialPort.LISTENING_EVENT_DATA_AVAILABLE;
        }

        @Override
        public void serialEvent(SerialPortEvent event) {
            if (event.getEventType() != SerialPort.LISTENING_EVENT_DATA_AVAILABLE) return;
            SerialPort comPort = event.getSerialPort();
            byte[] newData = new byte[comPort.bytesAvailable()];
            comPort.readBytes(newData, newData.length);
            readData(newData);
        }
    }

    public static void readData(byte[] newData) {
        try {
            String data = DataChangeUtil.byteArrayToHexString(newData);
            // 处理接收到的数据
            System.out.println("接收到的数据为: " + data);
            System.out.println("========================================================================");
            System.out.println();
        } catch (Exception e) {
            log.error("Bad Things",e);
        }
    }

    /**
     * 接收数据
     *
     * @param bufferSize 缓冲区大小cl
     * @return 接收到的数据
     */
    public byte[] receiveData(int bufferSize) {
        if (serialPort == null || !serialPort.isOpen()) {
            return null;
        }

        byte[] buffer = new byte[bufferSize];
        int bytesRead = serialPort.readBytes(buffer, bufferSize);

        if (bytesRead > 0) {
            byte[] actualData = new byte[bytesRead];
            System.arraycopy(buffer, 0, actualData, 0, bytesRead);
            return actualData;
        } else {
            return null;
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119

Controller

package com.xxxx.jserialcomm.controller;


import com.xxxx.jserialcomm.response.R;
import com.xxxx.jserialcomm.service.CommService;
import com.xxxx.jserialcomm.utils.DataChangeUtil;
import com.xxxx.jserialcomm.utils.SerialCommUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Api(value = "Java串口通讯测试")
public class SemeaController {

    @Autowired
    CommService commService;
    public static SerialCommUtil serialCommUtil = SerialCommUtil.getSerialCommUtil();

    @ApiOperation(value = "初始化串口")
    @PostMapping("/init")
    public R init(String portName, int baudRate)  {
        boolean flag = serialCommUtil.openPort(portName, baudRate);
        if(flag){
            return R.ok().data("msg","初始化成功");
        }else{
            return R.error().data("msg","初始化失败");
        }
    }

    @ApiOperation(value = "向传感器发送消息")
    @PostMapping("/sendMsg")
    public R sendMsg( String message)  {
        boolean flag = serialCommUtil.sendData(message.getBytes());
        if(flag){
            return R.ok().data("msg","消息发送成功:"+ message);
        }else{
            return R.error().data("msg","消息发送失败");
        }
    }


    @ApiOperation(value = "释放资源,关闭串口")
    @PostMapping("/closePort")
    public R closePort() {
        boolean b = serialCommUtil.closePort();
        if(b){
            return R.ok();
        }else {
            return R.error();
        }
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小惠珠哦/article/detail/937621
推荐阅读
相关标签
  

闽ICP备14008679号