Java串口编程控制硬件

  • 还是半年前接触的JAVA串口编程控制硬件,现在项目中又即将运用到,所以特别写成博客记录,同时分享交流。
  • Java环境中的JDK是本身不带有串口的jar包的,需要我们自己下载然后配置到本地的JDK之中,我们采用RXTX串口包(sun公司也提供了一个串口包但是十多年没更新了,不支持64位机器),RXTX是另外一个公司提供的,支持Windows和linux的。

官网下载地址:http://fizzed.com/oss/rxtx-for-java

在这里插入图片描述
自己选择版本下载压缩包,然后解压。我们这里用Windows64位的,解压后如下图
在这里插入图片描述
将这个配置到本地JDK中,步骤如下:
复制 RXTXcomm.jar —> <JAVA_HOME>\jre\lib\ext
复制 rxtxSerial.dll —> <JAVA_HOME>\jre\bin
复制 rxtxParallel.dll —> <JAVA_HOME>\jre\bin
注意:是JAVA_HOME里面的jdk目录,不是jre的目录
如我的是: 在这里插入图片描述
安装好本地JDK串口环境我们就可以在项目中使用了。

将需要控制的USB串口设备连接到你的电脑上,然后我们电脑上就会多一个串口,我们需要知道它的串口名字。

查看串口步骤:

计算机(我的电脑)–右键–管理–设备管理器–端口 如下图:
COM3就是我们插入的USB串口名字,我们在后面的代码中就是要根据这个COM3串口名对其进行硬件的控制。
在这里插入图片描述

import gnu.io.*;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;

/**
 * 警灯控制类 方法包括 init(PortName)初始化串口
 * closeSerialPort()关闭串口
 * openLamp(int second)开启警灯 到时间自动关闭
 * closeLamp()关闭警灯
 * <p>
 * 说明:无论是开启警灯和关闭警灯都需要先进行初始化串口
 */
// 注:串口操作类一定要实现SerialPortEventListener
public class lamp implements SerialPortEventListener {
    // 检测系统中可用的通讯端口类
    private CommPortIdentifier portId;
    // 枚举类型
    private Enumeration<CommPortIdentifier> portList;

    // RS232串口
    private SerialPort serialPort;

    // 输入输出流
    private InputStream inputStream;
    private OutputStream outputStream;

    //实现接口SerialPortEventListener中的方法
    @Override
    public void serialEvent(SerialPortEvent serialPortEvent) {
        switch (serialPortEvent.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:    //有数据到达
                break;
            default:
                break;
        }
    }

    /**
     * 初始化  需要把串口名传入
     */
    public String init(String PortName0) {
        //获取系统中所有的通讯端口
        portList = CommPortIdentifier.getPortIdentifiers();

        //把串口名进行优化,默认自动转成大写 让其传入值可忽略大小写
        String PortName = PortName0.toUpperCase();
        // 循环通讯端口
        while (portList.hasMoreElements()) {
            portId = portList.nextElement();
            // 判断是否是串口
            if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
                // 比较串口名称是否是我们所要的那个
                if (PortName.equals(portId.getName())) {
                    System.out.println("找到警灯串口" + PortName);
                    try {
                        //如果确实是我们需要的串口,则打开这个串口
                        // 并且需要转化成非抽象的serialPort类才能进行操作
                        serialPort = (SerialPort) portId.open(Object.class.getSimpleName(), 2000);
                        System.out.println("获取到警灯串口对象," + PortName);

                        //获取输入输出流
                        outputStream = serialPort.getOutputStream();
                        inputStream = serialPort.getInputStream();

                        // 设置串口通讯参数
                        // 波特率,数据位,停止位和校验方式
                        // 波特率2400,偶校验
                        serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8,//
                                SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);

                        return "初始化成功";
                    } catch (PortInUseException e) {
                        System.out.println("该串口已经被占用");
                    } catch (UnsupportedCommOperationException e) {
                        System.out.println("为发现该串口");
                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                }
            }
        }
        return null;
    }

    /**
     * 关闭串口
     */
    public void closeSerialPort() {
        if (serialPort != null) {
            serialPort.notifyOnDataAvailable(false);
            serialPort.removeEventListener();
            if (inputStream != null) {
                try {
                    inputStream.close();
                    inputStream = null;
                } catch (IOException e) {
                }
            }
            if (outputStream != null) {
                try {
                    outputStream.close();
                    outputStream = null;
                } catch (IOException e) {
                }
            }
            serialPort.close();
            System.out.println("串口已关闭");
            serialPort = null;
        }
    }
