Java / Arduino – 从串行端口读取数据

我有一个Java程序,我必须阅读Arduino发送的信息。 我从这里获取了Java代码。 现在,我真的不明白它是如何工作的,但我试着修改它,我得到了这个:

import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.OutputStream; import gnu.io.CommPortIdentifier; import gnu.io.SerialPort; import gnu.io.SerialPortEvent; import gnu.io.SerialPortEventListener; import java.util.Enumeration; public class Serial implements SerialPortEventListener { SerialPort serialPort; private static final String PORT_NAMES[] = { "/dev/tty.usbserial-A9007UX1", // Mac OS X "/dev/ttyUSB0", // Linux "COM3", // Windows }; private BufferedReader input; private static OutputStream output; private static final int TIME_OUT = 2000; private static final int DATA_RATE = 115200; public void initialize() { CommPortIdentifier portId = null; Enumeration portEnum = CommPortIdentifier.getPortIdentifiers(); while (portEnum.hasMoreElements()) { CommPortIdentifier currPortId = (CommPortIdentifier) portEnum.nextElement(); for (String portName : PORT_NAMES) { if (currPortId.getName().equals(portName)) { portId = currPortId; break; } } } if (portId == null) { System.out.println("Could not find COM port."); return; } try { serialPort = (SerialPort) portId.open(this.getClass().getName(),TIME_OUT); serialPort.setSerialPortParams(DATA_RATE, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); input = new BufferedReader(new InputStreamReader(serialPort.getInputStream())); output = serialPort.getOutputStream(); serialPort.addEventListener(this); serialPort.notifyOnDataAvailable(true); } catch (Exception e) { System.err.println(e.toString()); } } public synchronized void serialEvent(SerialPortEvent oEvent) { if (oEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) { try { String inputLine=input.readLine(); System.out.println(inputLine); } catch (Exception e) { System.err.println(e.toString()); } } } public synchronized void close() { if (serialPort != null) { serialPort.removeEventListener(); serialPort.close(); } } public Serial(String ncom){ if(Integer.parseInt(ncom)>=3 && Integer.parseInt(ncom)<=9) PORT_NAMES[2] = "COM" + ncom; initialize(); Thread t=new Thread() { public void run() { try {Thread.sleep(1000000);} catch (InterruptedException ie) {} } }; t.start(); System.out.println("Serial Comms Started"); } public synchronized void send(int b){ try{ output.write(b); } catch (Exception e) { System.err.println(e.toString()); } } public synchronized int read(){ int b = 0; try{ b = (int)input.read(); } catch (Exception e) { System.err.println(e.toString()); } return b; } } 

我在主程序中使用我需要的COM端口创建对象Serial,然后在需要时使用Serial.writeSerial.write

Serial.write运行良好,Arduino获取数据并在LCD显示器中显示。 问题是Serial.read 。 当程序运行时,它会保持从串口读取(大约每40毫秒),但这并不意味着Arduino发送了一些东西。 Arduino仅在按下按钮时发送一个字节。 因此,当Java代码运行时,它会在读取内容之前抛出“n”exception,这会导致很多延迟。

我知道我需要像Serial.available()这样的东西,我尝试了input.available() ,但它不起作用。 我不知道如何解决这个问题。

如果你有一个有效的代码,如果你能把它给我,我将非常感激。 我只需要两种方法,读写,我不关心代码是如何工作的:D

编辑:

我改变了Serial类,现在它又像apremalal那样再次使用了这个方法

 public synchronized void serialEvent(SerialPortEvent oEvent) { if (oEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) { try { String inputLine=null; if (input.ready()) { inputLine = input.readLine(); panel.read(inputLine); } } catch (Exception e) { System.err.println(e.toString()); } } } 

而在另一个类(在这种情况下的小组)我有这个:

 public void read(String data){ System.out.println(data); System.out.println(data == "255"); if(data == "255") //code here } 

它正确地打印了值,但是data == "255"总是假的,即使我真的得到了255 ….我试图做Integer.parseInt但没有改变。 为什么地狱?

编辑2:好的解决了:

 public void read(String data){ serialRead = Integer.parseInt(data); if(serialRead == 255) //code here } 

现在它的工作……不知道为什么我必须这样做……不管怎样:)

您不希望专门编写示例代码中已有的读取函数。正如TheMerovingian指出您可以在读取之前检查输入缓冲区。这是我在我的一个项目中使用的工作代码。

 import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.OutputStream; import gnu.io.CommPortIdentifier; import gnu.io.SerialPort; import gnu.io.SerialPortEvent; import gnu.io.SerialPortEventListener; import java.util.Enumeration; public class SerialTest implements SerialPortEventListener { SerialPort serialPort; /** The port we're normally going to use. */ private static final String PORT_NAMES[] = { "/dev/tty.usbserial-A9007UX1", // Mac OS X "/dev/ttyUSB0", // Linux "COM35", // Windows }; private BufferedReader input; private OutputStream output; private static final int TIME_OUT = 2000; private static final int DATA_RATE = 9600; public void initialize() { CommPortIdentifier portId = null; Enumeration portEnum = CommPortIdentifier.getPortIdentifiers(); //First, Find an instance of serial port as set in PORT_NAMES. while (portEnum.hasMoreElements()) { CommPortIdentifier currPortId = (CommPortIdentifier) portEnum.nextElement(); for (String portName : PORT_NAMES) { if (currPortId.getName().equals(portName)) { portId = currPortId; break; } } } if (portId == null) { System.out.println("Could not find COM port."); return; } try { serialPort = (SerialPort) portId.open(this.getClass().getName(), TIME_OUT); serialPort.setSerialPortParams(DATA_RATE, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); // open the streams input = new BufferedReader(new InputStreamReader(serialPort.getInputStream())); output = serialPort.getOutputStream(); serialPort.addEventListener(this); serialPort.notifyOnDataAvailable(true); } catch (Exception e) { System.err.println(e.toString()); } } public synchronized void close() { if (serialPort != null) { serialPort.removeEventListener(); serialPort.close(); } } public synchronized void serialEvent(SerialPortEvent oEvent) { if (oEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) { try { String inputLine=null; if (input.ready()) { inputLine = input.readLine(); System.out.println(inputLine); } } catch (Exception e) { System.err.println(e.toString()); } } // Ignore all the other eventTypes, but you should consider the other ones. } public static void main(String[] args) throws Exception { SerialTest main = new SerialTest(); main.initialize(); Thread t=new Thread() { public void run() { //the following line will keep this app alive for 1000 seconds, //waiting for events to occur and responding to them (printing incoming messages to console). try {Thread.sleep(1000000);} catch (InterruptedException ie) {} } }; t.start(); System.out.println("Started"); } } 

编辑:serialEvent函数负责读取缓冲区。

 public synchronized void serialEvent(SerialPortEvent oEvent) { if (oEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) { try { String inputLine=null; if (input.ready()) { inputLine = input.readLine(); System.out.println(inputLine); } } catch (Exception e) { System.err.println(e.toString()); } } // Ignore all the other eventTypes, but you should consider the other ones. } 

BufferedReader类有一个ready()方法,如果“缓冲区不为空,或者底层字符流已准备好”,则返回True 。 否则就是False 。 因此,您可以在read()方法中添加一个检查,以确保在尝试读取之前有数据要读取。

 public synchronized int read(){ int b = 0; try{ if (input.ready()) { b = (int)input.read(); } }catch (Exception e) { System.err.println(e.toString()); } return b; } 

看起来代码有一个try-catch来处理,如果这些事情失败,这可能是导致你的滞后的原因,因为try-catch非常昂贵。 因此input.ready()检查应该导致更少的exception。