How to Configure and Communicate with Serial Ports (RS-232, RS-422): Setting Baud Rate & Programming in Java, C/C++, Unix Shells, Windows/Hyperterminal

TutorialPedia Team

Date Updated

Serial communication has been a cornerstone of device interaction for decades, enabling data transfer between computers, embedded systems, industrial machinery, and sensors. Despite the rise of USB, Ethernet, and wireless protocols, serial ports remain prevalent in applications like industrial automation, robotics, IoT, and legacy hardware.

This blog demystifies serial port configuration and communication, focusing on two widely used standards: RS-232 (point-to-point, short-distance) and RS-422 (multi-drop, long-distance, differential signaling). We’ll cover key concepts like baud rate, data framing, and provide step-by-step guides to program serial ports in Java, C/C++, Unix shells, and Windows (including HyperTerminal/PuTTY). Whether you’re a hobbyist, engineer, or developer, this guide will equip you to reliably interface with serial devices.

Table of Contents#

  1. Basics of Serial Communication
    • 1.1 What is a Serial Port?
    • 1.2 Key Parameters: Baud Rate, Data Bits, Stop Bits, Parity, Flow Control
  2. RS-232 vs. RS-422: Standards Compared
  3. Baud Rate: What It Is and How to Choose
  4. Configuring & Communicating with Serial Ports
    • 4.1 Windows: HyperTerminal/PuTTY (GUI)
    • 4.2 Unix/Linux: Shell Commands (stty, cat, echo)
    • 4.3 Programming in C/C++ (Windows & Unix)
    • 4.4 Programming in Java (Cross-Platform)
  5. Troubleshooting Common Issues
  6. Conclusion
  7. References

1. Basics of Serial Communication#

1.1 What is a Serial Port?#

A serial port transmits data one bit at a time over a single wire (or pair of wires), unlike parallel ports that send multiple bits simultaneously. This simplicity makes serial communication ideal for long-distance or low-cost connections.

  • Physical Interface: RS-232 uses DB9/DB25 connectors; RS-422 often uses terminal blocks or DB9.
  • Wiring: For basic communication, only 3 wires are needed: TX (transmit), RX (receive), and GND (ground).

1.2 Key Parameters#

To communicate, both devices must agree on these parameters (often called “serial port settings”):

ParameterDescription
Baud RateNumber of bits transmitted per second (e.g., 9600, 115200). Must match on both ends.
Data BitsNumber of bits per data frame (5-8; 8 is standard for ASCII/UTF-8).
Stop BitsBits sent after data to signal end of a frame (1, 1.5, or 2; 1 is standard).
ParityError-checking bit (None, Even, Odd, Mark, Space; “None” is common).
Flow ControlPrevents data overflow (Hardware: RTS/CTS; Software: XON/XOFF; often disabled).

2. RS-232 vs. RS-422: Standards Compared#

FeatureRS-232RS-422
Signal TypeSingle-ended (voltage relative to GND).Differential (signal over two wires: A/B).
Max Distance~15 meters (at 9600 baud).~1200 meters (at 9600 baud).
Noise ImmunityLow (susceptible to interference).High (differential signaling rejects noise).
TopologyPoint-to-point (1 sender, 1 receiver).Multi-drop (1 sender, up to 10 receivers).
Voltage Levels±3V to ±25V (0 = +3V to +25V; 1 = -3V to -25V).±2V to ±6V (A > B = 1; B > A = 0).
Common UsesModems, legacy peripherals, short-distance sensors.Industrial networks, long-distance sensors, CNC machines.

3. Baud Rate: What It Is and How to Choose#

Baud rate defines the speed of data transfer (bits per second, bps). Despite the name, “baud” and “bps” are often used interchangeably in serial communication (strictly, baud = symbols/sec, but for UART, 1 symbol = 1 bit).

Key Considerations:#

  • Device Capability: Check the device datasheet for supported baud rates (e.g., Arduino supports 300–250000 bps).
  • Distance: Higher baud rates (e.g., 115200) work best for short distances (<10m); lower rates (e.g., 9600) for longer distances (>100m).
  • Noise: Electromagnetic interference (EMI) corrupts high-speed signals; use lower baud rates in noisy environments.

Common Baud Rates:#

9600 (most common), 19200, 38400, 57600, 115200, 230400, 460800.

4. Configuring & Communicating with Serial Ports#

4.1 Windows: HyperTerminal/PuTTY (GUI)#

HyperTerminal (deprecated in Windows 7+) and PuTTY (free, cross-platform) let you interact with serial ports via a GUI.

  1. Download PuTTY from putty.org.
  2. Open PuTTY, select Serial under “Connection type.”
  3. Enter:
    • Serial line: COM port (e.g., COM3; check Device Manager → Ports).
    • Speed: Baud rate (e.g., 9600).
  4. Click “Open.” A terminal window opens.
  5. Configure advanced settings (Data/Stop Bits, Parity) via Connection → Serial:
    • Data bits: 8
    • Stop bits: 1
    • Parity: None
    • Flow control: None

