2013-04-14 221 views
8

我有一個Java程序,我必須閱讀Arduino發送的信息。 我從here獲取了Java代碼。現在,我真的不明白它是如何工作的,但我試圖修改它,我得到這個:Java/Arduino - 從串口讀取數據

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 port我需要在主程序中的目標序列,然後我用Serial.readSerial.write當我需要它。

Serial.write很好用,Arduino獲取數據並顯示在液晶顯示器上。問題是Serial.read。當程序運行時,它會繼續從串口讀取(大約每隔40個時鐘),但這並不意味着Arduino發送了一些東西。只有當按下按鈕時,Arduino纔會發送一個字節。所以,當Java代碼正在運行時,它在讀取某些內容之前會拋出「n」異常,並且這會導致很多延遲。

我知道我需要類似Serial.available()的東西,我試過input.available(),但它不起作用。我不知道如何解決這個問題。

如果你有一個可以工作的代碼,如果你能把它給我,我會非常感激。我只是需要兩個方法,讀,寫,我不關心代碼是如何工作的:d

編輯:

我改變了串行類,現在它已經作爲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 
} 

現在是work..don't知道爲什麼我不得不這樣做......咩什麼:)

回答

8

您不希望在示例代碼中專門編寫讀取函數。作爲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. 
} 
+0

是的..這是來自arduino playground的示例java代碼... –

+0

我編輯了serialEvent方法來避免你提到的問題 – Anuruddha

+0

是的,但是這個代碼打印控制檯上的數據。我需要的是,從另一個類(如我的Main.java)獲取數據並使用它。像「if(Serial.read()= 255){dosomething()}」 –

0

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()檢查應該導致更少的例外。

+0

我添加了input.ready(),現在我得到了java.io.IOException:當我按下按鈕時,底層輸入流返回了零字節。從Arduino串行監視器中我看到了我發送的數據,所以我知道它可以工作,但是在Java中,當我按下按鈕時程序停滯不前,那麼當我釋放它時,它會拋出異常,然後繼續正常運行 –

+0

異常說的是什麼? – TheMerovingian

+0

java.io.IOException:底層輸入流返回零字節 –