以前使用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(); } }