赞
踩
参考 Java实现串口通信_我不吃芹菜的博客-CSDN博客_java 串口
java 串口通讯,直接控制报警灯的灯亮和播放音乐。
报警灯接口文档:接收16进制数组 。
报警灯指令文档:
工具方法: hexToByte () 把16进制 转成 bit,传参会用到。
- public static byte hexToByte(String arg) {
- int val = Integer.valueOf(arg, 16).intValue();
- byte c = (byte) (val & 0xff);
- return c;
- }
实现类 Chuankou.java
- package com.hs.server;
-
- import com.hs.util.NumberUtils;
- import gnu.io.*;
- import lombok.extern.slf4j.Slf4j;
-
- import java.io.IOException;
- import java.io.OutputStream;
- import java.util.Arrays;
- import java.util.Enumeration;
-
- /**
- * 串口通讯 modbus 485
- */
- @Slf4j
- public class ChuanKou {
- public static SerialPort port = null;
- /**
- * 打开电脑上指定的串口
- *
- * @param portName 端口名称,如 COM1,为 null 时,默认使用电脑中能用的端口中的第一个
- * @param b 波特率(baudrate),如 9600
- * @param d 数据位(datebits),如 SerialPort.DATABITS_8 = 8
- * @param s 停止位(stopbits),如 SerialPort.STOPBITS_1 = 1
- * @param p 校验位 (parity),如 SerialPort.PARITY_NONE = 0
- * @return 打开的串口对象,打开失败时,返回 null
- */
- public static final SerialPort openComPort(String portName, int b, int d, int s, int p) {
- Enumeration<CommPortIdentifier> portList = CommPortIdentifier.getPortIdentifiers();
- CommPort commPort = null;
- try {
- //当没有传入可用的 com 口时,默认使用电脑中可用的 com 口中的第一个
- // if (portName == null || "".equals(portName)) {
- // List<String> comPortList = findSystemAllComPort();
- // if (comPortList != null && comPortList.size() > 0) {
- // portName = comPortList.get(0);
- // }
- // }
- log.info("开始打开串口:portName=" + portName + ",baudrate=" + b + ",datebits=" + d + ",stopbits=" + s + ",parity=" + p);
-
- //通过端口名称识别指定 COM 端口
- CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);
- /**
- * open(String TheOwner, int i):打开端口
- * TheOwner 自定义一个端口名称,随便自定义即可
- * i:打开的端口的超时时间,单位毫秒,超时则抛出异常:PortInUseException if in use.
- * 如果此时串口已经被占用,则抛出异常:gnu.io.PortInUseException: Unknown Application
- */
- commPort = portIdentifier.open(portName, 5000);
- /**
- * 判断端口是不是串口
- * public abstract class SerialPort extends CommPort
- */
- if (commPort instanceof SerialPort) {
- SerialPort serialPort = (SerialPort) commPort;
- port = serialPort;
- /**
- * 设置串口参数:setSerialPortParams( int b, int d, int s, int p )
- * b:波特率(baudrate)
- * d:数据位(datebits),SerialPort 支持 5,6,7,8
- * s:停止位(stopbits),SerialPort 支持 1,2,3
- * p:校验位 (parity),SerialPort 支持 0,1,2,3,4
- * 如果参数设置错误,则抛出异常:gnu.io.UnsupportedCommOperationException: Invalid Parameter
- * 此时必须关闭串口,否则下次 portIdentifier.open 时会打不开串口,因为已经被占用
- */
- serialPort.setSerialPortParams(b, d, s, p);
- log.info("打开串口 " + portName + " 成功...");
- return serialPort;
- } else {
- log.error("当前端口 " + commPort.getName() + " 不是串口...");
- }
- } catch (NoSuchPortException e) {
- log.info("NoSuchPortException === ");
- e.printStackTrace();
- } catch (PortInUseException e) {
- log.warn("串口 " + portName + " 已经被占用,请先解除占用...");
- e.printStackTrace();
- } catch (UnsupportedCommOperationException e) {
- log.warn("串口参数设置错误,关闭串口,数据位[5-8]、停止位[1-3]、验证位[0-4]...");
- e.printStackTrace();
- if (commPort != null) {//此时必须关闭串口,否则下次 portIdentifier.open 时会打不开串口,因为已经被占用
- commPort.close();
- }
- }
- log.error("打开串口 " + portName + " 失败...");
- return null;
- }
-
- /**
- * 往串口发送数据
- *
- * @param serialPort 串口对象
- */
- public static void sendDataToComPort(SerialPort serialPort, byte[] orders) {
- OutputStream outputStream = null;
- try {
- if (serialPort != null) {
- outputStream = serialPort.getOutputStream();
- outputStream.write(orders);
- outputStream.flush();
- log.info("往串口 " + serialPort.getName() + " 发送数据:" + Arrays.toString(orders) + " 完成...");
- } else {
- log.error("gnu.io.SerialPort 为null,取消数据发送...");
- }
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- if (outputStream != null) {
- try {
- outputStream.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
- /**
- * 关闭串口
- *
- * @param serialPort 待关闭的串口对象
- */
- public static void closeComPort(SerialPort serialPort) {
- if (serialPort != null) {
- serialPort.close();
- log.info("关闭串口 " + serialPort.getName());
- }else{
- log.info("串口未关闭,串口为空");
- }
- }
-
- public static void main(String[] args) {
- String string = Integer.toHexString(31);
- System.out.println(string);
- // SerialPort serialPort = ChuanKou.openComPort("COM7", 9600, 8, 1, 502);
- // byte[] orders = {01,06,31,03,00,04};
- // ChuanKou.sendDataToComPort(serialPort,orders);
- System.out.println(Integer.parseInt(string,16));;
- }
-
- public static void WARN(String com){
- if(com==null){
- com="COM7";
- }
- SerialPort serialPort = ChuanKou.openComPort(com, 9600, 8, 1, 0);
- byte[] orders = {NumberUtils.hexToByte("FF"),
- NumberUtils.hexToByte("06"),
- NumberUtils.hexToByte("11"),
- NumberUtils.hexToByte("03"),
- NumberUtils.hexToByte("00"),
- NumberUtils.hexToByte("04"),
- NumberUtils.hexToByte("68"),
- NumberUtils.hexToByte("EB")};
- ChuanKou.sendDataToComPort(serialPort,orders);
- ChuanKou.closeComPort(ChuanKou.port);
-
- }
-
-
- }

遇到的问题及解决
一、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
dll和jar包传送门:
链接:https://pan.baidu.com/s/1cdMxM-x1P6TWmZgPNuoFIQ
提取码:afva
如图:
文件传送门
链接:https://pan.baidu.com/s/1b_3aufETiBnv2bv5zDeLLw
提取码:41f4
二、 jdk版本不合适
# A fatal error has been detected by the Java Runtime Environment:
java version "1.8.0_341"
Java(TM) SE Runtime EnvironmSee problematic frame for where to report the bug.
解决:jdk使用1.8.031版本。
相关附件传送门:
链接:https://pan.baidu.com/s/1VYjca_iTOklvcJrxHYWxkA
提取码:y961
补充:获取校验码,传入参数的前几位,获取后两位的校验码,每次换前面的参数都要重新获取校验码。比如选择绿灯红灯还是爆闪常亮。
- /**
- * 获取校验码
- * crc16 X16+x15+x2+1
- * 16进制报文是 02 03 00 00 00 40 CRC16
- * 传输的str:“020300000040”
- * 结果:4409
- * @param str
- * @return
- */
- public static String getCRC(String str) {
- byte[] bytes = NumberUtils.hexStringToBytes(str);
- int CRC = 0x0000ffff;
- int POLYNOMIAL = 0x0000a001;
-
- int i, j;
- for (i = 0; i < bytes.length; i++) {
- CRC ^= ((int) bytes[i] & 0x000000ff);
- for (j = 0; j < 8; j++) {
- if ((CRC & 0x00000001) != 0) {
- CRC >>= 1;
- CRC ^= POLYNOMIAL;
- } else {
- CRC >>= 1;
- }
- }
- }
- String crc = Integer.toHexString(CRC);
- if (crc.length() == 2) {
- crc = "00" + crc;
- } else if (crc.length() == 3) {
- crc = "0" + crc;
- }
- crc = crc.substring(2, 4) + crc.substring(0, 2);
- return crc.toUpperCase();
- }

拓展:
控制报警灯亮的时间的方法有两种:
一是选择想要播放时间长的音乐文件
二是用程序控制,亮灯指令和关灯指令,中间休息想要的时间。
- public static void WARN(String com){
- if(com==null){
- com="COM7";
- }
- SerialPort serialPort = ChuanKou.openComPort(com, 9600, 8, 1, 0);
- byte[] orders = {NumberUtils.hexToByte("FF"),
- NumberUtils.hexToByte("06"),
- NumberUtils.hexToByte("31"),
- NumberUtils.hexToByte("03"),
- NumberUtils.hexToByte("00"),
- NumberUtils.hexToByte("04"),
- NumberUtils.hexToByte("63"),
- NumberUtils.hexToByte("2B")};
- ChuanKou.sendDataToComPort(serialPort,orders);//制定串口发送指令
- ChuanKou.closeComPort(ChuanKou.port);//关闭报警灯
-
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。