web-dev-qa-db-fra.com

Java/Arduino - Lire les données du port série

J'ai un programme en Java où je dois lire les informations envoyées par un Arduino ..__ J'ai pris le code Java de ici . Maintenant, je n'ai pas vraiment compris comment ça marche, mais j'ai essayé de le modifier et j'ai compris ceci:

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

Je crée l'objet Serial avec le port COM dont j'ai besoin dans le programme principal, puis j'utilise Serial.read et Serial.write quand j'en ai besoin.

Serial.write fonctionne très bien, Arduino récupère les données et les affiche sur un écran LCD. Le problème est Serial.read. Lorsque le programme est en cours d'exécution, il reste lu depuis le port série (environ toutes les 40 ms), mais cela ne signifie pas qu'Arduino a envoyé quelque chose. Arduino envoie un octet uniquement lorsqu'un bouton est enfoncé. Ainsi, lorsque le code Java est en cours d’exécution, il génère "n" Exception avant de lire quelque chose, ce qui provoque beaucoup de retard.

Je sais que j'ai besoin de quelque chose comme Serial.available(), j'ai essayé input.available(), mais cela ne fonctionne pas. Je ne sais pas comment résoudre ce problème.

Si vous avez un code qui fonctionne, je vous serais très reconnaissant si vous pouviez me le donner. J'ai juste besoin de deux méthodes, lire et écrire, peu m'importe le fonctionnement du code: D

MODIFIER:

J'ai changé la classe de série, maintenant il a encore cette méthode comme l'a dit 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());
            }
        }       
    }

et dans l'autre classe (Panel dans ce cas), j'ai ceci:

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

Il affiche les valeurs correctement mais data == "255" est toujours faux, même si je reçois vraiment un 255 .... J'ai essayé de faire Integer.parseInt mais rien n’a changé. Pourquoi diable?

EDIT 2: Ok résolu: \

public void read(String data){

    serialRead = Integer.parseInt(data);

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

Maintenant, c'est du travail ... je ne sais pas pourquoi je devais faire ça ... peu importe :)

9
Giammarco Boscaro

Vous ne voulez pas écrire spécifiquement une fonction de lecture, cela se trouve déjà dans l'exemple de code. Comme l'a souligné TheMerovingian, vous pouvez vérifier le tampon d'entrée avant de le lire.

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

EDIT: la fonction serialEvent est responsable de la lecture du tampon.

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.
}
10
Anuruddha

La classe BufferedReader a une méthode ready() qui renvoie True si "le tampon n'est pas vide ou si le flux de caractères sous-jacent est prêt." et False autrement. Vous pouvez donc ajouter une vérification dans la méthode read() pour vous assurer qu'il y a des données à lire avant d'essayer de lire.

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

Il semble que le code a un try-catch en place pour gérer si cela échoue, ce qui est probablement la cause de votre décalage, car try-catch est assez coûteux. Ainsi, la vérification input.ready() devrait entraîner moins d'exceptions.

0
TheMerovingian