• SpringBoot+jSerialComm实现Java串口通信 读取串口数据以及发送数据


    记录一下使用SpringBoot+jSerialComm实现Java串口通信,使用Java语言开发串口,对串口进行读写操作,在win和linux系统都是可以的,有一点好处是不需要导入额外的文件。

    案例demo源码:SpringBoot+jSerialComm实现Java串口通信 读取串口数据以及发送数据

    之前使用RXTXcomm实现Java串口通信,这种方式对linux(centos)的支持效果不好还有些问题 但在win下面使用还不错,原文地址:SpringBoot+RXTXcomm实现Java串口通信 读取串口数据以及发送数据

    不需要额外导入文件 比如dll 只需要导入对应的包

     <dependency>
         <groupId>com.fazecast</groupId>
         <artifactId>jSerialComm</artifactId>
         <version>2.9.2</version>
     </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.0.5.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
    
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>boot.example.jSerialComm</groupId>
        <artifactId>boot-example-jSerialComm-2.0.5</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>boot-example-jSerialComm-2.0.5</name>
        <url>http://maven.apache.org</url>
    
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
            <java.version>1.8</java.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>com.fazecast</groupId>
                <artifactId>jSerialComm</artifactId>
                <version>2.9.2</version>
            </dependency>
            <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-swagger2</artifactId>
                <version>2.9.2</version>
            </dependency>
            <dependency>
                <groupId>com.github.xiaoymin</groupId>
                <artifactId>swagger-bootstrap-ui</artifactId>
                <version>1.9.2</version>
            </dependency>
        </dependencies>
    
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <configuration>
                        <mainClass>boot.example.SerialPortApplication</mainClass>
                        <includeSystemScope>true</includeSystemScope><!--外部进行打包-->
                    </configuration>
                    <executions>
                        <execution>
                            <goals>
                                <goal>repackage</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    
    </project>
    
    • 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

    SerialPortApplication启动类

    package boot.example;
    
    
    import boot.example.serialport.SerialPortManager;
    import org.springframework.boot.CommandLineRunner;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.scheduling.annotation.EnableAsync;
    import org.springframework.scheduling.annotation.EnableScheduling;
    import javax.annotation.PreDestroy;
    import java.io.IOException;
    
    /**
     *  蚂蚁舞
     */
    @SpringBootApplication
    @EnableScheduling
    @EnableAsync
    public class SerialPortApplication implements CommandLineRunner {
    
        public static void main(String[] args) throws IOException {
            SpringApplication.run(SerialPortApplication.class, args);
        }
    
        @Override
        public void run(String... args) throws Exception {
            try{
                //  win
                SerialPortManager.connectSerialPort("COM1");
                //  linux centos
                //SerialPortManager.connectSerialPort("ttyS1");
            } catch (Exception e){
                System.out.println(e.toString());
            }
    
        }
    
        @PreDestroy
        public void destroy() {
            SerialPortManager.closeSerialPort();
        }
    
    
    }
    
    
    • 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

    SwaggerConfig

    package boot.example;
    
    import com.google.common.base.Predicates;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import springfox.documentation.builders.ApiInfoBuilder;
    import springfox.documentation.builders.PathSelectors;
    import springfox.documentation.builders.RequestHandlerSelectors;
    import springfox.documentation.service.ApiInfo;
    import springfox.documentation.spi.DocumentationType;
    import springfox.documentation.spring.web.plugins.Docket;
    import springfox.documentation.swagger2.annotations.EnableSwagger2;
    
    /**
     *  蚂蚁舞
     */
    @Configuration
    @EnableSwagger2
    public class SwaggerConfig {
    
        @Bean
        public Docket createRestApi(){
            return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select()
                    .apis(RequestHandlerSelectors.any()).paths(PathSelectors.any())
                    .paths(Predicates.not(PathSelectors.regex("/error.*")))
                    .paths(PathSelectors.regex("/.*"))
                    .build().apiInfo(apiInfo());
        }
    
        private ApiInfo apiInfo(){
            return new ApiInfoBuilder()
                    .title("SpringBoot+jSerialComm实现Java串口通信 读取串口数据以及发送数据")
                    .description("测试接口")
                    .version("0.01")
                    .build();
        }
    
    }
    
    
    • 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

    SerialPortController

    package boot.example.controller;
    
    import boot.example.serialport.ConvertHexStrAndStrUtils;
    import boot.example.serialport.SerialPortManager;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.*;
    import java.util.List;
    
    /**
     *  蚂蚁舞
     */
    @Controller
    @RequestMapping("/serialPort")
    public class SerialPortController {
    
        @GetMapping("/list")
        @ResponseBody
        public List<String> listPorts() {
            List<String> portList = SerialPortManager.getSerialPortList();
            if(!portList.isEmpty()){
                return portList;
            }
            return null;
        }
    
    
        @PostMapping("/send/{hexData}")
        @ResponseBody
        public String sendPorts(@PathVariable("hexData") String hexData) {
            if (SerialPortManager.SERIAL_PORT_STATE){
                SerialPortManager.sendSerialPortData(ConvertHexStrAndStrUtils.hexStrToBytes(hexData));
                return "success";
            }
            return "fail";
        }
    
    
    
    }
    
    
    • 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

    ConvertHexStrAndStrUtils

    package boot.example.serialport;
    
    
    import java.nio.charset.StandardCharsets;
    
    /**
     *  蚂蚁舞
     */
    public class ConvertHexStrAndStrUtils {
    
        private static final char[] HEXES = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
    
        public static String bytesToHexStr(byte[] bytes) {
            if (bytes == null || bytes.length == 0) {
                return null;
            }
            StringBuilder hex = new StringBuilder(bytes.length * 2);
            for (byte b : bytes) {
                hex.append(HEXES[(b >> 4) & 0x0F]);
                hex.append(HEXES[b & 0x0F]);
            }
            return hex.toString().toUpperCase();
        }
    
        public static byte[] hexStrToBytes(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;
        }
    
        public static String strToHexStr(String str) {
            StringBuilder sb = new StringBuilder();
            byte[] bs = str.getBytes();
            int bit;
            for (int i = 0; i < bs.length; i++) {
                bit = (bs[i] & 0x0f0) >> 4;
                sb.append(HEXES[bit]);
                bit = bs[i] & 0x0f;
                sb.append(HEXES[bit]);
            }
            return sb.toString().trim();
        }
    
        public static String hexStrToStr(String hexStr) {
            //能被16整除,肯定可以被2整除
            byte[] array = new byte[hexStr.length() / 2];
            try {
                for (int i = 0; i < array.length; i++) {
                    array[i] = (byte) (0xff & Integer.parseInt(hexStr.substring(i * 2, i * 2 + 2), 16));
                }
                hexStr = new String(array, StandardCharsets.UTF_8);
            } catch (Exception e) {
                e.printStackTrace();
                return "";
            }
            return hexStr;
        }
    
    }
    
    
    
    
    • 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

    SerialPortManager

    package boot.example.serialport;
    
    import com.fazecast.jSerialComm.SerialPort;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.TimeUnit;
    import java.util.stream.Collectors;
    
    /**
     *  蚂蚁舞
     */
    public class SerialPortManager {
    
        public static final int SERIAL_BAUD_RATE = 115200;
    
        public static volatile boolean SERIAL_PORT_STATE = false;
    
        public static volatile SerialPort SERIAL_PORT_OBJECT = null;
    
        //查找所有可用端口
        public static List<String> getSerialPortList() {
            // 获得当前所有可用串口
            SerialPort[] serialPorts = SerialPort.getCommPorts();
            List<String> portNameList = new ArrayList<String>();
            // 将可用串口名添加到List并返回该List
            for(SerialPort serialPort:serialPorts) {
                System.out.println(serialPort.getSystemPortName());
                portNameList.add(serialPort.getSystemPortName());
            }
            //去重
            portNameList = portNameList.stream().distinct().collect(Collectors.toList());
            return portNameList;
        }
    
        //  连接串口
        public static void connectSerialPort(String portName){
            try {
                SerialPort serialPort = SerialPortManager.openSerialPort(portName, SERIAL_BAUD_RATE);
                TimeUnit.MILLISECONDS.sleep(2000);
                //给当前串口对象设置监听器
                serialPort.addDataListener(new SerialPortListener(new SerialPortCallback()));
                if(serialPort.isOpen()) {
                    SERIAL_PORT_OBJECT = serialPort;
                    SERIAL_PORT_STATE = true;
                    System.out.println(portName+"-- start success");
                }
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
    
    
        //  打开串口
        public static SerialPort openSerialPort(String portName, Integer baudRate) {
            SerialPort serialPort = SerialPort.getCommPort(portName);
            if (baudRate != null) {
                serialPort.setBaudRate(baudRate);
            }
            if (!serialPort.isOpen()) {  //开启串口
                serialPort.openPort(1000);
            }else{
                return serialPort;
            }
            serialPort.setFlowControl(SerialPort.FLOW_CONTROL_DISABLED);
            serialPort.setComPortParameters(baudRate, 8, SerialPort.ONE_STOP_BIT, SerialPort.NO_PARITY);
            serialPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING | SerialPort.TIMEOUT_WRITE_BLOCKING, 1000, 1000);
            return serialPort;
        }
    
        //  关闭串口
        public static void closeSerialPort() {
            if (SERIAL_PORT_OBJECT != null && SERIAL_PORT_OBJECT.isOpen()){
                SERIAL_PORT_OBJECT.closePort();
                SERIAL_PORT_STATE = false;
                SERIAL_PORT_OBJECT = null;
            }
        }
    
        //  发送字节数组
        public static void sendSerialPortData(byte[] content) {
            if (SERIAL_PORT_OBJECT != null && SERIAL_PORT_OBJECT.isOpen()){
                SERIAL_PORT_OBJECT.writeBytes(content, content.length);
            }
        }
    
        //  读取字节数组
        public static byte[] readSerialPortData() {
            if (SERIAL_PORT_OBJECT != null && SERIAL_PORT_OBJECT.isOpen()){
                byte[] reslutData = null;
                try {
                    if (!SERIAL_PORT_OBJECT.isOpen()){return null;};
                    int i=0;
                    while (SERIAL_PORT_OBJECT.bytesAvailable() > 0 && i++ < 5) Thread.sleep(20);
                    byte[] readBuffer = new byte[SERIAL_PORT_OBJECT.bytesAvailable()];
                    int numRead = SERIAL_PORT_OBJECT.readBytes(readBuffer, readBuffer.length);
                    if (numRead > 0) {
                        reslutData = readBuffer;
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return reslutData;
            }
            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

    SerialPortListener

    package boot.example.serialport;
    
    
    import com.fazecast.jSerialComm.SerialPort;
    import com.fazecast.jSerialComm.SerialPortDataListener;
    import com.fazecast.jSerialComm.SerialPortEvent;
    
    /**
     *  蚂蚁舞
     */
    public class SerialPortListener implements SerialPortDataListener {
    
        private final SerialPortCallback serialPortCallback;
    
        public SerialPortListener(SerialPortCallback serialPortCallback) {
            this.serialPortCallback = serialPortCallback;
        }
    
        @Override
        public int getListeningEvents() { //必须是return这个才会开启串口工具的监听
            return SerialPort.LISTENING_EVENT_DATA_AVAILABLE;
        }
    
        @Override
        public void serialEvent(SerialPortEvent serialPortEvent) {
            if (serialPortCallback != null) {
                serialPortCallback.dataAvailable();
            }
        }
    }
    
    
    
    • 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

    SerialPortCallback

    package boot.example.serialport;
    
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    /**
     *  蚂蚁舞
     */
    public class SerialPortCallback {
    
        public void dataAvailable() {
            try {
                //当前监听器监听到的串口返回数据 back
                byte[] back = SerialPortManager.readSerialPortData();
                System.out.println("back-"+(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()))+"--"+ConvertHexStrAndStrUtils.bytesToHexStr(back));
                String s = ConvertHexStrAndStrUtils.bytesToHexStr(back);
                System.out.println("rev--data:"+s);
                //throw new Exception();
            } catch (Exception e) {
                System.out.println(e.toString());
            }
        }
    }
    
    
    • 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

    项目结构
    myw

    demo使用的波特率是115200 其他参数就默认的就好,一般只有波特率改动

    启动项目和启动com工具(项目和com之间使用的是com1和com2虚拟串口 虚拟串口有工具的,比如Configure Virtual Serial Port Driver)
    myw
    可以看到com1和com2都已经在使用 应用程序用的com1端口 com工具用的com2端口,这样的虚拟串口工具可以模拟调试使用的 应用程序通过com1向com2发送数据 ,com工具通过com2向com1的应用程序发送数据,全双工双向的,如此可以测试了。

    访问地址

    http://localhost:24810/doc.html

    查看当前的串口 win系统下的两个虚拟串口
    myw
    通过虚拟串口发送数据到com工具
    myw
    通过com工具查看收到的数据已经发送数据给应用程序
    myw
    控制台收到数据
    myw
    记录着,将来用得着。

  • 相关阅读:
    mysql错误处理:Error 1067 (42000): Invalid default value for ‘created_at‘
    实践分享:vue模块化基本用法
    OKR目前应用到过哪些企业?
    获取本地json文件
    [自制操作系统] 第17回 编写键盘驱动
    带你了解树的全家桶(BST树到AVL树到B树到B+树)
    【LeetCode每日一题】——905.按奇偶排序数组
    “蔚来杯“2022牛客暑期多校训练营9 I题: The Great Wall II
    C++day6
    LeetCode19.删除链表的倒数第N个结点
  • 原文地址:https://blog.csdn.net/myyhtw/article/details/131778934