java 串口通讯

以前使用c++/C#时,都是能够直接调用串口API的,java没有源生支持串口,只能经过第三方扩展java

这里使用的是javacomm20-win32.zip这个实现的库,可自行网上下载c++

使用时,先解压,再复制三个文件到jdk中,可执行下面的命令进行复制api

copy comm.jar "%JAVA_HOME%\jre\lib\ext\"
copy javax.comm.properties "%JAVA_HOME%\jre\lib\"
copy win32com.dll "%JAVA_HOME%\jre\bin\"

在eclipse中在引入comm.jar便可使用串口api缓存

虽然这中方式确实可以解决java调用串口问题,可是须要复制第三方库到jdk,总感受不爽。eclipse

为了在不修改jdk的状况下,也可以使用串口功能,就须要修改引用串口库的方式了。maven

在个人项目中,ide

将comm.jar、javax.comm.properties、win32com.dll放在了src/main/resources/commapi/下工具

第一步是引入comm.jarthis

这一步相对比较容易,只要将这个jar包引入项目便可,若是使用maven进行管理的话,可参考以下方式引用spa

<dependency>
	<groupId>javax.comm</groupId>
	<artifactId>comm</artifactId>
	<version>1.0</version>
	<scope>system</scope>
	<systemPath>${project.basedir}/src/main/resources/commapi/comm.jar</systemPath>
</dependency>

第二部是引入win32com.dll

这一步实际上须要将win32com.dll所在的路径加入到path路径,可是不想经过直接修改环境变量,而是经过程序动态添加的方式实现,实现方式参考以下代码

public static void addDir(String s){
		try {
			logger.info(s);
			Field field = ClassLoader.class.getDeclaredField("sys_paths");
			field.setAccessible(true);
			String[] paths = (String[]) field.get(null);
			for (int i = 0; i < paths.length; i++) {
				if (s.equals(paths[i])) {
					return;
				}
			}
			String[] tmp = new String[paths.length + 1];
			System.arraycopy(paths, 0, tmp, 0, paths.length);
			tmp[paths.length] = s;
			field.set(null, tmp);
		} catch (Exception e) {
			logger.error("加载path异常", e);
		}
	}

	/**
	 * 动态添加系统path变量,用于动态加载DLL
	 */
	public static void systemPathInit() {
		// 添加串口win32com.dll路径
		addDir(PathUtil.getResourcePath() + "\\commapi");
		// 添加一个站位用的classpath,用于串口comm.jar寻找javax.comm.properties。详见comm.jar->CommPortIdentifier->findPropFile();
		System.setProperty("java.class.path", System.getProperty("java.class.path") + ";" + PathUtil.getResourcePath() + "\\commapi\\comm.jar");
	}

设置java.class.path,主要是由于,comm.jar源码中,会经过java.class.path找到comm.jar的路径,再在comm.jar的相同路径中寻找javax.comm.properties文件。这样就可让comm.jar找到javax.comm.properties文件。

systemPathInit()方法要在程序启动时,使用串口前先调用一次

如下是串口使用的参考代码

import java.io.InputStream;
import java.io.OutputStream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;



public abstract class CommunicateBase {
	
	private Logger logger = LoggerFactory.getLogger(getClass());

    protected OutputStream outputStream;
    protected InputStream inputStream;
    
	/**
	 * 打开
	 * @return
	 */
	public abstract String open();
	