//------------------------------------下面是我自己写的,用来控制警灯的------------------------------------
     /**
 * 打开警灯 需要传入时间 单位:秒 当为0时则一直开启 不会自动关闭
 *
 * 到时间后警灯会自动关闭
 *
 * @param second
 */
public void openLamp(int second) {
    //如果传入时间为0则默认一直开启  不会自动关闭
   String msg = "FE050000FF009835";//要发送的命令msg
    try {
        outputStream.write(hexStringToBytes(msg));
        System.out.println("警灯已开启");
        if(second!=0){
            try {
                Thread.sleep(1000*second);
                closeLamp();
                System.out.println("警灯已关闭");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}
//控制硬件基本都是16+进制,发送指令的时候需要16进制转成字节数组
//将输入的16进制string转成字节
public static byte[] hexStringToBytes(String hexString) {
    if (hexString == null || hexString.equals("")) {
        return null;
    }
    hexString = hexString.toUpperCase();
    int length = hexString.length() / 2;
    char[] hexChars = hexString.toCharArray();
    byte[] d = new byte[length];
    for (int i = 0; i < length; i++) {
        int pos = i * 2;
        d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
    }
    return d;
}

private static byte charToByte(char c) {
    return (byte) "0123456789ABCDEF".indexOf(c);
}

/**
 * 关闭警灯
 *
 */
public void closeLamp() {
    //发送关闭警灯的命令
    String msg = "FE0500000000D9C5";
    try {

        outputStream.write(hexStringToBytes(msg));
    } catch (IOException e) {
        e.printStackTrace();
    }
    System.out.println("警灯已关闭");
}

//-----------------------------------自己写的结束------------------------------------
}

测试类:

	/**
	 *
	 * 警灯串口测试类
	 *
	 * */
	public class lampTest1{
	    public static void main(String[] args) {
	        //实例化串口对象
	        lamp lamp=new lamp();
	        //传入串口名进行初始化  忽略大小写
	        String com = lamp.init("com3");
	        if(com!=null &&!"".equals(com)){
	            //打开警灯 传入开启时间,到时间后自动关闭  单位为秒 如果为0则默认一直开启 不会自动关闭
	           lamp.openLamp(5);
	          // lamp.closeLamp();
	        }else {
	            System.out.println("初始化失败,请检查串口名是否错误或该串口是否存在");
	        }
	        lamp.closeSerialPort();
	    }
	}

注意:发送什么指令需要你根据硬件的产品说明书来!!!!,每个产品是不一样的

到此就完成了连接串口设备,并发送指定操作的程序,如果需要进一步操作,比如对设备返回的数据进行获取操作的话,继续下面代码

其他深入操作:

对串口读:

SerialPortSimpleRead类

/*
 * @(#)SimpleRead.java	1.12 98/06/25 SMI
 *
 * Copyright (c) 1998 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Sun grants you ("Licensee") a non-exclusive, royalty free, license
 * to use, modify and redistribute this software in source and binary
 * code form, provided that i) this copyright notice and license appear
 * on all copies of the software; and ii) Licensee does not utilize the
 * software in a manner which is disparaging to Sun.
 *
 * This software is provided "AS IS," without a warranty of any kind.
 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND
 * ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY
 * LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE
 * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS
 * BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
 * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES,
 * HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING
 * OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 *
 * This software is not designed or intended for use in on-line control
 * of aircraft, air traffic, aircraft navigation or aircraft
 * communications; or in the design, construction, operation or
 * maintenance of any nuclear facility. Licensee represents and
 * warrants that it will not use or redistribute the Software for such
 * purposes.
 */

import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.util.TooManyListenersException;

/**
 * * 该类用来接收串口数据,并在新线程中处理
 * * 使用时如果需要对接收的进行数据处理,必须重写serialEvent(SerialPortEvent event)方法
 * @author zhe
 *
 */
public class SerialPortSimpleRead implements Runnable, SerialPortEventListener {
	Logger logger = LoggerFactory.getLogger(this.getClass());
	InputStream inputStream;
	SerialPort serialPort;
	public Thread readThread;
	private boolean isSingleMessage = true;

	//回传对象
	SerialPortManager serialPortManager;

	private String readStr = "";

	//串口参数
	int bautrate;
	int SerialPort_DATABIT;
	int SerialPort_STOPBIT;
	int SerialPort_PARITY;
	/**
     * 创建读取串口对象
	 * @param serialPort 端口号的字符串,如:"COM5"
	 * @param serialPortManager
	 * @param isSingleMessage
	 */
	public SerialPortSimpleRead(SerialPort serialPort, SerialPortManager serialPortManager, boolean isSingleMessage) {

		System.out.println("创建接收对象");
		this.serialPort = serialPort;
		this.serialPortManager = serialPortManager;
		this.isSingleMessage = isSingleMessage;
		try {
			inputStream = serialPort.getInputStream();
		} catch (IOException e) {}
		try {
			serialPort.addEventListener(this);
		} catch (TooManyListenersException e) {

		}
		serialPort.notifyOnDataAvailable(true);
		//        try {
		//            serialPort.setSerialPortParams(115200,
		//                SerialPort.DATABITS_8,
		//                SerialPort.STOPBITS_1,
		//                SerialPort.PARITY_NONE);
		//        } catch (UnsupportedCommOperationException e) {}
		//readThread = new Thread(this);
		//readThread.start();
	}

	@Override
	public void run() {
		try {
			Thread.sleep(20000);
			logger.info("串口接收二十秒超时,退出……");
		} catch (InterruptedException e) {
			logger.error("InterruptedException", e);
		}
	}

	@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 = new byte[128];

			try {
				while (inputStream.available() > 0) {
					int numBytes = inputStream.read(readBuffer);
					byte[] realBytes = new byte[numBytes];
					System.arraycopy(readBuffer, 0, realBytes, 0, numBytes);
					String receivedStr = encode(realBytes);
					//单条消息通过回调就能处理
					if (isSingleMessage){
						serialPortManager.serialReadNotify(receivedStr);
						readStr = receivedStr;
					} else {//非单条消息定时处理
						readStr = readStr + receivedStr;
					}
				}
			} catch (IOException e) {
				logger.error("inputStream read error.", e);
			}
			break;
		}

	}
	public static String hexStringToString(String s) {
	    if (s == null || s.equals("")) {
	        return null;
	    }
	    s = s.replace(" ", "");
	    byte[] baKeyword = new byte[s.length() / 2];
	    for (int i = 0; i < baKeyword.length; i++) {
	        try {
	            baKeyword[i] = (byte) (0xff & Integer.parseInt(s.substring(i * 2, i * 2 + 2), 16));
	        } catch (Exception e) {
	            e.printStackTrace();
	        }
	    }
	    try {
	        s = new String(baKeyword, "UTF-8");
	        new String();
	    } catch (Exception e1) {
	        e1.printStackTrace();
	    }
	    return s;
	}
	/**
	 * 16进制数字字符集
	 */
	private static String hexString = "0123456789ABCDEF";
	/*
	 * 将字符串编码成16进制数字,适用于所有字符(包括中文)
	 */
	public static String encode(byte[] str) {
		// 根据默认编码获取字节数组
		byte[] bytes = str;
		StringBuilder sb = new StringBuilder(bytes.length * 2);
		// 将字节数组中每个字节拆解成2位16进制整数
		for (int i = 0; i < bytes.length; i++) {
			sb.append(hexString.charAt((bytes[i] & 0xf0) >> 4));
			sb.append(hexString.charAt((bytes[i] & 0x0f) >> 0));
		}
		return sb.toString();
	}
	/**
	 * 释放掉资源
	 */
	public void close(){

		if(readThread!=null){
			readThread.interrupt();;
			readThread = null;
		}
		if(serialPort!=null){
			serialPort.close();
			serialPort=null;
		}
		if(inputStream!=null){
			try {
				inputStream.close();
				inputStream = null;
			} catch (IOException e) {
				logger.error("inputStream.close error.", e);
			}
		}
	}

	public String getReadStr() {
		return readStr;
	}
	public void setReadStr(String readStr) {
		this.readStr = readStr;
	}

}

