问题:RXTX接收不到数据

7

我已经使用RXTX大约一年了,没有太多问题。我刚开始一个新的程序来与新的硬件交互,所以我重用了我在其他项目中使用过的connect()方法,但是我遇到了一个我从未见过的奇怪问题。

问题

设备运行正常,因为当我使用HyperTerminal连接时,我发送和接收到我期望的东西,并且Serial Port Monitor(SPM)反映了这一点。

然而,当我运行我编写的简单HyperTerminal克隆程序来诊断我主应用程序中遇到的问题时,根据SPM发送字节,但是没有接收到任何内容,并且我的SerialPortEventListener从未触发。即使我在主循环中检查可用数据,reader.ready()返回false。如果我忽略此检查,则会得到异常,详情如下。

connect()方法的相关部分

// Configure and open port
port = (SerialPort) CommPortIdentifier.getPortIdentifier(name)
                                      .open(owner,1000)
port.setSerialPortParams(baud, databits, stopbits, parity);
port.setFlowControlMode(fc_mode);
final BufferedReader br = new BufferedReader(
                            new InputStreamReader(
                              port.getInputStream(), 
                              "US-ASCII"));

// Add listener to print received characters to screen
port.addEventListener(new SerialPortEventListener(){
  public void serialEvent(SerialPortEvent ev) {
    try {
      System.out.println("Received: "+br.readLine());
    } catch (IOException e) { e.printStackTrace(); }
  }   
});
port.notifyOnDataAvailable();

异常

java.io.IOException: Underlying input stream returned zero bytes
        at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:268)
        at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)
        at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
        at java.io.InputStreamReader.read(InputStreamReader.java:167)
        at java.io.BufferedReader.fill(BufferedReader.java:136)
        at java.io.BufferedReader.read(BufferedReader.java:157)
        at <my code>

重要问题(再次提出)

我认为我已经排除了所有可能的硬件问题,那么我的代码或RXTX库有什么问题呢?

编辑:有趣的事情

当我在从Java发送应该获得响应的一堆命令之后打开HyperTerminal时,所有响应都会立即显示出来,就好像它们被放在某个缓冲区中,但无法使用。

编辑2:尝试了一些新的东西,结果相同

我运行了在这里找到的代码示例,结果相同。没有数据进入,但当我切换到一个新程序时,所有数据都一起出现了。

编辑3

硬件是好的,甚至另一台计算机也有同样的问题。我没有使用任何USB适配器。

我开始使用PortMon,它给我提供了一些有趣的结果。HyperTerminal和RXTX没有使用相同的设置,而且RXTX总是轮询端口,不像HyperTerminal,但我仍然看不到哪些设置会影响这个问题。一旦我能够从不断轮询中隔离出配置,我将发布我的PortMon日志。

编辑4

有可能是在过去的三个月中的某次Windows更新导致了这个问题吗?它曾经搞砸过我的一个基于MATLAB的mex程序。

编辑5

我还注意到HyperTerminal、RXTX和我找到的一个与设备通信的单独程序之间存在一些不同之处(但它不能做我想要的事情,这就是为什么我正在编写自己的程序)

  • HyperTerminal - 设置为无流控制,但串口监视器的RTS和DTR指示灯是绿色的
  • 其他程序-不确定它认为它正在使用什么设置,但只有SPM的RTS指示灯是绿色的
  • RXTX-无论我设置什么流控制,只有SPM的CTS和DTR指示灯亮着。

从串口监视器的帮助文件中(改编):

the indicators display the state of the serial control lines

  RTS - Request To Send
  CTS - Clear To Send
  DTR - Data Terminal Ready
6个回答

7

好的,很抱歉让你等这么久才回答这个问题。以下是我如何使事情正常运转的方法。

注意:这种方法并不适用于所有人,请在将其复制/粘贴到自己的代码之前阅读下面的内容

