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();
		
	}

}
相關文章
相關標籤/搜索