对串口写:

SerialPortSimpleWrite类

/*
 * @(#)SimpleWrite.java	1.12 98/06/25 SMI
 *
 * Copyright (c) 1998 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Sun grants you ("Licensee") a non-exclusive, royalty free, license
 * to use, modify and redistribute this software in source and binary
 * code form, provided that i) this copyright notice and license appear
 * on all copies of the software; and ii) Licensee does not utilize the
 * software in a manner which is disparaging to Sun.
 *
 * This software is provided "AS IS," without a warranty of any kind.
 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND
 * ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY
 * LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE
 * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS
 * BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
 * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES,
 * HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING
 * OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 *
 * This software is not designed or intended for use in on-line control
 * of aircraft, air traffic, aircraft navigation or aircraft
 * communications; or in the design, construction, operation or
 * maintenance of any nuclear facility. Licensee represents and
 * warrants that it will not use or redistribute the Software for such
 * purposes.
 */

import gnu.io.SerialPort;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;

public class SerialPortSimpleWrite {
	Logger logger = LoggerFactory.getLogger(this.getClass());
	SerialPort serialPort;
	public OutputStream outputStream;

	/**
	 * 创建串口写数据对象
	 * @param serialPort 窗口号字符串,如:"COM5"
	 */
	public SerialPortSimpleWrite(SerialPort serialPort) {
		//super();
		this.serialPort = serialPort;
		try {
			this.outputStream = serialPort.getOutputStream();
		} catch (IOException e) {
			logger.error("serialPort[{}] create SerialPortSimpleWrite error.", serialPort.getName(), e);
		}
	}


