关于java实现的串口通信,使用的是开源项目RXTX,之前sun公司也有JCL项目,不过已经很久没有更新了,RXTX项目地址:点击打开,但是两个项目的API用法是一样的,只是导入的包不一样而已。简单的入门可以参照官方的wiki。
对应你的开发环境(Linux、window、Mac)下载对应的文件(下载地址),这里说下具体的安装方法,官方给的有点啰嗦,在Eclipse下使用,下载后里面的文件:
RXTXcomm.jar包放到你项目的lib文件夹下,Java Builder Path---->Add to builder path,然后对应系统环境选择文件:
将两个文件直接拷贝到项目的根目录下:
问题1
注意,我安装的时候出现了“VM warning: You have loaded library /****/***/***/librxtxSerial.so which might have disabled stack guard. The VM will try to fix the stack guard now.
It‘s highly recommended that you fix the library with ‘execstack -c <libfile>‘, or link it with ‘-z noexecstack‘.”
google很久没有解决办法,所以按照给出的提示信息,sudo apt-get install execstack,安装了execstack后,在librxtxSerial所在的文件夹,打开终端,按照提少的要求execstack -c librxtxSerial.so即可解决。
问题2
找不到设备,这是权限问题,你应该在终端下用sudo命令启动Eclipse
关于使用:
建议你参考这两篇博客:使用comm在java程序中管理本地端口和Java串口通讯,两篇讲的是一些基础知识依据API的基本用法,当然如果你依据很熟悉,那么你可以直接写写代码运行下,比如扫描当前的设备端口:
public static void listPorts() { java.util.Enumeration<CommPortIdentifier> portEnum = CommPortIdentifier.getPortIdentifiers(); while ( portEnum.hasMoreElements() ) { CommPortIdentifier portIdentifier = portEnum.nextElement(); System.out.println(portIdentifier.getName() + " - " + getPortTypeName(portIdentifier.getPortType()) ); } } public static String getPortTypeName ( int portType ) { switch ( portType ) { case CommPortIdentifier.PORT_I2C: return "I2C"; case CommPortIdentifier.PORT_PARALLEL: return "Parallel"; case CommPortIdentifier.PORT_RAW: return "Raw"; case CommPortIdentifier.PORT_RS485: return "RS485"; case CommPortIdentifier.PORT_SERIAL: return "Serial"; default: return "unknown type"; } }
串口通信,有两种方式,两篇博客说的很详细了,你也可以参考wiki的例子了解其通信流程,我仿照官方写的例子,部分有改动,SerialRXTX.java:
package nir.desktop.demo; import gnu.io.CommPort; import gnu.io.CommPortIdentifier; import gnu.io.PortInUseException; import gnu.io.SerialPort; import gnu.io.SerialPortEvent; import gnu.io.SerialPortEventListener; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Enumeration; import java.util.HashSet; public class SerialRXTX { /** * This code snippet shows how to retrieve the available comms ports on your * computer. A CommPort is available if it is not being used by another * application. */ public static void listAvailablePorts() { HashSet<CommPortIdentifier> portSet = getAvailableSerialPorts(); String[] serialPort = new String[portSet.size()]; int i = 0; for (CommPortIdentifier comm : portSet) { serialPort[i] = comm.getName(); System.out.println(serialPort[i]); i++; } } public static String getPortTypeName(int portType) { switch (portType) { case CommPortIdentifier.PORT_I2C: return "I2C"; case CommPortIdentifier.PORT_PARALLEL: return "Parallel"; case CommPortIdentifier.PORT_RAW: return "Raw"; case CommPortIdentifier.PORT_RS485: return "RS485"; case CommPortIdentifier.PORT_SERIAL: return "Serial"; default: return "unknown type"; } } /** * @return A HashSet containing the CommPortIdentifier for all serial ports * that are not currently being used. */ public static HashSet<CommPortIdentifier> getAvailableSerialPorts() { HashSet<CommPortIdentifier> h = new HashSet<CommPortIdentifier>(); @SuppressWarnings("rawtypes") Enumeration thePorts = CommPortIdentifier.getPortIdentifiers();// 可以找到系统的所有的串口,每个串口对应一个CommPortldentifier while (thePorts.hasMoreElements()) { CommPortIdentifier com = (CommPortIdentifier) thePorts .nextElement(); switch (com.getPortType()) { case CommPortIdentifier.PORT_SERIAL:// type of the port is serial try { CommPort thePort = com.open("CommUtil", 50);// open the serialPort thePort.close(); h.add(com); } catch (PortInUseException e) { System.out.println("Port, " + com.getName() + ", is in use."); } catch (Exception e) { System.err.println("Failed to open port " + com.getName()); e.printStackTrace(); } } } return h; } public static SerialPort connect(String portName) throws Exception { SerialPort serialPort = null; CommPortIdentifier portIdentifier = CommPortIdentifier .getPortIdentifier(portName);// initializes of port operation if (portIdentifier.isCurrentlyOwned()) { System.out.println("Error: Port is currently in use"); } else { CommPort commPort = portIdentifier.open(portName, 2000);// the delay // time of // opening // port if (commPort instanceof SerialPort) { serialPort = (SerialPort) commPort; serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);// serial // communication // parameters // setting InputStream inputStream = serialPort.getInputStream(); // OutputStream outputStream = serialPort.getOutputStream(); // (new Thread(new SerialWriter(outputStream))).start(); serialPort.addEventListener(new SerialReader(inputStream)); serialPort.notifyOnDataAvailable(true); } } return serialPort; } /** * not necessary to send command in new thread, but the serialPort only has * one instance * * @param serialPort * @param string */ public static void sendMessage(SerialPort serialPort, String string) { try { OutputStream outputStream = serialPort.getOutputStream(); (new Thread(new SerialWriter(outputStream, string))).start();// send // command // in // the // new // thread } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * Handles the input coming from the serial port. A new line character is * treated as the end of a block in this example. */ public static class SerialReader implements SerialPortEventListener { private InputStream in; public SerialReader(InputStream in) { this.in = in; } public void serialEvent(SerialPortEvent arg0) { byte[] buffer = new byte[1024]; try { Thread.sleep(500);// the thread need to sleep for completed // receive the data if (in.available() > 0) { in.read(buffer); } System.out.println(new String(buffer)); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** */ public static class SerialWriter implements Runnable { OutputStream out; String commandString; public SerialWriter(OutputStream out, String commandString) { this.out = out; this.commandString = commandString; } public void run() { while (true) { try { Thread.sleep(3000);// an interval of 3 seconds to sending // data out.write(commandString.getBytes()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InterruptedException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } } } public static void main(String[] args) { listAvailablePorts(); try { sendMessage(connect("/dev/ttyUSB0"), "P"); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
返回的数据:
在监听返回数据的时候,出现的问题是返回的数据不连续,比如:
P
H:05.36
解决的方法是在接受的地方让线程休眠一下,即可解决
Thread.sleep(500);