杰瑞科技汇

Java串口通信如何实现数据收发?

Of course! Here's a comprehensive guide to using Java with a serial port, covering the most common libraries, a step-by-step example, and best practices.

The Challenge: No Built-in Support

Unlike languages like Python or C#, the standard Java Development Kit (JDK) does not include any built-in libraries for communicating with hardware devices like serial ports. This means you must use a third-party library.

The most popular and widely-used library for this purpose is RXTX. However, its original development has stalled. A more modern, actively maintained, and easier-to-use alternative is jSerialComm.

We will focus on jSerialComm as it is the recommended choice for new projects due to its simplicity and robustness.


Recommended Library: jSerialComm

jSerialComm is a cross-platform Java library that provides a simple API for serial communication. It's easy to add to your project and has a clean, modern interface.

Step 1: Add the Dependency

You need to include the jSerialComm JAR file in your project.

For Maven Users: Add this to your pom.xml file:

<dependency>
    <groupId>com.fazecast</groupId>
    <artifactId>jSerialComm</artifactId>
    <version>2.10.3</version> <!-- Check for the latest version -->
</dependency>

For Gradle Users: Add this to your build.gradle file:

implementation 'com.fazecast:jSerialComm:2.10.3' // Check for the latest version

Manual Download: You can also download the JAR file directly from the jSerialComm Maven Repository and add it to your project's classpath.


Step-by-Step Example with jSerialComm

This example will:

  1. List all available serial ports.
  2. Let the user choose one.
  3. Open the port with specific settings (baud rate, data bits, etc.).
  4. Write a string to the port.
  5. Read data from the port in a separate thread.
  6. Close the port gracefully.

The Code

import com.fazecast.jSerialComm.*;
import java.util.Scanner;
public class SerialPortExample {
    public static void main(String[] args) {
        // 1. Get a list of available serial ports
        SerialPort[] availablePorts = SerialPort.getCommPorts();
        if (availablePorts.length == 0) {
            System.out.println("No serial ports found. Exiting.");
            return;
        }
        System.out.println("Available serial ports:");
        for (int i = 0; i < availablePorts.length; i++) {
            System.out.println("[" + i + "] " + availablePorts[i].getSystemPortName() + ": " + availablePorts[i].getDescriptivePortName());
        }
        // 2. Let the user choose a port
        Scanner scanner = new Scanner(System.in);
        System.out.print("Enter the port number to open: ");
        int chosenPortIndex = scanner.nextInt();
        SerialPort chosenPort = availablePorts[chosenPortIndex];
        // 3. Open the port
        if (chosenPort.openPort()) {
            System.out.println("Port " + chosenPort.getSystemPortName() + " opened successfully.");
        } else {
            System.out.println("Failed to open port " + chosenPort.getSystemPortName());
            return;
        }
        // 4. Configure the port parameters
        chosenPort.setBaudRate(9600);     // Set baud rate
        chosenPort.setNumDataBits(8);     // Set data bits (8 is standard)
        chosenPort.setNumStopBits(1);     // Set stop bits (1 is standard)
        chosenPort.setParity(SerialPort.NO_PARITY); // Set parity (none is standard)
        chosenPort.setFlowControl(SerialPort.FLOW_CONTROL_DISABLED); // Disable flow control
        // Optional: Set a timeout for read operations (in milliseconds)
        chosenPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, 1000, 0);
        // 5. Start a separate thread for reading data from the port
        // This is crucial to avoid blocking the main thread
        Thread readThread = new Thread(() -> {
            System.out.println("Starting read thread...");
            while (chosenPort.isOpen()) {
                byte[] readBuffer = new byte[1024];
                int numRead = chosenPort.readBytes(readBuffer, readBuffer.length);
                if (numRead > 0) {
                    String receivedData = new String(readBuffer, 0, numRead);
                    System.out.println("Received: " + receivedData);
                }
            }
            System.out.println("Read thread finished.");
        });
        readThread.start();
        // 6. Write data to the port from the main thread
        scanner.nextLine(); // Consume the newline left by nextInt()
        System.out.println("Enter text to send (type 'exit' to quit):");
        while (true) {
            String input = scanner.nextLine();
            if ("exit".equalsIgnoreCase(input)) {
                break;
            }
            chosenPort.writeBytes(input.getBytes(), input.length());
        }
        // 7. Close the port
        System.out.println("Closing port...");
        chosenPort.closePort();
        System.out.println("Port closed.");
        scanner.close();
    }
}

Key Concepts and Best Practices

A. Port Configuration (Baud Rate, Data Bits, etc.)

These settings must match the configuration of the device you are connecting to (e.g., an Arduino, a GPS module, a sensor).

  • Baud Rate: The speed of communication (e.g., 9600, 19200, 115200). This is the most critical setting.
  • Data Bits: Usually 8.
  • Stop Bits: Usually 1.
  • Parity: A form of simple error checking. NO_PARITY is the most common.
  • Flow Control: Manages data flow to prevent buffer overflow. FLOW_CONTROL_DISABLED is typical for simple devices.

B. Reading vs. Writing

  • Writing: Simple and synchronous. You call writeBytes() and it blocks until the data is sent or an error occurs.

    String data = "Hello, Device!";
    chosenPort.writeBytes(data.getBytes(), data.length());
  • Reading: This is where you need to be careful. If you call readBytes() without a timeout, your program will block indefinitely, waiting for data. This is why the example uses a separate thread for reading.

C. Timeouts

You can set timeouts to prevent your program from hanging forever.

  • TIMEOUT_READ_SEMI_BLOCKING: The readBytes() method will wait for at least the specified timeout for the first byte. Once the first byte arrives, it will read all available bytes immediately. This is a good general-purpose mode.
  • TIMEOUT_READ_BLOCKING: Will wait forever for the exact number of bytes you requested.
  • TIMEOUT_SCANNER: Allows you to use java.util.Scanner on the input stream, which is convenient for reading text line by line.

D. Threading for Non-Blocking I/O

As shown in the example, running your read operation in a separate Thread is the standard and most effective way to handle incoming data without freezing your application's main loop (the UI thread in a GUI application, for instance).


Troubleshooting Common Issues

  1. NoSuchPortException or Port Not Listed:

    • Cause: The library cannot find the serial port.
    • Solutions:
      • Check Permissions: On Linux and macOS, you might need to be in the dialout or uucp group to access serial ports. Run groups to see your groups. Use sudo usermod -a -G dialout $USER (then log out and back in) to add yourself.
      • Check Device Manager: On Windows, open the Device Manager and look under "Ports (COM & LPT)". Is your device listed? Is it using a driver like usbserial or ch341?
      • Physical Connection: Is the device plugged in? Is the cable working?
  2. PortInUseException:

    • Cause: Another program (including another instance of your Java app) is already using the port.
    • Solutions:
      • Close the other program.
      • On Linux/Unix, you might need to kill a process that has the device file open (lsof /dev/ttyUSB0).
  3. Garbage or No Data Received:

    • Cause: Almost always a baud rate mismatch. Double-check that the baud rate in your Java code is exactly the same as the one configured on the device.
    • Other causes: Incorrect wiring, the device is not powered on, or the device is not sending data.
  4. java.lang.UnsatisfiedLinkError: no rxtxSerial in java.library.path:

    • Cause: This error occurs if you are using the old RXTX library and the native library file (.dll, .so, .jnilib) is not in the correct location or is the wrong architecture (e.g., 64-bit library on a 32-bit JVM).
    • Solution: Switch to jSerialComm. It handles native libraries automatically and is much easier to set up.
分享:
扫描分享到社交APP
上一篇
下一篇