	/**
	 * 串口输出一个字符
	 * @param ch
	 */
	public void write(int ch){
		try {
			outputStream.write(ch);
		} catch (IOException e) {
			logger.error("serail write error.", e);
		}
	}
	/**
	 * 给下位机单片机发送一行字符
	 * @param datastr
	 */
	public void writeString(String datastr){

		try {
			outputStream.write(datastr.getBytes());
		} catch (IOException e) {
			logger.error("serail writeString error.", e);
		}
	}

	/**
	 * 发送字符串给STM32F4
	 * @param datastr
	 * @param loopdelay 下位机串口轮询的周期,单位ms
	 */
	public void writeStringToSTM32(String datastr, int loopdelay){
		try {
			datastr = datastr.replaceAll(" ", "");
			//发送
			logger.info("发送数据 data[{}], 16进制[{}] loopdelay[{}ms]", new String[]{ datastr, new String(hex2byte(datastr)), loopdelay + ""});
			outputStream.write(hex2byte(datastr));
			Thread.sleep(loopdelay);
		} catch (Exception e) {
			logger.error("writeStringToSTM32 error.", e);
		}
	}
	public static byte[] hex2byte(String hex) {
		String digital = "0123456789ABCDEF";
		String hex1 = hex.replace(" ", "");
		char[] hex2char = hex1.toCharArray();
		byte[] bytes = new byte[hex1.length() / 2];
		byte temp;
		for (int p = 0; p < bytes.length; p++) {
			temp = (byte) (digital.indexOf(hex2char[2 * p]) * 16);
			temp += digital.indexOf(hex2char[2 * p + 1]);
			bytes[p] = (byte) (temp & 0xff);
		}
		return bytes;
	}
	/**
	 * 发送文件给STM32,读出文本内容分行发给STM32
	 * @param file 要传送文本文件
	 * @param loopdelay
	 */
	public void writeFileToSTM32(final File file , final int loopdelay){

		Thread sendfileThread = new Thread(){
			public void run() {
				try {
					FileReader fr = new FileReader(file);
					BufferedReader br = new BufferedReader(fr);

					String line = null;
					while((line = br.readLine())!=null){
						System.out.println("发送:"+line);
						//发送一行
						writeStringToSTM32(line,loopdelay);
					}
					//发送结束标志"$$"
					SerialPortSimpleWrite.this.writeString("$$sendover");
					//延时
					Thread.sleep(loopdelay);

					br.close();

				} catch (Exception e) {

					e.printStackTrace();
				}

			}
		};

		sendfileThread.start();

	}


