• java 串口通讯


     参考 Java实现串口通信_我不吃芹菜的博客-CSDN博客_java 串口

     java 串口通讯,直接控制报警灯的灯亮和播放音乐。

    报警灯接口文档:接收16进制数组 。

    报警灯指令文档:

     工具方法: hexToByte ()   把16进制 转成 bit,传参会用到。

    1. public static byte hexToByte(String arg) {
    2. int val = Integer.valueOf(arg, 16).intValue();
    3. byte c = (byte) (val & 0xff);
    4. return c;
    5. }

    实现类 Chuankou.java

    1. package com.hs.server;
    2. import com.hs.util.NumberUtils;
    3. import gnu.io.*;
    4. import lombok.extern.slf4j.Slf4j;
    5. import java.io.IOException;
    6. import java.io.OutputStream;
    7. import java.util.Arrays;
    8. import java.util.Enumeration;
    9. /**
    10. * 串口通讯 modbus 485
    11. */
    12. @Slf4j
    13. public class ChuanKou {
    14. public static SerialPort port = null;
    15. /**
    16. * 打开电脑上指定的串口
    17. *
    18. * @param portName 端口名称,如 COM1,为 null 时,默认使用电脑中能用的端口中的第一个
    19. * @param b 波特率(baudrate),如 9600
    20. * @param d 数据位(datebits),如 SerialPort.DATABITS_8 = 8
    21. * @param s 停止位(stopbits),如 SerialPort.STOPBITS_1 = 1
    22. * @param p 校验位 (parity),如 SerialPort.PARITY_NONE = 0
    23. * @return 打开的串口对象,打开失败时,返回 null
    24. */
    25. public static final SerialPort openComPort(String portName, int b, int d, int s, int p) {
    26. Enumeration<CommPortIdentifier> portList = CommPortIdentifier.getPortIdentifiers();
    27. CommPort commPort = null;
    28. try {
    29. //当没有传入可用的 com 口时,默认使用电脑中可用的 com 口中的第一个
    30. // if (portName == null || "".equals(portName)) {
    31. // List<String> comPortList = findSystemAllComPort();
    32. // if (comPortList != null && comPortList.size() > 0) {
    33. // portName = comPortList.get(0);
    34. // }
    35. // }
    36. log.info("开始打开串口:portName=" + portName + ",baudrate=" + b + ",datebits=" + d + ",stopbits=" + s + ",parity=" + p);
    37. //通过端口名称识别指定 COM 端口
    38. CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);
    39. /**
    40. * open(String TheOwner, int i):打开端口
    41. * TheOwner 自定义一个端口名称,随便自定义即可
    42. * i:打开的端口的超时时间,单位毫秒,超时则抛出异常:PortInUseException if in use.
    43. * 如果此时串口已经被占用,则抛出异常:gnu.io.PortInUseException: Unknown Application
    44. */
    45. commPort = portIdentifier.open(portName, 5000);
    46. /**
    47. * 判断端口是不是串口
    48. * public abstract class SerialPort extends CommPort
    49. */
    50. if (commPort instanceof SerialPort) {
    51. SerialPort serialPort = (SerialPort) commPort;
    52. port = serialPort;
    53. /**
    54. * 设置串口参数:setSerialPortParams( int b, int d, int s, int p )
    55. * b:波特率(baudrate)
    56. * d:数据位(datebits),SerialPort 支持 5,6,7,8
    57. * s:停止位(stopbits),SerialPort 支持 1,2,3
    58. * p:校验位 (parity),SerialPort 支持 0,1,2,3,4
    59. * 如果参数设置错误,则抛出异常:gnu.io.UnsupportedCommOperationException: Invalid Parameter
    60. * 此时必须关闭串口,否则下次 portIdentifier.open 时会打不开串口,因为已经被占用
    61. */
    62. serialPort.setSerialPortParams(b, d, s, p);
    63. log.info("打开串口 " + portName + " 成功...");
    64. return serialPort;
    65. } else {
    66. log.error("当前端口 " + commPort.getName() + " 不是串口...");
    67. }
    68. } catch (NoSuchPortException e) {
    69. log.info("NoSuchPortException === ");
    70. e.printStackTrace();
    71. } catch (PortInUseException e) {
    72. log.warn("串口 " + portName + " 已经被占用,请先解除占用...");
    73. e.printStackTrace();
    74. } catch (UnsupportedCommOperationException e) {
    75. log.warn("串口参数设置错误,关闭串口,数据位[5-8]、停止位[1-3]、验证位[0-4]...");
    76. e.printStackTrace();
    77. if (commPort != null) {//此时必须关闭串口,否则下次 portIdentifier.open 时会打不开串口,因为已经被占用
    78. commPort.close();
    79. }
    80. }
    81. log.error("打开串口 " + portName + " 失败...");
    82. return null;
    83. }
    84. /**
    85. * 往串口发送数据
    86. *
    87. * @param serialPort 串口对象
    88. */
    89. public static void sendDataToComPort(SerialPort serialPort, byte[] orders) {
    90. OutputStream outputStream = null;
    91. try {
    92. if (serialPort != null) {
    93. outputStream = serialPort.getOutputStream();
    94. outputStream.write(orders);
    95. outputStream.flush();
    96. log.info("往串口 " + serialPort.getName() + " 发送数据:" + Arrays.toString(orders) + " 完成...");
    97. } else {
    98. log.error("gnu.io.SerialPort 为null,取消数据发送...");
    99. }
    100. } catch (IOException e) {
    101. e.printStackTrace();
    102. } finally {
    103. if (outputStream != null) {
    104. try {
    105. outputStream.close();
    106. } catch (IOException e) {
    107. e.printStackTrace();
    108. }
    109. }
    110. }
    111. }
    112. /**
    113. * 关闭串口
    114. *
    115. * @param serialPort 待关闭的串口对象
    116. */
    117. public static void closeComPort(SerialPort serialPort) {
    118. if (serialPort != null) {
    119. serialPort.close();
    120. log.info("关闭串口 " + serialPort.getName());
    121. }else{
    122. log.info("串口未关闭,串口为空");
    123. }
    124. }
    125. public static void main(String[] args) {
    126. String string = Integer.toHexString(31);
    127. System.out.println(string);
    128. // SerialPort serialPort = ChuanKou.openComPort("COM7", 9600, 8, 1, 502);
    129. // byte[] orders = {01,06,31,03,00,04};
    130. // ChuanKou.sendDataToComPort(serialPort,orders);
    131. System.out.println(Integer.parseInt(string,16));;
    132. }
    133. public static void WARN(String com){
    134. if(com==null){
    135. com="COM7";
    136. }
    137. SerialPort serialPort = ChuanKou.openComPort(com, 9600, 8, 1, 0);
    138. byte[] orders = {NumberUtils.hexToByte("FF"),
    139. NumberUtils.hexToByte("06"),
    140. NumberUtils.hexToByte("11"),
    141. NumberUtils.hexToByte("03"),
    142. NumberUtils.hexToByte("00"),
    143. NumberUtils.hexToByte("04"),
    144. NumberUtils.hexToByte("68"),
    145. NumberUtils.hexToByte("EB")};
    146. ChuanKou.sendDataToComPort(serialPort,orders);
    147. ChuanKou.closeComPort(ChuanKou.port);
    148. }
    149. }

    遇到的问题及解决

    一、java崩溃,原因缺少RXTXcomm.jar 包 和rxtxSerial.dll 配置

    no rxtxSerial64 in java.library.path thrown while loading gnu.io.RXTXCommDriver

    解决: 

    1、将rxtxParallel.dll和rxtxSerial.dll文件放到${JAVA_HOME}(jdk目录,不是jre目录)\jre\bin目录下

    如: C:\Program Files\Java\jdk1.8.0_31\jre\bin
    2、将RXTXcomm.jar 包放到{JAVA_HOME}jdk目录\jre\lib\ext目录下即可

    如:  C:\Program Files\Java\jdk1.8.0_31\jre\lib\ext

    如图:

    二、 jdk版本不合适

    # A fatal error has been detected by the Java Runtime Environment:

    java version "1.8.0_341"
    Java(TM) SE Runtime Environm

    See problematic frame for where to report the bug.

    解决:jdk使用1.8.031版本。 

    相关附件传送门:

    链接:https://pan.baidu.com/s/1OgZ-SxJwQ58riKx620P9Ew 
    提取码:jf98

    补充:获取校验码,传入参数的前几位,获取后两位的校验码,每次换前面的参数都要重新获取校验码。比如选择绿灯红灯还是爆闪常亮。

    1. /**
    2. * 获取校验码
    3. * crc16 X16+x15+x2+1
    4. * 16进制报文是 02 03 00 00 00 40 CRC16
    5. * 传输的str:“020300000040”
    6. * 结果:4409
    7. * @param str
    8. * @return
    9. */
    10. public static String getCRC(String str) {
    11. byte[] bytes = NumberUtils.hexStringToBytes(str);
    12. int CRC = 0x0000ffff;
    13. int POLYNOMIAL = 0x0000a001;
    14. int i, j;
    15. for (i = 0; i < bytes.length; i++) {
    16. CRC ^= ((int) bytes[i] & 0x000000ff);
    17. for (j = 0; j < 8; j++) {
    18. if ((CRC & 0x00000001) != 0) {
    19. CRC >>= 1;
    20. CRC ^= POLYNOMIAL;
    21. } else {
    22. CRC >>= 1;
    23. }
    24. }
    25. }
    26. String crc = Integer.toHexString(CRC);
    27. if (crc.length() == 2) {
    28. crc = "00" + crc;
    29. } else if (crc.length() == 3) {
    30. crc = "0" + crc;
    31. }
    32. crc = crc.substring(2, 4) + crc.substring(0, 2);
    33. return crc.toUpperCase();
    34. }

    拓展:

    控制报警灯亮的时间的方法有两种:

    一是选择想要播放时间长的音乐文件

    二是用程序控制,亮灯指令和关灯指令,中间休息想要的时间。 

    1. public static void WARN(String com){
    2. if(com==null){
    3. com="COM7";
    4. }
    5. SerialPort serialPort = ChuanKou.openComPort(com, 9600, 8, 1, 0);
    6. byte[] orders = {NumberUtils.hexToByte("FF"),
    7. NumberUtils.hexToByte("06"),
    8. NumberUtils.hexToByte("31"),
    9. NumberUtils.hexToByte("03"),
    10. NumberUtils.hexToByte("00"),
    11. NumberUtils.hexToByte("04"),
    12. NumberUtils.hexToByte("63"),
    13. NumberUtils.hexToByte("2B")};
    14. ChuanKou.sendDataToComPort(serialPort,orders);//制定串口发送指令
    15. ChuanKou.closeComPort(ChuanKou.port);//关闭报警灯
    16. }

  • 相关阅读:
    wstunnel (websocket模式ssh)
    python爬虫实战——抖音
    2023宁夏大学计算机考研信息汇总
    【SpringSecurity】SpringSecurity2.7.x 的使用(03)
    AotuDL中Linux环境下运行pix2pix-tensorflow的环境配置(tensorflow==1.8.0 python==3.6)
    mysql高阶语句(一)
    Linux基础内容(12)—— 程序地址空间
    使用Java实现一个简单的贪吃蛇小游戏
    uniapp——uniapp基础知识
    抢先看!阿里发布2023最新版分布式核心小册,GitHub标星破已千万
  • 原文地址:https://blog.csdn.net/somdip/article/details/126469213