public void connect(CommPortIdentifier portId) throws Failure {
    if (portId == null)
        throw new Failure("No port set");

    try { port = (SerialPort) portId.open(getClass().getName(), 10000); } 
    catch (PortInUseException e) {
        throw new Failure("Port in use by " + e.currentOwner,e); }

    try {
        port.setSerialPortParams(9600, SerialPort.DATABITS_8,
                SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
        port.setFlowControlMode(SerialPort.FLOWCONTROL_RTSCTS_IN
                              | SerialPort.FLOWCONTROL_RTSCTS_OUT);
    } catch (UnsupportedCommOperationException e) { throw new Failure(e); }

    port.setRTS(true);

    // More setup
}

因此,在我的情况下,问题是我的特定设备需要 RTS 流控。其他设备可能需要不同的东西(CTS、XON/XOFF),因此请检查该设备的手册。默认情况下,RXTX 禁用所有流控机制(与 Hypertrm 或其他程序不同)。启用每个流控机制是一个两步过程。
  1. 一旦你有了 SerialPort 对象,请调用 setFlowControlMode() 方法,并按位或('|')必要的 SerialPort.FLOWCONTROL_ 常量。
  2. 将适当的流控设置为 true 或 false(就像我使用 port.setRTS(true) 一样)。
对于其他遇到类似问题的人,如果这不起作用,我建议:
  1. 使用串口监视程序,例如 Serial Port Monitor 和/或 PortMon(都是 Windows)来查看实际发生了什么。
  2. 向 rxtx@qbang.org 发送电子邮件联系 RXTX 开发人员(他们非常乐意帮助)。

@drhorrible 我明白你如何在serialport对象上设置flowcontrol。但是我正在尝试弄清楚你如何检测到已发送流控制字符?我正在使用XON XOFF与RTS不同,但我认为它应该是类似的。0x13、0x11是我期望在触发serialEvent时看到的字符?你是如何在代码中检测到它们的? - ril3y
@ril3y我不记得曾经看到过流量控制字符。在串口监视器或PortMon(答案中的链接)中,我看到一个窗口右下角的一组红色和绿色圆圈,其中一个是CTS,另一个是XON / XOFF。当一切正常时,它们为绿色。否则,它们为红色。 - Nate Parsons
非常感谢您提供详细的解决方案。我花了整整两天时间来调试,但现在终于有了一个解决方法。 - HRJ

3

对于这个问题,有一个更简单的解决方案。这就是我所做的:

BufferedReader br = new BufferedReader(new InputStreamReader(in));
    String line;

    while (keepRunning) {
        try {
            while ((br.ready()) && (line = br.readLine()) != null) {
....
}

如果在读取缓冲区之前检查缓冲区“是否就绪”,那么应该不会出现问题。


2

好的,我知道这个帖子非常老,但是这些解决方案都不适用于我。 我遇到了同样的问题,并尝试了一切来修复它,但都没有成功。 然后我研究了一下导致该问题的原因,并且在不涉及串行通信时,它会发生在文件末尾。 因此,我想我需要在Java应用程序接收到的任何内容结尾添加回车符(\n)。 幸运的是,它确实为我解决了这个问题! 希望这能帮助到新手,因为我不指望能帮助到已经在这个帖子上的人...


0

可能有些简单,但总得从某个地方开始...

端口正在使用中吗?而不是:

port = (SerialPort) CommPortIdentifier.getPortIdentifier(name)
                                      .open(owner,1000)

怎么样:

CommPortIdentifier portIdentifier;
try {
    portIdentifier = CommPortIdentifier.getPortIdentifier(name);
} catch (NoSuchPortException nspe) {
    // handle?
}
if (portIdentifier.isCurrentlyOwned()) {
    // handle?
}
port = portIdentifier.open(owner, 1000);
if (!(port instanceof SerialPort)) {
    // handle?
}

你有没有吞掉任何异常?


谢谢,但是 connect() 方法的其余部分会捕获所有这些异常并打印堆栈跟踪信息并退出。 - Nate Parsons

0
如果您在使用RXTX时,即使您首先检查br.readline()== null并且已经读取了字符,仍然遇到“java.io.IOException:Underlying input stream returned zero bytes”的问题,请尝试使用try / catch进行以下简单修复:
String line;
while (true){   
    try{
        line = br.readLine();
    }catch(IOException e){
        System.out.println("No more characters received");
        break;
    }
    //Print the line read
    if (line.length() != 0) 
        System.out.println(line);
}

我做了一些搜索,看起来这是解决这个问题的最佳/最简单的方法。

编辑:我收回了。我尝试过这个方法,但仍然遇到了一些问题。我建议直接使用原始InputStream,并使用InputStream.read()实现自己的read/readLine方法。这对我有用。


0

我几个月前尝试了RXTX,并遇到了类似的问题。我建议两件事:

  1. 使用com0com创建虚拟串口。启用跟踪日志。比较你使用Hyperterminal和运行自己的程序时的日志,差异将突显你做错的地方。

  2. 依我之见,RXTX的设计存在缺陷,其实现相当有bug(看看它的源代码,真是一团糟!)。我在http://kenai.com/projects/jperipheral发布了一个替代库,但需注意以下几点:它只适用于Windows操作系统,且没有预构建二进制文件。这两者都将在不久的将来发生改变。如果你有兴趣试用,请使用http://desktopbeautifier.com/Main/contactus给我发送电子邮件,我会发送给你一个预构建版本。


1
现在也有purejavacomm可用。 - HRJ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接