4.2 Unix/Linux: Shell Commands (stty, cat, echo)#

Unix/Linux systems expose serial ports as files (e.g., /dev/ttyUSB0 for USB-to-serial adapters, /dev/ttyS0 for hardware ports). Use these commands to configure and test:

Step 1: Identify the Serial Port#

List all serial ports:

ls /dev/tty* | grep -E "ttyUSB|ttyS"  # USB: ttyUSB0; Hardware: ttyS0  

Step 2: Configure the Port with stty#

stty sets serial parameters. Example (9600 baud, 8N1: 8 data bits, No parity, 1 stop bit):

stty -F /dev/ttyUSB0 9600 cs8 -cstopb -parenb -ixon  # -ixon disables XON/XOFF flow control  
  • cs8: 8 data bits.
  • -cstopb: 1 stop bit (default; cstopb = 2 stop bits).
  • -parenb: No parity (default; parenb = enable parity).

Step 3: Read/Write Data#

  • Read from the port (print incoming data to console):

    cat /dev/ttyUSB0  # Press Ctrl+C to stop  
  • Write to the port (send "Hello" to the device):

    echo "Hello" > /dev/ttyUSB0  
  • Bidirectional communication (use screen for interactive mode):

    screen /dev/ttyUSB0 9600  # Exit with Ctrl+A, then K  

4.3 Programming in C/C++ (Windows & Unix)#

Windows (Win32 API)#

Windows uses the CreateFile API to access serial ports. Here’s a minimal example to open a port, configure it, and send data:

#include <windows.h>  
#include <stdio.h>  
 
int main() {  
    HANDLE hCom;  
    DCB dcb;  
    BOOL fSuccess;  
 
    // Step 1: Open the serial port (COM3)  
    hCom = CreateFile(  
        "COM3",                  // Port name  
        GENERIC_READ | GENERIC_WRITE,  // Read/write access  
        0,                       // No sharing  
        NULL,                    // Default security  
        OPEN_EXISTING,           // Open existing port  
        0,                       // Non-overlapped I/O  
        NULL                     // No template  
    );  
    if (hCom == INVALID_HANDLE_VALUE) {  
        printf("Error opening COM3: %lu\n", GetLastError());  
        return 1;  
    }  
 
    // Step 2: Configure port settings (9600, 8N1)  
    fSuccess = GetCommState(hCom, &dcb);  
    if (!fSuccess) { printf("GetCommState failed: %lu\n", GetLastError()); return 1; }  
 
    dcb.BaudRate = CBR_9600;    // 9600 baud  
    dcb.ByteSize = 8;           // 8 data bits  
    dcb.StopBits = ONESTOPBIT;  // 1 stop bit  
    dcb.Parity = NOPARITY;      // No parity  
    dcb.fOutX = FALSE;          // Disable XON/XOFF  
    dcb.fInX = FALSE;  
 
    fSuccess = SetCommState(hCom, &dcb);  
    if (!fSuccess) { printf("SetCommState failed: %lu\n", GetLastError()); return 1; }  
 
    // Step 3: Send data  
    char* txBuffer = "Hello from Windows!\n";  
    DWORD bytesWritten;  
    fSuccess = WriteFile(hCom, txBuffer, strlen(txBuffer), &bytesWritten, NULL);  
    if (!fSuccess) { printf("WriteFile failed: %lu\n", GetLastError()); return 1; }  
    printf("Sent %lu bytes\n", bytesWritten);  
 
    // Step 4: Read data (example)  
    char rxBuffer[1024];  
    DWORD bytesRead;  
    fSuccess = ReadFile(hCom, rxBuffer, sizeof(rxBuffer)-1, &bytesRead, NULL);  
    if (fSuccess && bytesRead > 0) {  
        rxBuffer[bytesRead] = '\0';  
        printf("Received: %s\n", rxBuffer);  
    }  
 
    // Step 5: Close the port  
    CloseHandle(hCom);  
    return 0;  
}  

Unix/Linux (termios API)#

Unix uses the termios struct to configure serial ports. Here’s an example:

#include <stdio.h>  
#include <fcntl.h>  
#include <unistd.h>  
#include <termios.h>  
 
