我无法通过modbus与数据记录器通信

时间:2018-02-10 11:21:13

标签: java serial-port modbus

我尝试连接到这样的数据记录器:

enter image description here

我可以通过串口发送一个问题,这只不过是一个字节数组。问题是我无法得到答案。我知道数据记录器以9600波特进行通信。我试图连接示波器,看它是否是程序或硬件问题,但示波器似乎给我一个答案,但我无法接收。这意味着问题肯定是软件。下面我将在示波器中显示答案

enter image description here

import gnu.io.CommPortIdentifier;
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;

public class SerialRead implements SerialPortEventListener
{

    private SerialPort serialPort;
    private static String st;
    private String PORT_ID;
    private static SerialRead mInstance = null;
    private InputStream input;
    private OutputStream output;
    private static final int TIME_OUT = 2000;

    //TODO: inserisci il baud per la velocità di acquisizione
    private static final int DATA_RATE = 9600;


    public static SerialRead getInstance()
    {
        if (mInstance == null) {
            mInstance = new SerialRead();
        }

        return mInstance;
    }

    /**
     * setto il valore della PORT_ID e vado a restituire l'istanza della classe
     * @param PORT_ID
     * @return
     */
    public SerialRead setPORT_ID(String PORT_ID) {
        this.PORT_ID = PORT_ID;

        if (PORT_ID == null){
            throw new NullPointerException("Devi dare un valore alla porta");
        }

        return this;
    }


    private SerialRead() {
        //costruttore interno
        initialize();
        close();
    }


    /**
     * metodo che va a settare i parametri per l'inizializzazione della porta seriale ed
     * per la comunicazione seriale per gestire sucessivamente la richiesta con un
     * InputStream e OutputSteam
     * @return
     */
    public SerialRead initialize() {
        CommPortIdentifier portId = null;
        Enumeration portEnum = CommPortIdentifier.getPortIdentifiers();
        // iterate through, looking for the port
        while (portEnum.hasMoreElements()) {
            CommPortIdentifier currPortId = (CommPortIdentifier) portEnum.nextElement();
            if (currPortId.getName().equals(PORT_ID)) {
                portId = currPortId;
                System.out.println("-Porta connessa da " + SerialRead.class.getSimpleName());
                break;
            }
        }

        try {
            serialPort = (SerialPort) portId.open(PORT_ID, TIME_OUT);
            // set port parameters
            serialPort.setSerialPortParams(DATA_RATE,
                    SerialPort.DATABITS_8,
                    SerialPort.STOPBITS_1,
                    SerialPort.PARITY_NONE);
            input = serialPort.getInputStream();
            output = serialPort.getOutputStream();
            // add event listeners
            serialPort.addEventListener(this);
            serialPort.notifyOnDataAvailable(true);
        } catch (Exception e) {
        }

        return this;
    }

    /**
     * chiude la porta seriale così da liberare la comunicazione per la scrittura o la lettura
     * questo perchè è monodirezionale
     */
    private synchronized void close() {
        if (serialPort != null) {
            serialPort.removeEventListener();
            serialPort.close();
        }
    }

    /**
     * Richiamo il metodo definito all'interno dell'interfaccia implementata SerialPortEventListener
     * Creo un thread continuo per la lettura dei dati che andrà a terminare alla lettura di un dato specifico
     * Andremo a leggere i dati solamente nel caso in cui siano disponibili
     * @param oEvent
     */

    @Override
    public synchronized void serialEvent(final SerialPortEvent oEvent) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                if (oEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
                    try {
                        int available = input.available();
                        byte[] chunk = new byte[available];
                        //System.out.println(chunk);
                        input.read(chunk, 0, available);
                        st = new String(chunk);
                        System.out.print(st);
                        /*try{ //impostato per risparmiare prestazioni e eseguire il ciclo meno spesso
                            Thread.sleep(5000);
                        } catch(InterruptedException ex) {
                            Thread.currentThread().interrupt();
                        }*/
                    }
                    catch (IOException e) {
                        System.out.println("IO Error Occurred: " + e.toString());
                    }
                }
            }
        }).start();
    }

}

SerialWriter.java

import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;

public class SerialWriter
{

    /**
     * inizializzazione porte e strumenti per la scrittura della seriale
     */
    private SerialPort serialPort;
    private String PORT_ID;
    private static SerialWriter mInstance = null;
    private CommPortIdentifier portId = null;
    private InputStream input;
    private OutputStream output;
    private static final int TIME_OUT = 2000;

    //TODO: inserisci il baud per la velocità di acquisizione
    private static final int DATA_RATE = 9600;

    private SerialWriter() {
        //costruttore interno
        close();
    }


    public static SerialWriter getInstance() {
        if (mInstance == null) {
            mInstance = new SerialWriter();
        }
        return mInstance;
    }

