树莓派3上使用Java与USB纸币接收器通信问题求助
排查USB转串口纸币接收器无响应的问题
看起来你已经有多年串口设备开发的经验了,不过在Java环境下操作USB转串口设备,有些细节和你之前的C/C++开发思路不太一样。结合你的代码和输出,我整理了几个最可能的问题点和改进建议:
1. 缺失串口核心参数配置
USB转串口设备本质还是串口设备,必须匹配波特率、数据位、停止位、奇偶校验、流控制这些参数才能正常通信——你之前在Windows/Unix用C开发时肯定会做这一步,但当前Java代码用RandomAccessFile直接读写设备文件,完全没处理这些配置,这大概率是设备无响应的核心原因。
首先去厂商文档里确认设备要求的串口参数(比如常见的9600波特率、8数据位、1停止位、无校验,或者带RTS/CTS流控制),然后必须用支持串口参数配置的Java库来操作,而不是通用的文件类。
2. RandomAccessFile不适合串口操作
串口是流式字符设备,RandomAccessFile是为随机访问文件设计的,用它来读写串口会带来缓冲、流控制等一系列问题。应该使用专门的串口通信库,比如jSerialComm(比老旧的RXTX更容易在树莓派上配置)。
3. 权限与设备访问细节
虽然你检查了文件的读写权限,但树莓派上的串口设备通常需要用户属于dialout组才能正常访问。执行以下命令添加权限,然后重启或重新登录:
sudo usermod -a -G dialout pi
改进后的示例代码(基于jSerialComm)
下面是适配你的需求的代码,已经包含了串口参数配置、正确的流操作和校验逻辑:
import com.fazecast.jSerialComm.SerialPort; import java.io.InputStream; import java.io.OutputStream; public class BillAcceptorComm { public static void main(String[] args) { // 遍历串口设备,找到目标纸币接收器 SerialPort targetPort = null; for (SerialPort port : SerialPort.getCommPorts()) { if (port.getDescriptivePortName().contains("EBDS_over_USB")) { targetPort = port; System.out.println("找到目标设备: " + port.getSystemPortName()); break; } } if (targetPort == null) { System.err.println("未找到目标设备!"); return; } // 配置串口参数(请根据厂商文档修改) targetPort.setComPortParameters(9600, 8, SerialPort.ONE_STOP_BIT, SerialPort.NO_PARITY); targetPort.setFlowControl(SerialPort.FLOW_CONTROL_RTS_ENABLED | SerialPort.FLOW_CONTROL_CTS_ENABLED); if (!targetPort.openPort()) { System.err.println("打开串口失败!"); return; } System.out.println("串口打开成功"); try (OutputStream out = targetPort.getOutputStream(); InputStream in = targetPort.getInputStream()) { boolean bOddCount = false; while (true) { // 构造发送指令(和你原代码逻辑一致) byte[] sendBuffer = new byte[8]; sendBuffer[0] = (byte) 0x02; // STX sendBuffer[1] = (byte) 0x08; sendBuffer[2] = bOddCount ? (byte) 0x10 : (byte) 0x11; bOddCount = !bOddCount; sendBuffer[3] = (byte) 0x1F; sendBuffer[4] = (byte) 0x0C; sendBuffer[5] = (byte) 0x00; sendBuffer[6] = (byte) 0x03; // ETX // 计算校验位 byte checkDigit = sendBuffer[1]; int idx = 2; while (sendBuffer[idx] != 0x03) { checkDigit = (byte) (sendBuffer[idx] ^ checkDigit); idx++; } sendBuffer[++idx] = checkDigit; // 发送指令并强制刷新输出流 out.write(sendBuffer); out.flush(); System.out.println("已发送: " + javax.xml.bind.DatatypeConverter.printHexBinary(sendBuffer)); // 接收响应(设置1秒超时) targetPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING, 1000, 0); byte[] recvBuffer = new byte[10]; int bytesRead = in.read(recvBuffer); if (bytesRead > 0) { System.out.println("读取到 " + bytesRead + " 字节数据"); System.out.println("响应内容: " + javax.xml.bind.DatatypeConverter.printHexBinary(recvBuffer, 0, bytesRead)); } else { System.out.println("未收到设备响应"); } Thread.sleep(1000); // 间隔1秒发送下一条指令 } } catch (Exception ex) { ex.printStackTrace(); } finally { targetPort.closePort(); } } }
额外注意事项
- 先确认厂商文档中的串口参数,必须和代码配置完全一致,否则设备不会响应。
jSerialComm的安装:可以直接从官网下载jar包,或者用Maven添加依赖:<dependency> <groupId>com.fazecast</groupId> <artifactId>jSerialComm</artifactId> <version>2.9.0</version> </dependency>- 可以用
minicom或screen工具先在树莓派终端测试串口通信,确认设备能正常响应,再回到Java代码调试。
内容的提问来源于stack exchange,提问作者Shane Price
相关产品推荐
相关产品推荐