	/**
	 * 关闭串口资源
	 */
	public void close(){
		if(outputStream != null){
			try {
				outputStream.close();
				outputStream = null;
			} catch (IOException e) {
				logger.error("outputStream close error.", e);
			}
		}
		if(serialPort != null){
			serialPort.close();
		}
	}
}

管理串口数据收发的类:

SerialPortManager

import com.alibaba.fastjson.JSON;
import gnu.io.CommPortIdentifier;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.UnsupportedCommOperationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.TooManyListenersException;


/**
 * 该类是用来管理串口数据收发的类,通过该类的静态方法可以获取系统可识别的端口
 * 使用时如果需要对接收的数据进行处理,处理代码添加在getPortSimpleReadInstance()中的serialEvent(SerialPortEvent event)方法
 *
 *
 */
public abstract class SerialPortManager {
	static Logger logger = LoggerFactory.getLogger("serial");
	//定义串口收发变量
	private SerialPortSimpleRead portSimpleRead;
	private SerialPortSimpleWrite portSimpleWrite;

	@SuppressWarnings("rawtypes")
	static Enumeration portList;
	static CommPortIdentifier portId;
	static SerialPort serialPort;

	//通讯参数 默认值如下
	int bautrate = 9600;
	int serialPort_DATABIT = SerialPort.DATABITS_8;
	int serialPort_STOPBIT = SerialPort.STOPBITS_1;
	int serialPort_PARITY = SerialPort.PARITY_NONE;

	static{
		//获取系统COM列表
		portList = CommPortIdentifier.getPortIdentifiers();
	}

	/**
	 * 用指定参数构造
	 * @param comPort
	 * @param bautrate
	 * @param serialPort_DATABIT
	 * @param serialPort_STOPBIT
	 * @param serialPort_PARITY
	 */
	public SerialPortManager(String comPort, int bautrate, int serialPort_DATABIT,
                             int serialPort_STOPBIT, int serialPort_PARITY, boolean isSingleMessage, boolean isOpenReadThread, boolean isOpenWriteThread) {

		this.bautrate = bautrate;
		this.serialPort_DATABIT = serialPort_DATABIT;
		this.serialPort_STOPBIT = serialPort_STOPBIT;
		this.serialPort_PARITY = serialPort_PARITY;
		SerialPortManager.serialPort = openPort(comPort, isSingleMessage, isOpenReadThread, isOpenWriteThread);
	}

	/**
	 * 默认参数构造
	 * @param comPort
	 * @throws TooManyListenersException
	 */
	public SerialPortManager(String comPort, boolean isSingleMessage, boolean isOpenReadThread, boolean isOpenWriteThread) {
		super();
		//设置要管理的端口,打开串口
		SerialPortManager.serialPort = openPort(comPort, isSingleMessage, isOpenReadThread, isOpenWriteThread);
	}

