2013-04-14 26 views
8

Ho un programma in Java in cui devo leggere le informazioni che un Arduino sta inviando. Ho preso il codice Java da here. Ora, non ho ben capito come funziona, ma ho cercato di modificarla e ho ottenuto questo:Java/Arduino - Lettura dati dalla porta seriale

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

creo Serial oggetto con il COM port ho bisogno nel programma principale, allora io uso Serial.read e Serial.write quando ne ho bisogno.

Serial.write funziona benissimo, Arduino riceve i dati e li mostra in un display LCD. Il problema è Serial.read. Quando il programma è in esecuzione, continua a leggere dalla porta seriale (circa ogni 40   ms), ma ciò non significa che Arduino abbia inviato qualcosa. Arduino invia un byte solo quando viene premuto un pulsante. Quindi, quando il codice Java è in esecuzione, lancia "n" Exception prima di leggere qualcosa, e questo cousera così tanto ritardo.

So che ho bisogno di qualcosa come Serial.available(), ho provato input.available(), ma non funziona. Non so come risolvere questo problema.

Se hai un codice funzionante, sarei molto grato se me lo potessi dare. Ho solo bisogno di due metodi, leggere e scrivere, non mi interessa come funziona il codice: D

EDIT:

ho cambiato la classe seriale, ora ha di nuovo questo metodo come detto 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()); 
      } 
     }  
    } 

e l'altra classe (Pannello in questo caso) ho questo:

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

stampa correttamente i valori, ma data == "255" è sempre false, anche se davvero ottenere un 255 012.351..... Ho provato a fare Integer.parseInt ma non è cambiato nulla. Perché diavolo?

EDIT 2: Ok risolto: \

public void read(String data){ 

    serialRead = Integer.parseInt(data); 

    if(serialRead == 255) 
     //code here 
} 

Ora è work..don't so perché ho dovuto fare questo ... meh qualunque :)

risposta

8

Non si desidera scrivere in modo specifico una funzione di lettura che è già presente nel codice di esempio. Come indicato da TheMerovingian, è possibile controllare il buffer di input prima della lettura.Qui è il codice di lavoro che ho utilizzato in uno dei miei progetti .

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

MODIFICA: la funzione serialEvent è responsabile della lettura del buffer.

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

Sì..questo è il codice java di esempio da Arduino playground ... –

+0

Ho modificato il metodo serialEvent per evitare il problema che hai menzionato – Anuruddha

+0

sì ma questo codice stampa il dati sulla console. Quello di cui ho bisogno è, da un'altra classe (come la mia Main.java), ottenere i dati e usarli. Come "if (Serial.read() = 255) {dosomething()}" –

0

La classe BufferedReader ha un ready() metodo che restituisce True se "il buffer non è vuoto o se il flusso di caratteri sottostante è pronto." e False in caso contrario. Quindi è possibile aggiungere un controllo nel metodo read() per assicurarsi che ci siano dati da leggere prima di provare a leggere.

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

Sembra che il codice ha un try-catch in atto per gestire se queste cose non riescono, che è forse quello che fa sì che il ritardo a causa try-catch sono piuttosto costosi. Pertanto il controllo input.ready() dovrebbe comportare un numero inferiore di eccezioni.

+0

Ho aggiunto l'input.ready() e ora ho java.io.IOException: il flusso di input sottostante restituisce zero byte quando premo il pulsante. Dal monitor seriale di Arduino vedo i dati che sto inviando, quindi so che funziona, ma poi in Java mentre premo il pulsante il programma è appena bloccato, quindi quando lo rilascio getta l'eccezione e quindi continua a funzionare normalmente –

+0

Che cosa dice esattamente l'eccezione? – TheMerovingian

+0

java.io.IOException: flusso di input sottostante restituito zero byte –

Problemi correlati