首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Java jSerialComm库串口通信(USB RS-485/232) 查询/应答、主动上报模式

查询/应答模式

要在Java中通过USB RS-485接口发送和接收特定的数据帧,你需要利用适当的串行通信库。在Java中,一个常见的选择是使用RXTX或jSerialComm库。这些库允许Java应用程序与串行端口进行通信。

以下是实现你描述的特定通信过程的步骤:

1. 添加串行通信库依赖

如果你选择使用jSerialComm库,可以在你的Maven pom.xml 文件中添加以下依赖:

com.fazecast

jSerialComm

2.6.2

2. 串行端口通信代码

以下是一个基本的示例代码,展示如何发送和接收数据:

import com.fazecast.jSerialComm.SerialPort;

public class RS485Communication {

public static void main(String[] args) {

SerialPort serialPort = SerialPort.getCommPort("COM3"); // 替换为你的端口名

serialPort.setComPortParameters(9600, 8, SerialPort.ONE_STOP_BIT, SerialPort.NO_PARITY); // 设置端口参数

serialPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING, 1000, 0);

if (serialPort.openPort()) {

System.out.println("Port opened successfully.");

} else {

System.out.println("Unable to open the port.");

return;

}

try {

// 发送数据

byte[] writeBuffer = new byte[]{(byte) 0xFA, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, (byte) 0xCE, (byte) 0xFA};

serialPort.writeBytes(writeBuffer, writeBuffer.length);

// 接收数据

byte[] readBuffer = new byte[1024]; // 调整数组大小以适应预期的响应长度

int numRead = serialPort.readBytes(readBuffer, readBuffer.length);

System.out.println("Read " + numRead + " bytes.");

// 将读取的字节转换为十六进制字符串

StringBuilder data = new StringBuilder();

for (int i = 0; i 

data.append(String.format("%02X ", readBuffer[i]));

}

System.out.println("Received data: " + data.toString());

} catch (Exception e) {

e.printStackTrace();

} finally {

serialPort.closePort();

}

}

}

3. 数据解析

在接收到数据后,你可能需要根据你的协议解析这些数据。例如,你可能需要检查帧头、SN码、命令字等,并从数据内容中提取所需的信息。

4. 注意事项

确保你的USB RS-485适配器已正确安装,并且你知道它在你的系统中的端口名称(如COM3、COM4等)。

适当设置串行通信参数(如波特率、数据位、停止位和奇偶校验位)以匹配你的设备要求。

如果你的系统不是基于Windows,串行端口名称可能会有所不同(如在Linux上通常是 /dev/ttyUSB0)。

异常处理对于处理通信错误和意外情况非常重要。

根据实际情况调整代码中缓冲区大小。

主动上报模式(监听)

1. 实现方法

一种是轮询模式(Polling),另一种是事件监听模式(Event Listener)。以下是关于这两种方法的说明:

轮询模式(Polling)

在轮询模式下,程序会周期性地(通常使用循环)检查串口是否有可用数据。

使用一个循环来检查串口COM3是否有可用数据,如果有数据,则读取并处理数据。

这种方式比较简单,但可能会造成CPU的浪费,因为程序会不断地检查串口,即使没有数据到达。

事件监听模式(Event Listener)

在事件监听模式下,程序注册了一个事件监听器(SerialPortEventListener),当串口有数据到达时,事件监听器会触发相应的事件。

使用事件监听器来监听串口CO3,当有数据到达时,事件监听器会调用serialEvent方法来处理数据。

这种方式相对更高效,因为程序只有在有数据到达时才会执行相应的处理代码,而不需要不断地轮询串口。

根据你的应用需求,选择轮询模式还是事件监听模式都是可以的。事件监听模式通常更加高效,特别是在需要实时处理数据或需要减少CPU占用的情况下。但需要注意的是,使用事件监听模式需要注册事件监听器,并确保程序不会在数据到达前退出。

无论哪种模式,都需要确保串口保持打开状态,以便能够接收数据。串口被打开后,程序进入一个循环或事件监听状态,以便随时接收数据。如果在数据到达之前关闭串口,数据将会丢失。

2. 事件监听模式

import com.fazecast.jSerialComm.SerialPort;

import com.fazecast.jSerialComm.SerialPortDataListener;

import com.fazecast.jSerialComm.SerialPortEvent;

public class RS485CommunicationEventListener {

public static void main(String[] args) {

SerialPort serialPort = SerialPort.getCommPort("COM3"); // 替换为你的端口名

serialPort.setComPortParameters(9600, 8, SerialPort.ONE_STOP_BIT, SerialPort.NO_PARITY); // 设置端口参数

/**

你可以根据具体的需求选择适当的超时模式来控制串口通信的行为。在你的代码中,如果希望立即输出接收到的数据,可以选择 TIMEOUT_NONBLOCKING 模式。如果希望等待数据并确保完整读取,可以选择 TIMEOUT_READ_BLOCKING 模式。

**/

serialPort.setComPortTimeouts(SerialPort.TIMEOUT_NONBLOCKING, 0, 0);

if (serialPort.openPort()) {

System.out.println("Port opened successfully.");

} else {

System.out.println("Unable to open the port.");

return;

}

// 创建数据监听器

serialPort.addDataListener(new SerialPortDataListener() {

@Override

public int getListeningEvents() {

return SerialPort.LISTENING_EVENT_DATA_AVAILABLE;

}

@Override

public void serialEvent(SerialPortEvent event) {

if (event.getEventType() == SerialPort.LISTENING_EVENT_DATA_AVAILABLE) {

// 接收数据

byte[] readBuffer = new byte[1024]; // 调整数组大小以适应预期的响应长度

int numRead = serialPort.readBytes(readBuffer, readBuffer.length);

if (numRead > 0) {

// 将读取的字节转换为十六进制字符串

StringBuilder data = new StringBuilder();

for (int i = 0; i 

data.append(String.format("%02X ", readBuffer[i]));

}

System.out.println("Received data: " + data.toString());

// 在这里进行收到数据的处理操作,例如加入阻塞队列,另一个模块消费队列解析收到的数据

}

}

}

});

// 程序会持续监听串口数据,无需手动创建新线程

}

}