	/**
	 * 以字符串集合的方式返回当前系统可识别的串口(COM)号
	 * @return 端口号的字符集合
	 */
	public synchronized static List<String> getAvailablePorts(){

		//重新获取系统COM列表
		portList = CommPortIdentifier.getPortIdentifiers();
		//列表保存成字符串集合
		List<String> portstrList = new ArrayList<>();
		//遍历集合
		while (portList.hasMoreElements()) {
			portId = (CommPortIdentifier) portList.nextElement();
			//如果端口是串口
			if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
				logger.info("获取到的串口ID[{}], info[{}]", portId.getName(), JSON.toJSONString(portId));
				//添加到集合
				portstrList.add(portId.getName());
			}
		}
		return portstrList;
	}

	/**
	 * 打开串口
	 * @param comPort 端口号字符串 ,如:"COM5"
	 * @return 返回打开的串口
	 */
	private synchronized SerialPort openPort(String comPort, boolean isSingleMessage, boolean isOpenReadThread, boolean isOpenWriteThread){
		//重新获取系统COM列表
		portList = CommPortIdentifier.getPortIdentifiers();
		if(portList.hasMoreElements()!=true){
			logger.error("打开端口失败,检测不到串口[{}]", comPort);
			return null;
		}

		SerialPort serialPort = null;
		//遍历集合
		while (portList.hasMoreElements()) {
			portId = (CommPortIdentifier) portList.nextElement();
			if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {

				logger.info("获取到的串口[{}]", portId.getName());
				if (portId.getName().equals(comPort)){
					try {
						serialPort = (SerialPort) portId.open("SerialPortManager", 2000);
						serialPort.setSerialPortParams(this.bautrate,
								this.serialPort_DATABIT,
								this.serialPort_STOPBIT,
								this.serialPort_PARITY);
					} catch (PortInUseException e) {
						logger.error("串口[{}]被占用", portId.getName());
					} catch (UnsupportedCommOperationException e) {
						logger.error("串口[{}]设置的参数不支持", portId.getName(), e);
					}  catch (Exception e) {
						logger.error("串口[{}]打开异常", portId.getName(), e);
					}
				}
			}

		}
		if (serialPort == null){
			logger.error("串口[{}]打开失败!", comPort);
			return null;
		}
		if (isOpenReadThread ){
			//开启一个接收线程
			portSimpleRead = new SerialPortSimpleRead(serialPort, this, isSingleMessage);
			logger.info("串口[{}]----开启接收线程", comPort);
		}
		if (isOpenWriteThread && serialPort != null){
			portSimpleWrite = new SerialPortSimpleWrite(serialPort);
			logger.info("串口[{}]----开启发送线程", comPort);
		}
		return serialPort;
	}

	/**
     *  根据新参数再次打开 串口
	 * @param comPort
     * @param isSingleMessage
     * @param isOpenReadThread
     * @param isOpenWriteThread
     * @return
     */
	public synchronized SerialPort reOpenPort(String comPort, boolean isSingleMessage, boolean isOpenReadThread, boolean isOpenWriteThread){
		//关闭当前串口
		close();
		SerialPortManager.serialPort = openPort(comPort, isSingleMessage, isOpenReadThread, isOpenWriteThread);
		logger.info("串口重启成功----");
		return serialPort;
	}

	/**
	 * 设置串口参数
	 * @param bautrate
	 * @param serialPort_DATABIT
	 * @param serialPort_STOPBIT
	 * @param serialPort_PARITY
	 */
	void setCommPrams(int bautrate,
			int serialPort_DATABIT,
			int serialPort_STOPBIT,
			int serialPort_PARITY){
		this.bautrate = bautrate;
		this.serialPort_DATABIT = serialPort_DATABIT;
		this.serialPort_STOPBIT = serialPort_STOPBIT;
		this.serialPort_PARITY = serialPort_PARITY;
	}

	/**
	 * 关闭串口管理的资源
	 */
	public synchronized void close(){
		try {
			String portName = null;
			if (serialPort != null){
				portName = serialPort.getName();
			}
			logger.info("-----串口[{}]关闭-----", portName);
			if(SerialPortManager.serialPort!=null){
				SerialPortManager.serialPort.close();
				serialPort = null;
			}
			if (portSimpleRead != null){
				logger.info("-----串口[{}]关闭读线程-----", portName);
				portSimpleRead.close();
			}
			if (portSimpleWrite != null){
				logger.info("-----串口[{}]关闭写线程-----", portName);
				portSimpleWrite.close();
			}
		} catch (Exception e) {
			logger.error("close失败", e);
		}

	}

	/**
     * 处理串口读到数据后怎么处理
	 * @param readStr
	 */
	public abstract void serialReadNotify(String readStr);


	public SerialPortSimpleRead getPortSimpleRead() {
		return portSimpleRead;
	}
	public void setPortSimpleRead(SerialPortSimpleRead portSimpleRead) {
		this.portSimpleRead = portSimpleRead;
	}
	public SerialPortSimpleWrite getPortSimpleWrite() {
		return portSimpleWrite;
	}
	public void setPortSimpleWrite(SerialPortSimpleWrite portSimpleWrite) {
		this.portSimpleWrite = portSimpleWrite;
	}
}

