【问题标题】:Java: read serial port (baudrate 921600)Java:读取串口(波特率 921600)
【发布时间】:2012-10-04 15:59:50
【问题描述】:

我正在开发一个 Java 软件,它必须能够读取设备通过串行 COM 端口发送的一些数据,通信速度对我来说非常重要,因此波特率设置为 921600。 一开始一切正常(因此它读取设备通过串行端口发送的正确数据),但过了一段时间,软件开始读取错误数据。 看起来软件太慢了,当它们进入输入缓冲区时它实际上丢失了一些数据(可能是当输入缓冲区第一次完全填满时)。 为了加快读取操作,我目前正在使用一种读取方法,在该方法中,软件每次读取时处理尽可能多的字节。 我还尝试使输入缓冲区大小更大(通过使用 serialPort.setInputBufferSize(byte) 方法,但它没有解决我的问题) 那么有没有人用java进行过快速的串行通信?我错过了什么吗? 为什么一段时间一切正常,然后就停止正常工作?

这是我的读取部分(甚至驱动)的代码,请跳过数据转换部分,因为每个数据实际上是由2个字节组成的,所以我也必须在将它们写入之前将它们组合成一个txt 文件。

/**
 *
 * @param evt
 */
@Override
public void serialEvent(SerialPortEvent evt) {

     switch(evt.getEventType()) {

        case SerialPortEvent.OUTPUT_BUFFER_EMPTY:
            System.out.println("THE OUTPUT BUFFER IS EMPTY");
            break;

        case SerialPortEvent.DATA_AVAILABLE:
            try {     

                while(SerialPortEvent.DATA_AVAILABLE == 1) {


                   num_bytes = input.available();
                   array = new byte[num_bytes];

                   bytes_read = input.read(array, 0, num_bytes);

                   dato = new short[bytes_read];
                   datoc = new int[bytes_read/2];
                   datos = new String[bytes_read/2];


                   for(j=0;j<bytes_read;j++){                           
                       dato[j] = (short) (((byte) array[j]) & 0xff);
                   }

                   k = 0;
                   for(j=0;j<(bytes_read/2);j++){

                       datoc[j] = dato[k];
                       datoc[j] = (datoc[j]<<8) + dato[k+1];
                       datoc[j] = datoc[j] & 0xffffffff;  
                       k = k + 2;
                   }

                   for(j=0;j<(bytes_read/2);j++){

                       System.out.println(datoc[j]);
                       datos[j] = Integer.toString(datoc[j]);
                       output1.write(datos[j] + " ");
                   }

               }
            } catch(IOException ex) {
              logText = "Failed to read data. (" + ex.toString() + ")";
              System.out.println(logText);
            }
            break;

    }

【问题讨论】:

  • 一段时间是多久?如果您可以在数据失败前处理一个小时的数据,我猜您可能有内存泄漏,或者在 Java 进行垃圾收集时它会失败(只是猜测 Java 会这样做)。另外,在您完成最后一个事件的处理之前,串行事件是否再次触发?

标签: java io serial-port


【解决方案1】:

听起来您的程序未能足够快地为传入的数据提供服务;它会工作一段时间,因为输入进入缓冲区,并且当您清空缓冲区时,会有更多空间用于更多输入。但是如果数据进来的速度比你处理它的速度要快,那么最终你的缓冲区就会满了,数据仍然进来,无处可去。在串行通信中,此类数据被转储到(虚拟)楼层是/是典型的。

设置状态指示“缓冲区溢出”也很常见。我要检查的第一件事是在您用来读取串行数据的任何库中是否可以使用此状态,并查看它是否/何时设置。这将验证上述情况是否正在发生。

要检查的另一件事是 XON/XOFF 功能,如果它在您的环境中是合理的。这是/是某些串行通信的一个特性,它允许接收器向发送器指示其缓冲区几乎已满并停止发送 (XOFF),直到被告知可以重新开始 (XON)。并非所有硬件和软件都支持此功能。

如果无论出于何种原因这都不起作用并且这确实是问题所在,那么您将不得不更好地处理数据或进一步缓冲数据。一个简单的蛮力方法是在字节进入时将它们写入存储,并在单独的线程中读取它们。例如,如果这是一个传统的计算机系统,您可以将它们写入磁盘,然后处理磁盘文件,在一个线程中打开它进行读取并在另一个线程中写入(多么有趣!)。

【讨论】:

  • XON/XOFF 是软件流控,所以与硬件支持无关。使用 XON/XOFF 非常少见。更常见的流量控制解决方案是硬件 RTS/CTS。绝大多数硬件都支持 RTS/CTS。
  • 要支持XON/XOFF,必须有全双工;也许我回溯到历史太远了——我怀疑那里有很多半双工系统——但确实需要硬件支持来发送信号的软件。你说得对,它是基于软件的,我确实忘记提到 RTS/CTS —— OP 应该看看,我很高兴你提到它。
【解决方案2】:

降低串行通信速度的原因是使用了System.out.println()。没有它,数据接收最终会很好

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-30
    • 1970-01-01
    • 2019-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多