int main() {  
    int fd;  
    struct termios tty;  
 
    // Step 1: Open the port (/dev/ttyUSB0)  
    fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NONBLOCK);  // O_NONBLOCK for non-blocking read  
    if (fd < 0) { perror("Error opening port"); return 1; }  
 
    // Step 2: Configure port (9600, 8N1)  
    if (tcgetattr(fd, &tty) != 0) { perror("tcgetattr failed"); return 1; }  
 
    // Set baud rate (input/output)  
    cfsetospeed(&tty, B9600);  
    cfsetispeed(&tty, B9600);  
 
    tty.c_cflag &= ~PARENB;   // No parity  
    tty.c_cflag &= ~CSTOPB;   // 1 stop bit  
    tty.c_cflag &= ~CSIZE;    // Clear data bits  
    tty.c_cflag |= CS8;       // 8 data bits  
    tty.c_cflag &= ~CRTSCTS;  // Disable hardware flow control  
    tty.c_cflag |= CREAD | CLOCAL;  // Enable receiver, ignore modem controls  
 
    // Raw input (no line buffering)  
    tty.c_lflag &= ~ICANON;  
    tty.c_lflag &= ~ECHO;     // Disable echo  
 
    // Apply settings immediately  
    if (tcsetattr(fd, TCSANOW, &tty) != 0) { perror("tcsetattr failed"); return 1; }  
 
    // Step 3: Send data  
    char* txBuffer = "Hello from Unix!\n";  
    int bytesWritten = write(fd, txBuffer, strlen(txBuffer));  
    if (bytesWritten < 0) { perror("write failed"); return 1; }  
    printf("Sent %d bytes\n", bytesWritten);  
 
    // Step 4: Read data (non-blocking)  
    char rxBuffer[1024];  
    int bytesRead = read(fd, rxBuffer, sizeof(rxBuffer)-1);  
    if (bytesRead > 0) {  
        rxBuffer[bytesRead] = '\0';  
        printf("Received: %s\n", rxBuffer);  
    }  
 
    // Step 5: Close port  
    close(fd);  
    return 0;  
}  

4.4 Programming in Java (Cross-Platform)#

Java uses libraries like jSerialComm (modern, active) or RXTX (legacy) for serial communication. We’ll use jSerialComm for this example.

Step 1: Add jSerialComm Dependency#

For Maven, add to pom.xml:

<dependency>  
    <groupId>com.fazecast</groupId>  
    <artifactId>jSerialComm</artifactId>  
    <version>2.10.3</version>  
</dependency>  

Step 2: Java Example Code#

import com.fazecast.jSerialComm.SerialPort;  
 
public class SerialCommExample {  
    public static void main(String[] args) {  
        // Step 1: List available ports  
        SerialPort[] ports = SerialPort.getCommPorts();  
        System.out.println("Available ports:");  
        for (int i = 0; i < ports.length; i++)  
            System.out.println(i + ": " + ports[i].getSystemPortName());  
 
        // Step 2: Open the first port (adjust index as needed)  
        SerialPort port = ports[0];  
        if (!port.openPort()) {  
            System.err.println("Failed to open port");  
            return;  
        }  
 
        // Step 3: Configure port (9600, 8N1)  
        port.setBaudRate(9600);  
        port.setNumDataBits(8);  
        port.setNumStopBits(SerialPort.ONE_STOP_BIT);  
        port.setParity(SerialPort.NO_PARITY);  
        port.setFlowControl(SerialPort.FLOW_CONTROL_DISABLED);  
 
        // Step 4: Send data  
        String txData = "Hello from Java!\n";  
        byte[] txBuffer = txData.getBytes();  
        port.writeBytes(txBuffer, txBuffer.length);  
        System.out.println("Sent: " + txData);  
 
        // Step 5: Read data (blocking)  
        byte[] rxBuffer = new byte[1024];  
        int bytesRead = port.readBytes(rxBuffer, rxBuffer.length);  
        if (bytesRead > 0) {  
            String rxData = new String(rxBuffer, 0, bytesRead);  
            System.out.println("Received: " + rxData);  
        }  
 
        // Step 6: Close port  
        port.closePort();  
    }  
}  

5. Troubleshooting Common Issues#

  • No Data Received?

    • Check wiring: TX ↔ RX (cross over), GND ↔ GND.
    • Verify baud rate, parity, and stop bits match on both devices.
    • On Unix: Ensure permissions (sudo chmod 666 /dev/ttyUSB0 or add user to dialout group).
  • Garbled Data?

    • Mismatched baud rate (most common cause).
    • Electrical noise (use shielded cable for RS-232; RS-422 is more robust).
  • Permission Denied (Unix)?

    • Add your user to the dialout group: sudo usermod -aG dialout $USER (log out and back in).

6. Conclusion#

Serial communication via RS-232 and RS-422 remains a reliable, low-cost solution for connecting devices. By mastering parameters like baud rate and using tools like HyperTerminal, Unix shells, or programming languages (C/C++, Java), you can interface with everything from sensors to industrial machines. Remember: matching port settings and proper wiring are critical for success.

7. References#