测试

测试类:SerialPortManagerTest

import cn.hutool.core.util.StrUtil;
import com.example.demo2.serial.SerialPortManager;
import com.example.demo2.serial.SerialPortSimpleRead;
import com.example.demo2.serial.SerialPortSimpleWrite;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

public class SerialPortManagerTest {
	static Logger logger = LoggerFactory.getLogger(SerialPortManagerTest.class);

	public static void main2(String[] agrs){
		//一般写测试
		for (int i = 0; i < 10; i++){
			SerialPortManager cabinetSerailManager = new SerialPortManager("COM3", false, true, true) {
				//响应串口接收读数据
				@Override
				public void serialReadNotify(String readStr) {
					//应用程序,监听到数据读入
					System.out.println("应用程序,监听到数据读入:"+readStr);
					//读数据测试
				}
			};
			String message = "55 AA 01 0A 05 04 90 00 04 00 3F 68 86";
			write(cabinetSerailManager.getPortSimpleWrite(), cabinetSerailManager.getPortSimpleRead(), message);
			try {
				Thread.sleep(500L);
			} catch (InterruptedException e) {
				logger.error("", e);
			}
			//关闭串口
			cabinetSerailManager.close();
		}
	}
	public static void main(String[] agrs) throws InterruptedException {
		//一般写测试
		SerialPortSimpleRead simpleRead;
		SerialPortManager cabinetSerailManager = new SerialPortManager("COM4", true, true, false) {
			//响应串口接收读数据
			@Override
			public void serialReadNotify(String message) {
				String msgStr = SerialPortSimpleRead.hexStringToString(message);
				//应用程序,监听到数据读入
				logger.info("监听串口接收数据[{}]", msgStr.trim());
				//调用后台程序

			}
		};
		while(true){
			if (!StrUtil.isEmpty(cabinetSerailManager.getPortSimpleRead().getReadStr())){
				//System.out.println(simpleRead.getReadStr());
			}
			Thread.sleep(1000L);
		}
		//关闭串口
		//cabinetSerailManager.close();
	}

	/**
	 * 获取系统可以识别的串口
	 * @return 返回端口的字符串集合
	 */
	public static List<String> getPortsList(){
		List<String> list = SerialPortManager.getAvailablePorts();
		return list;
	}

	/**
	 * 发送数据
	 */
	public synchronized static void write(final SerialPortSimpleWrite simpleWrite, final SerialPortSimpleRead simpleRead, String message){
		simpleRead.setReadStr("");
		simpleWrite.writeStringToSTM32(message, 1000);
		Timer timer = new Timer();
		timer.schedule(new TimerTask() {
			public void run() {
				String returnValue = simpleRead.getReadStr();
				System.out.println("返回:" + returnValue);
			}
		}, 10);// 设定指定的时间time,此处为10毫秒
	}


}

这些就包含了对串口的常用操作了,完结

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值