3. 轮询模式

3.1 实现方法

为了让程序持续监听串口并输出收到的数据,可以在一个单独的线程中运行一个循环来读取串行端口。

import com.fazecast.jSerialComm.SerialPort;

public class RS485CommunicationPolling {

public static void main(String[] args) {

SerialPort serialPort = SerialPort.getCommPort("COM3"); // 替换为你的端口名

serialPort.setComPortParameters(9600, 8, SerialPort.ONE_STOP_BIT, SerialPort.NO_PARITY); // 设置端口参数

serialPort.setComPortTimeouts(SerialPort.TIMEOUT_NONBLOCKING, 0, 0);

if (serialPort.openPort()) {

System.out.println("Port opened successfully.");

} else {

System.out.println("Unable to open the port.");

return;

}

// 创建一个新线程来处理输入

Thread thread = new Thread(() -> {

while (true) {

try {

// 接收数据

byte[] readBuffer = new byte[1024]; // 调整数组大小以适应预期的响应长度

int numRead = serialPort.readBytes(readBuffer, readBuffer.length);

if (numRead > 0) {

// 将读取的字节转换为十六进制字符串

StringBuilder data = new StringBuilder();

for (int i = 0; i 

data.append(String.format("%02X ", readBuffer[i]));

}

System.out.println("Received data: " + data.toString());

// 收到数据的处理操作,例如加入阻塞队列,另一个模块消费队列解析收到的数据

}

} catch (Exception e) {

e.printStackTrace();

}

}

});

// 启动线程

thread.start();

}

}

上面创建了一个无限循环的线程来读取串行端口。它会持续检查串行端口,当有数据到达时,它会读取数据,将其转换成十六进制格式的字符串,然后输出。

请注意,这样的代码会创建一个永远不会停止的线程,除非你在代码中添加了一种方法来停止它,比如检测到特定的输入或者程序关闭时。在实际应用中,你通常需要一种机制来安全地停止线程,并在不需要它时关闭串行端口。

3.2 轮询模式是否会丢失数据?

在轮询模式下,程序会周期性地使用循环来检查串口是否有可用数据。如果在轮询的间隙内有数据到达串口,这些数据通常会被串口驱动程序缓存起来,等待程序读取。

串口驱动程序通常会提供一个输入缓冲区,用于存储从串口接收到的数据。当数据到达串口时,它们会被放入这个缓冲区中,直到程序来读取它们。如果数据到达速度比程序读取速度快,那么这些数据会在缓冲区中等待。

因此,在轮询模式下,如果程序在轮询间隙内没有及时读取串口数据,已到达但尚未读取的数据会保留在串口的输入缓冲区中,等待程序的读取。程序可以随时读取这些数据,只要它们仍然存在于缓冲区中。

需要注意的是,串口的输入缓冲区大小是有限的,如果数据到达速度非常快,缓冲区可能会被填满,导致后续到达的数据丢失。因此,程序应该以足够快的速度读取串口数据,以避免数据丢失。如果需要处理大量数据或数据到达速度非常快,可以考虑使用事件监听模式,以便在数据到达时立即处理,而不是周期性地轮询。这可以提高数据的实时性。

3.3 串口缓冲区

串口缓冲区通常由串口设备的驱动程序和操作系统共同管理,它们在计算机系统中的位置是软件实现的。

具体来说,串口缓冲区通常包括两个部分:

硬件缓冲区:这部分是串口硬件上的缓冲区,用于存储从外部串口接收到的数据和将要发送的数据。串口硬件上的缓冲区大小是有限的,通常是几个字节到数十个字节不等,具体取决于串口设备的规格和型号。硬件缓冲区的大小是固定的,不可更改。

操作系统缓冲区:这部分缓冲区位于操作系统内核中,用于管理串口数据的传输。当数据从串口硬件传输到计算机时,操作系统会将数据从硬件缓冲区复制到操作系统缓冲区中,然后提供给应用程序进行读取。同样,当应用程序要发送数据时,数据首先被写入操作系统缓冲区,然后由操作系统传输到串口硬件。

应用程序通过串口API(如Java中的javax.comm或其他串口库)与操作系统交互,操作系统负责管理硬件缓冲区和数据传输。

因此,串口缓冲区的管理是由操作系统和串口驱动程序协同工作的结果,它们确保数据能够以可靠的方式在计算机和串口设备之间传输。

  • 发表于:
  • 原文链接https://page.om.qq.com/page/OGD8Q3qj4zc64Qx3CkrvMEHA0
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券