package com.XXX.utils; import com.databus.Log; import gnu.io.*; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.*; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; public class RS485Demo extends Thread implements SerialPortEventListener { //单例模式提供连接串口的对象 private static RS485Demo getInstance(){ if (cRead == null){ synchronized (RS485Demo.class) { if (cRead == null) { cRead = new RS485Demo(); // 启动线程来处理收到的数据 cRead.start(); } } } return cRead; } // 封装十六进制的打开、关闭命令 private static final List<byte[]> onOrderList = Arrays.asList( new byte[]{0x01, 0x05, 0x00, 0x00, (byte) 0xFF, 0x00, (byte) 0x8C, 0x3A}, new byte[]{0x01, 0x05, 0x00, 0x01, (byte) 0xFF, 0x00, (byte) 0xDD, (byte)0xFA}, new byte[]{0x01, 0x05, 0x00, 0x02, (byte) 0xFF, 0x00, (byte) 0x2D, (byte)0xFA}, new byte[]{0x01, 0x05, 0x00, 0x03, (byte) 0xFF, 0x00, (byte) 0x7C, 0x3A}, new byte[]{0x01, 0x05, 0x00, 0x04, (byte) 0xFF, 0x00, (byte) 0xCD,(byte) 0xFB}, new byte[]{0x01, 0x05, 0x00, 0x05, (byte) 0xFF, 0x00, (byte) 0x9C, 0x3B}, new byte[]{0x01, 0x05, 0x00, 0x06, (byte) 0xFF, 0x00, (byte) 0x6C, 0x3B}, new byte[]{0x01, 0x05, 0x00, 0x07, (byte) 0xFF, 0x00, 0x3D, (byte)0xFB}); private static final List<byte[]> offOrderList = Arrays.asList( new byte[]{0x01, 0x05, 0x00, 0x00, 0x00, 0x00, (byte) 0xCD, (byte)0xCA},new byte[]{0x01, 0x05, 0x00, 0x01, 0x00, 0x00, (byte) 0x9C, (byte)0x0A}, new byte[]{0x01, 0x05, 0x00, 0x02, 0x00, 0x00, (byte) 0x6C, (byte)0x0A},new byte[]{0x01, 0x05, 0x00, 0x03, 0x00, 0x00, (byte) 0x3D, (byte)0xCA}, new byte[]{0x01, 0x05, 0x00, 0x04, 0x00, 0x00, (byte) 0x8C, (byte)0x0B},new byte[]{0x01, 0x05, 0x00, 0x05, 0x00, 0x00, (byte) 0xDD, (byte)0xCB}, new byte[]{0x01, 0x05, 0x00, 0x06, 0x00, 0x00, (byte) 0x2D, (byte)0xCB},new byte[]{0x01, 0x05, 0x00, 0x07, 0x00, 0x00, (byte) 0x7C, (byte)0x0B}); // 监听器,这里独立开辟一个线程监听串口数据 // 串口通信管理类 static CommPortIdentifier portId; static RS485Demo cRead = null; //USB在主机上的通信端口名称,如:COM1、COM2等 static String COMNUM = ""; static Enumeration<?> portList; InputStream inputStream; // 从串口来的输入流 static OutputStream outputStream;// 向串口输出的流 static SerialPort serialPort; // 串口的引用 // 堵塞队列用来存放读到的数据 private BlockingQueue<String> msgQueue = new LinkedBlockingQueue<String>(); / * SerialPort EventListene 的方法,持续监听端口上是否有数据流 */ 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 = RS485Demo.readFromPort(serialPort); String needData = printHexString(readBuffer); System.out.println(new Date() + "真实收到的数据为:-----" + needData); availableBytes = inputStream.available(); msgQueue.add(needData); } } catch (IOException e) { } default: break; } } / * 从串口读取数据 * * @param serialPort 当前已建立连接的SerialPort对象 * @return 读取到的数据 */ public static byte[] readFromPort(SerialPort serialPort) { InputStream in = null; byte[] bytes = {}; try { in = serialPort.getInputStream(); // 缓冲区大小为一个字节 byte[] readBuffer = new byte[1]; int bytesNum = in.read(readBuffer); while (bytesNum > 0) { bytes = concat(bytes, readBuffer); bytesNum = in.read(readBuffer); } } catch (IOException e) { e.printStackTrace(); } finally { try { if (in != null) { in.close(); in = null; } } catch (IOException e) { e.printStackTrace(); } } return bytes; } / * 通过程序打开COM串口,设置监听器以及相关的参数 * @return 返回1 表示端口打开成功,返回 0表示端口打开失败 */ public int startComPort() { // 通过串口通信管理类获得当前连接上的串口列表 try { Log.info("开始获取串口。。。"); portList = CommPortIdentifier.getPortIdentifiers(); Log.info("获取串口。。。" + portList); Log.info("获取串口结果。。。" + portList.hasMoreElements()); while (portList.hasMoreElements()) { // 获取相应串口对象 Log.info(portList.nextElement()); portId = (CommPortIdentifier) portList.nextElement(); System.out.println("设备类型:--->" + portId.getPortType()); System.out.println("设备名称:---->" + portId.getName()); // 判断端口类型是否为串口 if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) { // 判断如果COM4串口存在,就打开该串口 // if (portId.getName().equals(portId.getName())) { if (portId.getName().equals(COMNUM)) { try { // 打开串口名字为COM_4(名字任意),延迟为1000毫秒 serialPort = (SerialPort) portId.open(portId.getName(), 1000); } catch (PortInUseException e) { System.out.println("打开端口失败!"); e.printStackTrace(); return 0; } // 设置当前串口的输入输出流 try { inputStream = serialPort.getInputStream(); outputStream = serialPort.getOutputStream(); } catch (IOException e) { e.printStackTrace(); return 0; } // 给当前串口添加一个监听器,serialEvent方法监听串口返回的数据 try { serialPort.addEventListener(this); } catch (TooManyListenersException e) { e.printStackTrace(); return 0; } // 设置监听器生效,即:当有数据时通知 serialPort.notifyOnDataAvailable(true); // 设置串口的一些读写参数 try { // 比特率、数据位、停止位、奇偶校验位 serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); } catch (UnsupportedCommOperationException e) { e.printStackTrace(); return 0; } return 1; } } } }catch (Exception e){ e.printStackTrace(); Log.info(e); return 0; } return 0; } @Override public void run() { // TODO Auto-generated method stub try { System.out.println("--------------任务处理线程运行了--------------"); while (true) { // 如果堵塞队列中存在数据就将其输出 try { if (msgQueue.size() > 0) { String vo = msgQueue.peek(); String vos[] = vo.split(" ", -1); //根据返回数据可以做相应的业务逻辑操作 // getData(vos); // sendOrder(); msgQueue.take(); } }catch (Exception e){ e.printStackTrace(); } } } catch (Exception e) { e.printStackTrace(); } } // 16转10计算 public long getNum(String num1, String num2) { long value = Long.parseLong(num1, 16) * 256 + Long.parseLong(num2, 16); return value; } // 字节数组转字符串 private String printHexString(byte[] b) { StringBuffer sbf = new StringBuffer(); for (int i = 0; i < b.length; i++) { String hex = Integer.toHexString(b[i] & 0xFF); if (hex.length() == 1) { hex = '0' + hex; } sbf.append(hex.toUpperCase() + " "); } return sbf.toString().trim(); } / * 合并数组 * * @param firstArray 第一个数组 * @param secondArray 第二个数组 * @return 合并后的数组 */ public static byte[] concat(byte[] firstArray, byte[] secondArray) { if (firstArray == null || secondArray == null) { if (firstArray != null) return firstArray; if (secondArray != null) return secondArray; return null; } byte[] bytes = new byte[firstArray.length + secondArray.length]; System.arraycopy(firstArray, 0, bytes, 0, firstArray.length); System.arraycopy(secondArray, 0, bytes, firstArray.length, secondArray.length); return bytes; } //num:偶数启动报警器,奇数关闭报警器 //commandInfo:偶数打开,奇数关闭;channel:继电器通道;comNum:串口设备通信名称 public static void startRS485(int commandInfo,int channel,String comNum) { try { if(cRead == null){ cRead = getInstance(); } if (!COMNUM.equals(comNum) && null != serialPort){ serialPort.close(); COMNUM = comNum; } int i = 1; if (serialPort == null){ COMNUM = comNum; //打开串口通道并连接 i = cRead.startComPort(); } if (i == 1){ Log.info("串口连接成功"); try { //根据提供的文档给出的发送命令,发送16进制数据给仪器 byte[] b; if (commandInfo % 2 == 0) { b = onOrderList.get(channel); }else{ b = offOrderList.get(channel); } System.out.println("发送的数据:" + b); System.out.println("发出字节数:" + b.length); outputStream.write(b); outputStream.flush(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (outputStream != null) { outputStream.close(); } } catch (IOException e) { e.printStackTrace(); } //每次调用完以后关闭串口通道 if (null != cRead){ if (null != serialPort){ serialPort.close(); serialPort = null; } cRead.interrupt(); cRead = null; } } }else{ Log.info("串口连接失败"); return; } }catch (Exception e){ e.printStackTrace(); Log.info("串口连接失败"); } } public static void main(String[] args) { //打开通道1的电路,对应设备名称COM3 startRS485(0,1,"COM3"); } }
版权声明:
本文来源网络,所有图片文章版权属于原作者,如有侵权,联系删除。
本文网址:https://www.bianchenghao6.com/java-jiao-cheng/16677.html