	/**
	 * 
	 * @param cmd
	 */
	public void send(String cmd) {
		try {
			if (outputStream == null) {
				logger.error("链接未打开");
				return;
			}
			outputStream.write(cmd.getBytes());
		} catch (Exception e) {
			logger.error("发送异常", e);
		}
	}
	
	
	/**
	 * 读取数据
	 * @return
	 */
	public String read(int len){
		try {
			
			if (inputStream == null) {
				logger.error("链接未打开");
				return "";
			}
			
			int off = 0;//偏移
			byte[] readBuffer = new byte[len];//读数据缓存
			while (inputStream.available() > 0) {//循环读取接收的数据
				
				// 读取数据
				int readCount = inputStream.read(readBuffer, off, len);
				
				// 修正偏移量
				off += readCount;
				len -= readCount;
				
				ThreadUtil.sleep(50);
			}
			
			// 转换为字符串
			return new String(readBuffer).trim();
		} catch (Exception e) {
			logger.error("接收异常", e);
			return "";
		}
	}
	
	
	/**
	 * 关闭
	 */
	public abstract void close();
}
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

import javax.comm.CommDriver;
import javax.comm.CommPort;
import javax.comm.CommPortIdentifier;
import javax.comm.SerialPort;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sun.comm.Win32Driver;

/**
 * 串口工具类
 * 
 *
 */
public class Uart extends CommunicateBase{
	protected Logger logger = LoggerFactory.getLogger(Uart.class);

	private CommPortIdentifier portId;
	private SerialPort serialPort;
	
	private String comm = "COM9";// 端口号
	private int baudRate = 9600;// 波特率
    private int timeout = 100;//open 端口时的等待时间  
	
    public Uart(String comm, int baudRate) {
    	this.comm = comm;
    	this.baudRate = baudRate;
    }
    
    
    /**
     * 经过反射清空CommPortIdentifier中的串口列表
     * 能够解决动态添加串口时,也可以识别出的功能,
     */
	private void commClear() {
		try {
			// 清空api链表
			Constructor con = CommPortIdentifier.class.getDeclaredConstructor(
					String.class, CommPort.class, int.class, CommDriver.class);
			con.setAccessible(true);
			Object o = (CommPortIdentifier) con
					.newInstance(null, null, 0, null);// 获取对象
			Field f = CommPortIdentifier.class.getDeclaredField("masterIdList");// 根据key获取参数
			f.setAccessible(true);
			f.set(o, null);
			
			// 从新初始化串口api
			new Win32Driver().initialize();
		} catch (Exception e) {
			logger.error("清除串口异常", e);
		}

	}

	/**
	 * 打开串口
	 * @return
	 */
	@Override
	public String open(){
		try {
			close();//先保证串口为关闭状态
			PathUtil.printAllPath();
			
			// 清空串口链表
			commClear();
			
			portId = CommPortIdentifier.getPortIdentifier(comm);
			serialPort = (SerialPort) portId.open("Uart", timeout);

			outputStream = serialPort.getOutputStream();
			inputStream = serialPort.getInputStream();
			
			serialPort.setSerialPortParams(baudRate,// 波特率
					SerialPort.DATABITS_8, // 数据位
					SerialPort.STOPBITS_1,// 中止位
					SerialPort.PARITY_NONE);// 校验位
			
			logger.info("串口已打开");
			return "成功";
		} catch (Exception e) {
			logger.error("串口打开失败", e);
			return e.getMessage();
		}

	}
	
	/**
	 * 关闭串口
	 */
	@Override
	public void close() {
		if (serialPort != null) {
			serialPort.close();
			portId = null;
			serialPort = null;
			outputStream = null;
			inputStream = null;
			logger.info("串口已关闭");
		}
	}

	
	/**
	 * 是否链接
	 * @return
	 */
	public boolean isConnected() {
		
		if (portId != null) {
			
			logger.info(portId.getCurrentOwner());
			return portId.getCurrentOwner().equals("Port currently not owned");
		}
		return false;
		
	}
	
	
	public static void main(String[] args) throws InterruptedException{
		
		PathUtil.addDir(PathUtil.getResourcePath() + "\\commapi");
		
		Uart uart = new Uart("COM4", 9600);
		uart.open();
		
		uart.send("aa");
		
		Thread.sleep(1000);
		
		System.out.println(uart.read(50));
		
		uart.close();
		
	}

}
相关文章
相关标签/搜索