    /**
     * setto il valore della PORT_ID e vado a restituire l'istanza della classe
     * @param PORT_ID
     * @return
     */
    public SerialWriter setPORT_ID(String PORT_ID) {
        this.PORT_ID = PORT_ID;

        if (PORT_ID == null){
            throw new NullPointerException("Devi dare un valore alla porta");
        }
        return this;
    }


    /**
     * metodo che va a settare i parametri per l'inizializzazione della porta seriale ed
     * per la comunicazione seriale per gestire sucessivamente la richiesta con un
     * InputStream e OutputSteam
     * @return
     */
    public SerialWriter initialize() {
        Enumeration portEnum = CommPortIdentifier.getPortIdentifiers();
        // iterate through, looking for the port
        while (portEnum.hasMoreElements()) {
            CommPortIdentifier currPortId = (CommPortIdentifier) portEnum.nextElement();
            //for (String portName : PORT_NAMES) {
                if (currPortId.getName().equals(PORT_ID)) {
                    portId = currPortId;
                    System.out.println("-Porta connessa da " + SerialWriter.class.getSimpleName());
                    break;
                }
           //}
        }
        if (portId == null) {
            System.out.println("scanner is not connected !");
        }
        try {
            serialPort = (SerialPort) portId.open(PORT_ID, TIME_OUT);
            // set port parameters
            serialPort.setSerialPortParams(DATA_RATE,
                    SerialPort.DATABITS_8,
                    SerialPort.STOPBITS_1,
                    SerialPort.PARITY_NONE);
            input = serialPort.getInputStream();
            output = serialPort.getOutputStream();
            serialPort.notifyOnDataAvailable(true);

        } catch (Exception e) {
        }
        return this;
    }

    /**
     * chiude la porta seriale così da liberare la comunicazione per la scrittura o la lettura
     * questo perchè è monodirezionale
     */
    private synchronized void close() {
        if (serialPort != null) {
            serialPort.removeEventListener();
            serialPort.close();
            System.out.println("-Porta chiusa da " + SerialWriter.class.getSimpleName());
        }
    }

