Java 串口通信(RS232/485),Java串口通信(RS232与RS485协议)

马肤

温馨提示:这篇文章已超过424天没有更新,请注意相关的内容是否还可用!

摘要:Java支持串口通信,包括RS232和RS485协议。通过Java的串口通信API,开发者可以实现与设备的串行数据传输。这种通信方式广泛应用于数据传输、设备控制等领域。Java串口通信具有灵活性高、可靠性强的特点,可以方便地实现与各种设备的连接和数据交换。

Java 串口通信(RS232/485)

  • 一.串口通信页面
  • 二.串口服务实现
    • 1.Java 串口通信配置
      • 1.扩展包和依赖库
      • 2.Pom配置
      • 2.启动类
      • 3.工具包类
        • 1.Common
        • 2.Crc16Modbus
        • 3.SerialUtil
        • 4.WebSocket 配置
          • 1.启动配置
          • 2.监听配置
          • 5.UI交互类
            • 1.串口配置对象
            • 2.串口信息获取接口
            • 3.RS232接口
            • 4.RS485接口
            • 6.串口配置类
              • 1.串口配置
              • 2.RS232串口配置
              • 3.RS232串口监听
              • 4.RS485串口配置
              • 5.RS485串口监听
              • 三.UI代码
              • 四.测试效果
                • 1.串口通信
                • 2.CRC16通信

                  一.串口通信页面

                  Java 串口通信(RS232/485),Java串口通信(RS232与RS485协议) 第1张

                  Java 实现串口通信,同时通过 WebSocket 与 UI 实时交互传递通信数据

                  准备工作:

                  虚拟串口工具:Launch Virtual Serial Port Driver

                  串口调试助手:SSCOM

                  Java 串口通信(RS232/485),Java串口通信(RS232与RS485协议) 第2张

                  RS485

                  根据 Modbus 协议,常规485通讯的信息发送形式如下:
                  地址  功能码 数据信息 校验码
                  1byte 1byte  nbyte  2byte
                  

                  在线 CRC检验码计算:CRC 测试链接

                  二.串口服务实现

                  1.Java 串口通信配置

                  1.扩展包和依赖库

                  RXTXcomm.jar   放入 {JAVA_HOME}/jre/lib/ext
                  rxtxserial.dll 放入 {JAVA_HOME}/jre/bin
                  

                  以上两个包可以直接网上下载,注意和JDK版本搭配即可

                  2.Pom配置

                  串口通信包:rxtx

                  
                      4.0.0
                      org.example
                      SerialPort
                      1.0-SNAPSHOT
                      
                          8
                          8
                          UTF-8
                      
                      
                          
                              org.springframework.boot
                              spring-boot-starter-web
                              2.7.4
                          
                          
                              org.projectlombok
                              lombok
                              1.18.24
                          
                          
                              org.springframework
                              spring-websocket
                              5.3.27
                          
                          
                              org.rxtx
                              rxtx
                              2.1.7
                          
                      
                      
                          
                              nexus-aliyun
                              nexus-aliyun
                              http://maven.aliyun.com/nexus/content/groups/public/
                              
                                  true
                              
                              
                                  false
                              
                          
                      
                      
                          
                              public
                              aliyun nexus
                              http://maven.aliyun.com/nexus/content/groups/public/
                              
                                  true
                              
                              
                                  false
                              
                          
                      
                  
                  

                  2.启动类

                  package com.serial.demo;
                  import org.springframework.boot.SpringApplication;
                  import org.springframework.boot.autoconfigure.SpringBootApplication;
                  /**
                   * @author
                   * @date 2023-07-01 12:41
                   * @since 1.8
                   */
                  @SpringBootApplication
                  public class SerialApplication {
                      public static void main(String[] args) {
                          SpringApplication.run(SerialApplication.class,args);
                      }
                  }
                  

                  3.工具包类

                  1.Common

                  package com.serial.demo.util;
                  /**
                   * @author
                   * @date 2023-07-03 22:17
                   * @since 1.8
                   */
                  public class Common {
                      public static String HEX_STRING = "0123456789ABCDEF";
                      public static final String NONE = "无";
                      public static final String ODD = "奇";
                      public static final String EVEN = "偶";
                      public static final String FORMAT_HEX="HEX";
                  }
                  

                  2.Crc16Modbus

                  CRC16 Modbus Java 实现:计算数据的校验码
                  
                  package com.serial.demo.util;
                  /**
                   * @author
                   * @date 2023-07-04 20:37
                   * @since 1.8
                   */
                  public class Crc16Modbus {
                      /**
                       * CRC 循环冗余校验 即通过生成多项式对原始数据进行计算,将计算结果拼接到数据上一起发送
                       *     接收方计算接收到的数据校验接收结果是否准确
                       * CRC 即对生成多项式的模二运算
                       *
                       * 1.预置1个16位的寄存器为十六进制 FFFF(即全为1),称此寄存器为CRC寄存器
                       * 2.把第1个8位二进制数据(帧头字节)与 CRC 寄存器的低8位相异或并写回寄存器 高8位数据不变
                       * 3.把 CRC 循环右移 高位补 0 取得移出位
                       * 4.如果移出位为 0 继续右移 如果移出位为 1 则 CRC 寄存器与多项式 A001(1010 0000 0000 0001)进行异或运算
                       * 5.重复步骤 3 和 4 直到右移 8 次
                       * 6.重复步骤 2 到 5 进行数据帧下一个字节的处理 直到将数据帧所有字节按上述步骤计算
                       * 7.根据需要将寄存器的高、低字节进行交换 得到最终 CRC码
                       *
                       */
                      /**
                       * 初始值 CRC-16 寄存器
                       */
                      private static final int INITIAL_VALUE = 0xFFFF;
                      private static final boolean IS_OUT_PUT_OVER_TURN = true;
                      /**
                       * 原始数据 + CRC码
                       *
                       * @param hexes 16 进制字符串
                       * @return
                       */
                      public static byte[] getData(String... hexes) {
                          byte[] data = new byte[hexes.length];
                          int i = 0;
                          for (String hex:hexes){
                              //先转为数字在转为 byte
                              data[i++] = (byte) Integer.parseInt(hex, 16);
                          }
                          return merge(data);
                      }
                      /**
                       * 原始数据 + CRC码
                       *
                       * @param data
                       * @return
                       */
                      public static byte[] merge(byte[] data) {
                          byte[] crc = getCrc16(data);
                          int dLen = data.length;
                          int cLen = crc.length;
                          byte[] result = new byte[dLen + cLen];
                          System.arraycopy(data,0,result,0,dLen);
                          System.arraycopy(crc,0,result,dLen,cLen);
                          return result;
                      }
                      /**
                       * 基于 CRC16 Modbus 计算校验码
                       * CRC 16 Modbus 默认多项式为 x16+x15+x2+1 => 8005 反转即 A001
                       *
                       * @param data
                       * @return
                       */
                      private static byte[] getCrc16(byte[] data) {
                          int len = data.length;
                          int crc = INITIAL_VALUE;
                          int i, j;
                          for (i = 0; i  0) {
                                      // 如果移出位为 1, CRC寄存器与多项式A001进行异或
                                      crc = crc >> 1;
                                      crc = crc ^ 0xA001;
                                  } else {
                                      // 如果移出位为 0,再次右移一位
                                      crc = crc >> 1;
                                  }
                              }
                          }
                          return intToBytes(crc);
                      }
                      /**
                       * 将 int 转换成 byte 数组 低位在前 高位在后
                       */
                      private static byte[] intToBytes(int value)  {
                          byte[] src = new byte[2];
                          byte hig = (byte) ((value>>8) & 0xFF);
                          byte low = (byte) (value & 0xFF);
                          if (IS_OUT_PUT_OVER_TURN){
                              src[0] = low;
                              src[1] = hig;
                          } else {
                              src[0] = hig;
                              src[1] = low;
                          }
                          return src;
                      }
                      /**
                       * 将字节数组转换成十六进制字符串
                       */
                      public static String byteTo16String(byte[] data) {
                          StringBuffer buffer = new StringBuffer();
                          for (byte b : data) {
                              byteToHex(buffer,b);
                          }
                          return buffer.toString().toUpperCase();
                      }
                      /**
                       * 将字节转换成十六进制字符串
                       *
                       * int 转 byte 对照表
                       * [128,255],0,[1,128)
                       * [-128,-1],0,[1,128)
                       */
                      public static void byteToHex(StringBuffer buffer ,byte b) {
                          if (b  0 && b 
                              buffer.append("0" + Integer.toString(b, 16));
                          } else if (b  15) {
                              buffer.append(Integer.toString(b, 16));
                          }
                          buffer.append(" ");
                      }
                  }
                  

                  3.SerialUtil

                  package com.serial.demo.util;
                  import gnu.io.SerialPort;
                  import java.io.ByteArrayOutputStream;
                  import java.io.IOException;
                  import java.io.InputStream;
                  import java.nio.charset.StandardCharsets;
                  /**
                   * @author
                   * @date 2023-07-03 21:52
                   * @since 1.8
                   */
                  public class SerialUtil {
                      /**
                       * 转为 HEX
                       * @param str
                       * @return
                       */
                      public static String toHex(String str){
                          StringBuffer sbf = new StringBuffer();
                          byte[] b = str.getBytes(StandardCharsets.UTF_8);
                          for (int i = 0; i  
                  

                  4.WebSocket 配置

                  1.启动配置

                  package com.serial.demo.socket;
                  import org.springframework.context.annotation.Bean;
                  import org.springframework.context.annotation.Configuration;
                  import org.springframework.web.socket.server.standard.ServerEndpointExporter;
                  /**
                   * @author
                   * @date 2023-07-02 21:05
                   * @since 1.8
                   */
                  @Configuration
                  public class WebSocketConfig {
                      /**
                       * 开启 websocket 配置
                       * @return
                       */
                      @Bean
                      public ServerEndpointExporter serverEndpointExporter(){
                          return new ServerEndpointExporter();
                      }
                  }
                  

                  2.监听配置

                  package com.serial.demo.socket;
                  import lombok.extern.slf4j.Slf4j;
                  import org.springframework.stereotype.Component;
                  import javax.websocket.OnClose;
                  import javax.websocket.OnMessage;
                  import javax.websocket.OnOpen;
                  import javax.websocket.Session;
                  import javax.websocket.server.PathParam;
                  import javax.websocket.server.ServerEndpoint;
                  import java.io.IOException;
                  import java.util.Map;
                  import java.util.concurrent.ConcurrentHashMap;
                  /**
                   * @author
                   * @date 2023-07-02 21:07
                   * @since 1.8
                   */
                  @Slf4j
                  @Component
                  @ServerEndpoint("/websocket/{sid}")
                  public class SerialWebSocket {
                      /**
                       * 缓存通信实例
                       */
                      private static Map webSocketMap = new ConcurrentHashMap(16);
                      /**
                       * 会话
                       */
                      private Session session;
                      /**
                       * 标识
                       */
                      private String sid;
                      /**
                       * 建立连接
                       * @param sid
                       * @param session
                       */
                      @OnOpen
                      public void onOpen(@PathParam("sid") String sid,Session session){
                          this.session = session;
                          this.sid = sid;
                          webSocketMap.put(sid,this);
                          //sendMessage(sid,"Hello:");
                      }
                      /**
                       * 关闭连接
                       * @param sid
                       */
                      @OnClose
                      public void onClose(@PathParam("sid") String sid){
                          try {
                              SerialWebSocket socket = webSocketMap.remove(sid);
                              if (socket != null){
                                  socket.session.close();
                                  socket = null;
                              }
                          } catch (IOException e) {
                              log.error("Close {} exception:",sid,e);
                          }
                      }
                      /**
                       * 接收消息
                       * @param message
                       */
                      @OnMessage
                      public void onMessage(String message){
                          log.info("sid {} msg {}",this.sid,message);
                      }
                      /**
                       * 发送消息
                       * @param message
                       * @param sid
                       */
                      public static void sendMessage(String sid,String message){
                          SerialWebSocket socket = webSocketMap.get(sid);
                          if (socket != null){
                              try {
                                  socket.session.getBasicRemote().sendText(message);
                              } catch (IOException e) {
                                  log.error("Send {} message {} exception:",sid,message,e);
                              }
                          }
                      }
                      /**
                       * 广播消息
                       * @param message
                       */
                      public static void broadcast(String message){
                          for (String sid:webSocketMap.keySet()){
                              sendMessage(sid,message);
                          }
                      }
                  }
                  

                  5.UI交互类

                  1.串口配置对象

                  package com.serial.demo.entity;
                  import lombok.Data;
                  /**
                   * @author
                   * @date 2023-07-02 22:58
                   * @since 1.8
                   */
                  @Data
                  public class SerialEntity {
                      private String portId;
                      private int bitRate;
                      private int dataBit;
                      private int stopBit;
                      private String checkBit;
                      private String format;
                  }
                  

                  2.串口信息获取接口

                  package com.serial.demo.controller;
                  import com.serial.demo.config.SerialPortConfig;
                  import com.serial.demo.util.SerialUtil;
                  import org.springframework.beans.factory.annotation.Autowired;
                  import org.springframework.web.bind.annotation.CrossOrigin;
                  import org.springframework.web.bind.annotation.GetMapping;
                  import org.springframework.web.bind.annotation.RequestMapping;
                  import org.springframework.web.bind.annotation.RestController;
                  import java.util.List;
                  /**
                   * @author
                   * @date 2023-07-01 16:37
                   * @since 1.8
                   */
                  @CrossOrigin
                  @RestController
                  @RequestMapping("/serial")
                  public class SerialController {
                      @Autowired
                      SerialPortConfig serial;
                      /**
                       * 获取端口列表
                       * @return
                       */
                      @GetMapping("/getSerialPortList")
                      public List getSerialPortList(){
                          return serial.getSerialPortList();
                      }
                      /**
                       * 字符串 转 HEX
                       * @return
                       */
                      @GetMapping("/toHex")
                      public String toHex(String str){
                          return SerialUtil.toHex(str);
                      }
                      /**
                       * HEX 转 字符串
                       * @return
                       */
                      @GetMapping("/toStr")
                      public String toStr(String hex){
                          return SerialUtil.toStr(hex);
                      }
                  }
                  

                  3.RS232接口

                  package com.serial.demo.controller;
                  import com.serial.demo.config.Rs232Config;
                  import com.serial.demo.entity.SerialEntity;
                  import org.springframework.beans.factory.annotation.Autowired;
                  import org.springframework.web.bind.annotation.*;
                  /**
                   * @author
                   * @date 2023-07-03 1:03
                   * @since 1.8
                   */
                  @CrossOrigin
                  @RestController
                  @RequestMapping("/serial/232")
                  public class Rs232Controller {
                      @Autowired
                      Rs232Config rs232Config;
                      /**
                       * 监听端口
                       * @param serial
                       */
                      @PostMapping("/open")
                      public boolean open(@RequestBody SerialEntity serial){
                          return rs232Config.openPort(serial);
                      }
                      /**
                       * 获取端口列表
                       * @return
                       */
                      @GetMapping("/close/{portId}")
                      public void close(@PathVariable("portId") String portId){
                          rs232Config.closePort(portId);
                      }
                      /**
                       * 获取端口列表
                       * @return
                       */
                      @GetMapping("/send/{portId}/{format}/{msg}")
                      public void close(@PathVariable("portId") String portId,@PathVariable("format") String format,@PathVariable("msg") String msg){
                          rs232Config.sendData(portId,format,msg);
                      }
                  }
                  

                  4.RS485接口

                  package com.serial.demo.controller;
                  import com.serial.demo.config.Rs485Config;
                  import com.serial.demo.entity.SerialEntity;
                  import org.springframework.beans.factory.annotation.Autowired;
                  import org.springframework.web.bind.annotation.*;
                  /**
                   * @author
                   * @date 2023-07-03 23:33
                   * @since 1.8
                   */
                  @CrossOrigin
                  @RestController
                  @RequestMapping("/serial/485")
                  public class Rs485Controller {
                      @Autowired
                      Rs485Config rs485Config;
                      /**
                       * 监听端口
                       * @param serial
                       */
                      @PostMapping("/open")
                      public boolean open(@RequestBody SerialEntity serial){
                          return rs485Config.openPort(serial);
                      }
                      /**
                       * 获取端口列表
                       * @return
                       */
                      @GetMapping("/close/{portId}")
                      public void close(@PathVariable("portId") String portId){
                          rs485Config.closePort(portId);
                      }
                      /**
                       * 获取端口列表
                       * @return
                       */
                      @GetMapping("/send/{portId}/{format}/{msg}")
                      public void close(@PathVariable("portId") String portId,@PathVariable("format") String format,@PathVariable("msg") String msg){
                          rs485Config.sendData(portId,format,msg);
                      }
                  }
                  

                  6.串口配置类

                  1.串口配置

                  package com.serial.demo.config;
                  import gnu.io.CommPortIdentifier;
                  import lombok.extern.slf4j.Slf4j;
                  import org.springframework.stereotype.Component;
                  import javax.annotation.PostConstruct;
                  import java.util.Collections;
                  import java.util.Enumeration;
                  import java.util.List;
                  import java.util.Map;
                  import java.util.concurrent.ConcurrentHashMap;
                  import java.util.stream.Collectors;
                  /**
                   * @author
                   * @date 2023-07-03 1:01
                   * @since 1.8
                   */
                  @Slf4j
                  @Component
                  public class SerialPortConfig {
                      /**
                       * 缓存端口信息
                       */
                      private static Map serialMap;
                      @PostConstruct
                      private void init(){
                          refreshCom();
                      }
                      /**
                       * 刷新端口
                       */
                      public void refreshCom(){
                          Enumeration portList = CommPortIdentifier.getPortIdentifiers();
                          CommPortIdentifier serial;
                          Map temp = new ConcurrentHashMap(16);
                          while (portList.hasMoreElements()){
                              serial = portList.nextElement();
                              if (serial.getPortType() == CommPortIdentifier.PORT_SERIAL){
                                  temp.put(serial.getName(),serial);
                              }
                          }
                          serialMap = Collections.unmodifiableMap(temp);
                      }
                      /**
                       * 获取端口列表
                       * @return
                       */
                      public List getSerialPortList(){
                          return serialMap.keySet().stream().sorted().collect(Collectors.toList());
                      }
                      /**
                       * 获取串口
                       * @return
                       */
                      public Map getSerialMap(){
                          return serialMap;
                      }
                  }
                  

                  2.RS232串口配置

                  package com.serial.demo.config;
                  import com.serial.demo.entity.SerialEntity;
                  import com.serial.demo.util.Common;
                  import com.serial.demo.util.SerialUtil;
                  import gnu.io.CommPortIdentifier;
                  import gnu.io.PortInUseException;
                  import gnu.io.SerialPort;
                  import gnu.io.UnsupportedCommOperationException;
                  import lombok.extern.slf4j.Slf4j;
                  import org.springframework.beans.factory.annotation.Autowired;
                  import org.springframework.stereotype.Component;
                  import java.io.IOException;
                  import java.io.InputStream;
                  import java.io.OutputStream;
                  import java.nio.charset.StandardCharsets;
                  import java.util.Map;
                  import java.util.TooManyListenersException;
                  import java.util.concurrent.ConcurrentHashMap;
                  /**
                   * @author
                   * @date 2023-07-01 16:22
                   * @since 1.8
                   */
                  @Slf4j
                  @Component
                  public class Rs232Config {
                      private static final int DELAY_TIME = 1000;
                      @Autowired
                      SerialPortConfig config;
                      /**
                       * 缓存端口实例
                       */
                      private Map serialPortMap = new ConcurrentHashMap(16);
                      /**
                       * 监听端口
                       * @param serial
                       */
                      public boolean openPort(SerialEntity serial) {
                          String portId = serial.getPortId();
                          CommPortIdentifier commPortIdentifier = config.getSerialMap().get(portId);
                          if (null != commPortIdentifier){
                              SerialPort serialPort = null;
                              int bitRate = 0,dataBit = 0,stopBit = 0,parity = 0;
                              try {
                                  serialPort = (SerialPort) commPortIdentifier.open(portId,DELAY_TIME);
                                  // 设置监听器生效 当有数据时通知
                                  serialPort.notifyOnDataAvailable(true);
                                  // 比特率、数据位、停止位、奇偶校验位
                                  bitRate = serial.getBitRate();
                                  dataBit = serial.getDataBit();
                                  stopBit = serial.getStopBit();
                                  parity = SerialUtil.getParity(serial.getCheckBit());
                                  serialPort.setSerialPortParams(bitRate, dataBit, stopBit,parity);
                              } catch (PortInUseException e) {
                                  log.error("Open CommPortIdentifier {} Exception:",serial.getPortId(),e );
                                  return false;
                              } catch (UnsupportedCommOperationException e) {
                                  log.error("Set SerialPortParams BitRate {} DataBit {} StopBit {} Parity {} Exception:",bitRate,dataBit,stopBit,parity,e);
                                  return false;
                              }
                              // 设置当前串口的输入输出流
                              InputStream input;
                              OutputStream output;
                              try {
                                  input = serialPort.getInputStream();
                                  output = serialPort.getOutputStream();
                              } catch (IOException e) {
                                  log.error("Get serialPort data stream exception:",e);
                                  return false;
                              }
                              // 给当前串口添加一个监听器
                              try {
                                  serialPort.addEventListener(new Serial232Listener(input,output,serial.getFormat()));
                              } catch (TooManyListenersException e) {
                                  log.error("Get serialPort data stream exception:",e);
                                  return false;
                              }
                              serialPortMap.put(portId,serialPort);
                              return true;
                          }
                          return false;
                      }
                      /**
                       * 关闭端口
                       * @param portId
                       */
                      public void closePort(String portId){
                          SerialPort serialPort = serialPortMap.remove(portId);
                          if (null != serialPort){
                              serialPort.close();
                          }
                      }
                      /**
                       * 发送数据
                       * @param portId
                       * @param format
                       * @param message
                       */
                      public void sendData(String portId,String format,String message){
                          SerialPort serialPort = serialPortMap.get(portId);
                          if (null == serialPort){
                              return;
                          }
                          OutputStream output = null;
                          try {
                              byte[] bytes;
                              if (Common.FORMAT_HEX.equals(format)){
                                  bytes = SerialUtil.hexToByte(message);
                              } else {
                                  bytes = message.getBytes(StandardCharsets.UTF_8);
                              }
                              output = serialPort.getOutputStream();
                              output.write(bytes);
                              output.flush();
                          } catch (IOException e) {
                              throw new RuntimeException(e);
                          } finally {
                              if (null != output){
                                  try {
                                      output.close();
                                  } catch (IOException e) {
                                      throw new RuntimeException(e);
                                  }
                              }
                          }
                      }
                  }
                  

                  3.RS232串口监听

                  package com.serial.demo.config;
                  import com.serial.demo.socket.SerialWebSocket;
                  import com.serial.demo.util.Crc16Modbus;
                  import com.serial.demo.util.SerialUtil;
                  import gnu.io.SerialPortEvent;
                  import gnu.io.SerialPortEventListener;
                  import java.io.IOException;
                  import java.io.InputStream;
                  import java.io.OutputStream;
                  /**
                   * @author
                   * @date 2023-07-01 17:06
                   * @since 1.8
                   */
                  public class Serial232Listener implements SerialPortEventListener {
                      InputStream inputStream;
                      OutputStream outputStream;
                      String format;
                      public Serial232Listener(InputStream input, OutputStream output, String format){
                          inputStream = input;
                          outputStream = output;
                          this.format = format;
                      }
                      @Override
                      public void serialEvent(SerialPortEvent event) {
                          switch (event.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:
                                  // 当有可用数据时读取数据
                                  byte[] readBuffer = null;
                                  int availableBytes = 0;
                                  try {
                                      availableBytes = inputStream.available();
                                      while (availableBytes > 0) {
                                          readBuffer = SerialUtil.readFromPort(inputStream);
                                          String needData = Crc16Modbus.byteTo16String(readBuffer);
                                          SerialWebSocket.broadcast(needData);
                                          availableBytes = inputStream.available();
                                      }
                                  } catch (IOException e) {
                                  }
                              default:
                                  break;
                          }
                      }
                  }
                  

                  4.RS485串口配置

                  package com.serial.demo.config;
                  import com.serial.demo.entity.SerialEntity;
                  import com.serial.demo.util.Common;
                  import com.serial.demo.util.Crc16Modbus;
                  import com.serial.demo.util.SerialUtil;
                  import gnu.io.CommPortIdentifier;
                  import gnu.io.PortInUseException;
                  import gnu.io.SerialPort;
                  import gnu.io.UnsupportedCommOperationException;
                  import lombok.extern.slf4j.Slf4j;
                  import org.springframework.beans.factory.annotation.Autowired;
                  import org.springframework.stereotype.Component;
                  import java.io.IOException;
                  import java.io.InputStream;
                  import java.io.OutputStream;
                  import java.nio.charset.StandardCharsets;
                  import java.util.Map;
                  import java.util.TooManyListenersException;
                  import java.util.concurrent.ConcurrentHashMap;
                  /**
                   * @author
                   * @date 2023-07-03 1:00
                   * @since 1.8
                   */
                  @Slf4j
                  @Component
                  public class Rs485Config {
                      private static final int DELAY_TIME = 1000;
                      @Autowired
                      SerialPortConfig config;
                      /**
                       * 缓存端口实例
                       */
                      private Map serialPortMap = new ConcurrentHashMap(16);
                      /**
                       * 监听端口
                       * @param serial
                       */
                      public boolean openPort(SerialEntity serial) {
                          String portId = serial.getPortId();
                          CommPortIdentifier commPortIdentifier = config.getSerialMap().get(portId);
                          if (null != commPortIdentifier){
                              SerialPort serialPort;
                              int bitRate = 0,dataBit = 0,stopBit = 0,parity = 0;
                              try {
                                  serialPort = (SerialPort) commPortIdentifier.open(portId,DELAY_TIME);
                                  // 设置监听器生效 当有数据时通知
                                  serialPort.notifyOnDataAvailable(true);
                                  serialPort.setDTR(true);
                                  serialPort.setRTS(true);
                                  // 比特率、数据位、停止位、奇偶校验位
                                  bitRate = serial.getBitRate();
                                  dataBit = serial.getDataBit();
                                  stopBit = serial.getStopBit();
                                  parity = SerialUtil.getParity(serial.getCheckBit());
                                  serialPort.setSerialPortParams(bitRate, dataBit, stopBit,parity);
                              } catch (PortInUseException e) {
                                  log.error("Open CommPortIdentifier {} Exception:",serial.getPortId(),e );
                                  return false;
                              } catch (UnsupportedCommOperationException e) {
                                  log.error("Set SerialPortParams BitRate {} DataBit {} StopBit {} Parity {} Exception:",bitRate,dataBit,stopBit,parity,e);
                                  return false;
                              }
                              // 设置当前串口的输入输出流
                              InputStream input;
                              OutputStream output;
                              try {
                                  input = serialPort.getInputStream();
                                  output = serialPort.getOutputStream();
                              } catch (IOException e) {
                                  log.error("Get serialPort data stream exception:",e);
                                  return false;
                              }
                              // 给当前串口添加一个监听器
                              try {
                                  serialPort.addEventListener(new Serial485Listener(input,output,serial.getFormat()));
                              } catch (TooManyListenersException e) {
                                  log.error("Get serialPort data stream exception:",e);
                                  return false;
                              }
                              serialPortMap.put(portId,serialPort);
                              return true;
                          }
                          return false;
                      }
                      /**
                       * 关闭端口
                       * @param portId
                       */
                      public void closePort(String portId){
                          SerialPort serialPort = serialPortMap.remove(portId);
                          if (null != serialPort){
                              serialPort.close();
                          }
                      }
                      /**
                       * 发送数据
                       * @param portId
                       * @param format
                       * @param message
                       */
                      public void sendData(String portId,String format,String message){
                          SerialPort serialPort = serialPortMap.get(portId);
                          if (null == serialPort){
                              return;
                          }
                          OutputStream output = null;
                          try {
                              byte[] bytes = new byte[0];
                              if (Common.FORMAT_HEX.equals(format)){
                                  bytes = SerialUtil.hexToByte(message);
                                  bytes = Crc16Modbus.merge(bytes);
                              }
                              output = serialPort.getOutputStream();
                              output.write(bytes);
                              output.flush();
                          } catch (IOException e) {
                              throw new RuntimeException(e);
                          } finally {
                              if (null != output){
                                  try {
                                      output.close();
                                  } catch (IOException e) {
                                      throw new RuntimeException(e);
                                  }
                              }
                          }
                      }
                  }
                  

                  5.RS485串口监听

                  package com.serial.demo.config;
                  import com.serial.demo.socket.SerialWebSocket;
                  import com.serial.demo.util.Crc16Modbus;
                  import com.serial.demo.util.SerialUtil;
                  import gnu.io.SerialPortEvent;
                  import gnu.io.SerialPortEventListener;
                  import java.io.IOException;
                  import java.io.InputStream;
                  import java.io.OutputStream;
                  /**
                   * @author
                   * @date 2023-07-03 23:21
                   * @since 1.8
                   */
                  public class Serial485Listener implements SerialPortEventListener {
                      InputStream inputStream;
                      OutputStream outputStream;
                      String format;
                      public Serial485Listener(InputStream input, OutputStream output, String format){
                          inputStream = input;
                          outputStream = output;
                          this.format = format;
                      }
                      @Override
                      public void serialEvent(SerialPortEvent event) {
                          switch (event.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:
                                  // 当有可用数据时读取数据
                                  byte[] readBuffer = null;
                                  int availableBytes = 0;
                                  try {
                                      availableBytes = inputStream.available();
                                      while (availableBytes > 0) {
                                          readBuffer = SerialUtil.readFromPort(inputStream);
                                          String needData = printHexString(readBuffer);
                                          SerialWebSocket.broadcast(needData);
                                          availableBytes = inputStream.available();
                                      }
                                  } catch (IOException e) {
                                  }
                              default:
                                  break;
                          }
                      }
                      /**
                       * 转为 16 进制字符串
                       * @param b
                       * @return
                       */
                      public static String printHexString(byte[] b) {
                          return Crc16Modbus.byteTo16String(b);
                      }
                  }
                  

                  三.UI代码

                  
                      
                          
                          
                          
                          Serial Communication
                          
                          
                          
                          
                              .btn-group{
                                  display: inline-block;
                              }
                              .left {
                                  width: 300px;
                                  height: 500px;
                                  float: left;
                              }
                              .right {
                                  width: calc(100% - 330px);
                                  height: 500px;
                                  margin-left: 300px;
                              }
                              .configSelect{
                                  width: 100%;
                              }
                              .bk{
                                  border-color: #D5DBDB;
                                  background-color: #1E1E1E;
                                  margin: 1px;
                              }
                              .bkw{
                                  border-color: #D5DBDB;
                                  background-color: #1E1E1E;
                                  margin: 1px;
                                  border-left: none;
                                  border-right: none;
                                  border-bottom: none;
                                  border-top: none;
                              }
                              select{
                                  background-color: #3C3C3C;
                                  color: white;
                              }
                              button{
                                  background-color: #3C3C3C;
                                  color: white;
                                  cursor: pointer;
                              }
                          
                      
                      
                          
                  串口配置
                  端口
                  波特率
                  数据位
                  停止位
                  校验位
                  操作打开串口
                  RS485
                  RS485
                  接收区设置
                  数据格式
                  停止显示
                  清空接收区
                  保存到文件
                  WebSocket
                  连接 断开 清空
                  发送
                  发送区设置
                  自动发送
                  数据格式
                  类型
                  发送发送数据
                  类型转换
                  字符串转HEX
                  HEX转字符串
                  STR HEX
                  function formatDate(now) { var year = now.getFullYear(); var month = now.getMonth() + 1; var date = now.getDate(); var hour = now.getHours(); var minute = now.getMinutes(); var second = now.getSeconds(); return year + "-" + (month = month ' + message); websocket.send(message); } function writeToScreen(message) { var div = "" + message + ""; var d = $("#output"); var d = d[0]; var doScroll = d.scrollTop == d.scrollHeight - d.clientHeight; $("#output").append(div); if (doScroll) { d.scrollTop = d.scrollHeight - d.clientHeight; } } function en(event) { var evt = evt ? evt : (window.event ? window.event : null); if (evt.keyCode == 13) { doSend() } } var http = "http://localhost:8080/serial"; var httpSerial = "http://localhost:8080/serial/232"; function getSerialPortList(){ $("#serialPortList").html(''); $.ajax({url:http + "/getSerialPortList",success:function(result){ for (var i in result) { $("#serialPortList").append("

0
收藏0
文章版权声明:除非注明,否则均为VPS857原创文章,转载或复制请以超链接形式并注明出处。

相关阅读

  • 【研发日记】Matlab/Simulink自动生成代码(二)——五种选择结构实现方法,Matlab/Simulink自动生成代码的五种选择结构实现方法(二),Matlab/Simulink自动生成代码的五种选择结构实现方法详解(二)
  • 超级好用的C++实用库之跨平台实用方法,跨平台实用方法的C++实用库超好用指南,C++跨平台实用库使用指南,超好用实用方法集合,C++跨平台实用库超好用指南,方法与技巧集合
  • 【动态规划】斐波那契数列模型(C++),斐波那契数列模型(C++实现与动态规划解析),斐波那契数列模型解析与C++实现(动态规划)
  • 【C++】,string类底层的模拟实现,C++中string类的模拟底层实现探究
  • uniapp 小程序实现微信授权登录(前端和后端),Uniapp小程序实现微信授权登录全流程(前端后端全攻略),Uniapp小程序微信授权登录全流程攻略,前端后端全指南
  • Vue脚手架的安装(保姆级教程),Vue脚手架保姆级安装教程,Vue脚手架保姆级安装指南,Vue脚手架保姆级安装指南,从零开始教你如何安装Vue脚手架
  • 如何在树莓派 Raspberry Pi中本地部署一个web站点并实现无公网IP远程访问,树莓派上本地部署Web站点及无公网IP远程访问指南,树莓派部署Web站点及无公网IP远程访问指南,本地部署与远程访问实践,树莓派部署Web站点及无公网IP远程访问实践指南,树莓派部署Web站点及无公网IP远程访问实践指南,本地部署与远程访问详解,树莓派部署Web站点及无公网IP远程访问实践详解,本地部署与远程访问指南,树莓派部署Web站点及无公网IP远程访问实践详解,本地部署与远程访问指南。
  • vue2技术栈实现AI问答机器人功能(流式与非流式两种接口方法),Vue2技术栈实现AI问答机器人功能,流式与非流式接口方法探究,Vue2技术栈实现AI问答机器人功能,流式与非流式接口方法详解
  • 发表评论

    快捷回复:表情:
    评论列表 (暂无评论,0人围观)

    还没有评论,来说两句吧...

    目录[+]

    取消
    微信二维码
    微信二维码
    支付宝二维码