    /**
     * metodo create per inviare una serie ("infinita") di messaggi tramite il parametro varags(un array di elementi)
     * @param messagge
     */
    public void sendData(String... messagge) {

        if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {

            OutputStream outstream = null;
            try {
                outstream = serialPort.getOutputStream();
                for (String currentMessage: messagge) {
                    //TODO: da cancellare- solo per debugging 1-2 riga
                    System.out.println(currentMessage);
                    outstream.write("\n".getBytes());
                    outstream.write(currentMessage.getBytes());
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        close();
    }


    public synchronized void sendData(byte... messagge) {

        if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {

            OutputStream outstream = null;
            try {
                outstream = serialPort.getOutputStream();
                /*for (byte currentMessage: messagge) {
                    //TODO: da cancellare- solo per debugging 1-2 riga
                    System.out.println(currentMessage);
                    //outstream.write("\n".getBytes());
                    outstream.write(currentMessage);
                    outstream.flush();
                }*/

                outstream.write(messagge);
                //outstream.flush();

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        close();
    }


    public void sendData(char... messagge) {

        if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {

            OutputStream outstream = null;
            try {
                outstream = serialPort.getOutputStream();
                for (char currentMessage: messagge) {
                    //TODO: da cancellare- solo per debugging 1-2 riga
                    System.out.println(Integer.toBinaryString(currentMessage));
                    //outstream.write("\n".getBytes());
                    outstream.write(String.valueOf(currentMessage).getBytes());
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        close();
    }

}

和主要活动:

public class SerialeEsegui
{
    public static void main(String args[]) {
        String PORT_ID = "COM4";
        SerialRead.getInstance().setPORT_ID(PORT_ID).initialize();
}

2 个答案:

答案 0 :(得分:0)

在你的代码中没有发送请求所以我假设这个设备是自己发送的。 Modbus协议远比标准串行通信复杂。人们通常需要构建类似协议栈的东西才能接收消息。我们使用Modbus做了很多工作,我们正在使用SuperCom库(adontec.com)来完成这项工作。它还提供了一个名为RS_RXMODBUS的功能,可以接收原始Modbus数据。不幸的是,这个库不是免费的,但是非常可靠。

答案 1 :(得分:0)

似乎错误发生在关闭序列然后重新打开它的close()方法上。实际上,您已经为打开和关闭的串行创建了两个类,分别是写入和读取(SerialWriting.java和SerialReading.java)。但这没有任何意义,事实上,创建单个类更加正确和简单。它仅对序列进行一次初始化,然后您可以直接在其中管理数据的读取和写入。问题似乎是你花了太多时间从一个类改为另一个类,然后关闭串口然后重新打开它,从而失去了示波器中显示的数据记录器的响应。在下面的代码中,所有内容都由一个类管理,您可以在读完数据后调用close()方法。

import gnu.io.CommPortIdentifier;
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.TooManyListenersException;

public class SerialManager implements SerialPortEventListener
{

    /**
     * inizializzazione porte e strumenti per la scrittura della seriale
     */
    private SerialPort serialPort;
    private String PORT_ID;
    private static String st;
    private static SerialManager mInstance = null;
    private CommPortIdentifier portId = null;
    private InputStream input;
    private OutputStream output;
    private static final int TIME_OUT = 2000;


    //TODO: inserisci il baud per la velocità di acquisizione
    private static final int DATA_RATE = 9600;

    private SerialManager() {
        //costruttore interno
        close();
    }


    public static SerialManager getInstance() {
        if (mInstance == null) {
            mInstance = new SerialManager();
        }
        return mInstance;
    }

    /**
     * setto il valore della PORT_ID e vado a restituire l'istanza della classe
     * @param PORT_ID
     * @return
     */
    public SerialManager setPORT_ID(String PORT_ID) {
        this.PORT_ID = PORT_ID;

        if (PORT_ID == null){
            throw new NullPointerException("Devi dare un valore alla porta");
        }
        return this;
    }


    /**
     * metodo che va a settare i parametri per l'inizializzazione della porta seriale ed
     * per la comunicazione seriale per gestire sucessivamente la richiesta con un
     * InputStream e OutputSteam
     * @return
     */
    public SerialManager initialize() {
        Enumeration portEnum = CommPortIdentifier.getPortIdentifiers();
        // iterate through, looking for the port
        while (portEnum.hasMoreElements()) {
            CommPortIdentifier currPortId = (CommPortIdentifier) portEnum.nextElement();
            //for (String portName : PORT_NAMES) {
            if (currPortId.getName().equals(PORT_ID)) {
                portId = currPortId;
                System.out.println("-Porta connessa da " + SerialManager.class.getSimpleName());
                break;
            }
            //}
        }
        if (portId == null) {
            System.out.println("scanner is not connected !");
        }
        try {
            serialPort = (SerialPort) portId.open(PORT_ID, TIME_OUT);
            // set port parameters
            serialPort.setSerialPortParams(DATA_RATE,
                    SerialPort.DATABITS_8,
                    SerialPort.STOPBITS_1,
                    SerialPort.PARITY_NONE);
            input = serialPort.getInputStream();
            output = serialPort.getOutputStream();
            serialPort.notifyOnDataAvailable(true);

        } catch (Exception e) { e.printStackTrace();}
        return this;
    }

    /**
     * chiude la porta seriale così da liberare la comunicazione per la scrittura o la lettura
     * questo perchè è monodirezionale
     */
    private synchronized void close() {
        if (serialPort != null) {
            serialPort.removeEventListener();
            serialPort.close();
            System.out.println("\n-Porta chiusa da " + SerialManager.class.getSimpleName());
        }
    }


    public synchronized void sendData(byte... messagge) {

        if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {

            OutputStream outstream = null;
            try {
                outstream = serialPort.getOutputStream();
                outstream.write(messagge);
                //outstream.flush();

                for (byte m : messagge) {
                    System.out.print(m + " ");
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //close();
        try {
            System.out.println("\nSeriale in ascolto (in esadecimale)");
            serialPort.addEventListener(this);
        } catch (TooManyListenersException e) {
            e.printStackTrace();
        }
    }


    @Override
    public void serialEvent(final SerialPortEvent oEvent) {
        final StringBuilder builder = new StringBuilder();
        new Thread(new Runnable() {
            @Override
            public void run() {
                if (oEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
                    try {
                        int available = input.available();
                        byte[] chunk = new byte[available];
                        input.read(chunk, 0, available);

                        for (byte b : chunk) {
                            builder.append(b).append(" ");
                        }

                        System.out.print(builder.toString());
                    }
                    catch (IOException e) {
                        System.out.println("IO Error Occurred: " + e.toString());
                    }
                }
            }
        }).start();
    }
}

和主要活动:

public class SerialeEsegui
{
    public static void main(String args[]) {
        String PORT_ID = "COM4";
        int b =  unsignedToBytes((byte) 0x93);
        int c =  unsignedToBytes((byte) 0xf4);
        int f =  unsignedToBytes((byte) 0xfd);
        int z =  unsignedToBytes((byte) 0xf1);

        //Request example
        byte array[] = new byte[]{0x01, 0x03, 0x00,(byte) b, 0x00, 0x0b, (byte) c, 0x20};
        byte array1[] = new byte[]{0x01, 0x10, 0x00,(byte) b, 0x00, 0x0b, 0x16, 0x23,
                0x40, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
                0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, (byte) f, (byte) z};

        SerialManager.getInstance().setPORT_ID(PORT_ID).initialize().sendData(array);
    }

    public static int unsignedToBytes(byte b) {
        return b & 0xFF;
    }
}