Open In App

C++ Serial Port Connection

Last Updated : 19 Jun, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report

In C++, interacting with hardware devices often involves serial port communication. This serial port communication is used for the transfer of data between a computer or a device and external peripherals like printers, scanners, and modems among others. In serial port programming, data is send in a sequence, one bit at a time. In this article, we will go in depth of serial port connection in C++.

Core Concepts and Terminology

Before we dive into the program, we need to know the few terminology:

  • Serial Port: A physical interface facilitating sequential data transmission.
  • Baud Rate: The speed of data transfer, measured in bits per second (bps).
  • Data Bits: The number of bits used to represent a single character (typically 8).
  • Parity: An error-checking mechanism (often omitted).
  • Stop Bits: Marks the end of a character frame (usually 1 or 2).
  • Flow Control: Manages data flow to prevent buffer overflows (e.g., hardware or software flow control).

Serial Port Connection in C++

To read data from or write data to serial ports in C++, we can use either direct Win32 API calls (Windows-only) or third-party libraries that offer cross-platform compatibility and simplified APIs. But all these libraries will use the same concept internally so the algorithm or approach will be same. In this article, we will use two libraries, Boost::asio and terminos.h for Linux. Below is a breakdown of the steps involved:

Approach

  1. Open the Serial Port using the appropriate library functions or API calls to open the desired serial port.
  2. Specify parameters like port name, baud rate, data bits, parity, stop bits, and flow control settings.
  3. Adjust the serial port configuration parameters using the provided functions. This step allows customization of communication settings based on the connected device's requirements.
  4. Read/Write data using library functions or API calls to transmit and receive data via the serial port. Data can be handled in various formats (byte arrays, strings, custom structures).
  5. Handle errors implement error-checking mechanisms to manage potential issues (timeouts, transmission errors, invalid data). This might involve checking return values or utilizing exception handling provided by the library.
  6. Close the serial port resources after communication is finished to ensure proper cleanup and prevent resource conflicts.

C++ Programs to Create Serial Port Connection

Program 1: Using POSIX Functions (Unix-like Systems):

C++
// serial_posix.cpp
#include <cstring>
#include <errno.h>
#include <fcntl.h>
#include <iostream>
#include <termios.h>
#include <unistd.h>
using namespace std;

// Function to open the serial port
int openSerialPort(const char* portname)
{
    int fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC);
    if (fd < 0) {
        cerr << "Error opening " << portname << ": "
             << strerror(errno) << endl;
        return -1;
    }
    return fd;
}

// Function to configure the serial port
bool configureSerialPort(int fd, int speed)
{
    struct termios tty;
    if (tcgetattr(fd, &tty) != 0) {
        cerr << "Error from tcgetattr: " << strerror(errno)
             << endl;
        return false;
    }

    cfsetospeed(&tty, speed);
    cfsetispeed(&tty, speed);

    tty.c_cflag
        = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit characters
    tty.c_iflag &= ~IGNBRK; // disable break processing
    tty.c_lflag = 0; // no signaling chars, no echo, no
                     // canonical processing
    tty.c_oflag = 0; // no remapping, no delays
    tty.c_cc[VMIN] = 0; // read doesn't block
    tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout

    tty.c_iflag &= ~(IXON | IXOFF
                     | IXANY); // shut off xon/xoff ctrl

    tty.c_cflag
        |= (CLOCAL | CREAD); // ignore modem controls,
                             // enable reading
    tty.c_cflag &= ~(PARENB | PARODD); // shut off parity
    tty.c_cflag &= ~CSTOPB;
    tty.c_cflag &= ~CRTSCTS;

    if (tcsetattr(fd, TCSANOW, &tty) != 0) {
        cerr << "Error from tcsetattr: " << strerror(errno)
             << endl;
        return false;
    }
    return true;
}

// Function to read data from the serial port
int readFromSerialPort(int fd, char* buffer, size_t size)
{
    return read(fd, buffer, size);
}

// Function to write data to the serial port
int writeToSerialPort(int fd, const char* buffer,
                      size_t size)
{
    return write(fd, buffer, size);
}

// Function to close the serial port
void closeSerialPort(int fd) { close(fd); }

int main()
{
    // Replace with your serial port name
    const char* portname = "/dev/ttyS1";
    int fd = openSerialPort(portname);
    if (fd < 0)
        return 1;

    if (!configureSerialPort(fd, B9600)) {
        closeSerialPort(fd);
        return 1;
    }

    const char* message = "Hello, Serial Port!";
    if (writeToSerialPort(fd, message, strlen(message))
        < 0) {
        cerr << "Error writing to serial port: "
             << strerror(errno) << endl;
    }

    char buffer[100];
    int n = readFromSerialPort(fd, buffer, sizeof(buffer));
    if (n < 0) {
        cerr << "Error reading from serial port: "
             << strerror(errno) << endl;
    }
    else {
        cout << "Read from serial port: "
             << std::string(buffer, n) << endl;
    }

    closeSerialPort(fd);
    return 0;
}

// This code is contributed by Susobhan Akhuli


Output

Message sent: Hello, Serial Port!
Read from serial port: Hello, Serial Port!

Compile the Example Using Commands shown Below:

g++ -o serial_posix serial_posix.cpp -lboost_system -lpthread

Program 2: Using Boost.Asio (Cross-Platform):

C++
//
#include <boost/asio.hpp>
#include <iostream>

using namespace std;
using namespace boost;

// Function to configure the serial port
void configureSerialPort(asio::serial_port& serial,
                         const string& portname,
                         unsigned int baud_rate)
{
    // Open the specified serial port
    serial.open(portname);
    // Set the baud rate
    serial.set_option(
        asio::serial_port_base::baud_rate(baud_rate));
}

// Function to read data from the serial port
string readFromSerialPort(asio::serial_port& serial)
{
    char buffer[100]; // Buffer to store incoming data
    system::error_code ec;
    // Read data from the serial port
    size_t len
        = asio::read(serial, asio::buffer(buffer), ec);
    if (ec) {
        cerr << "Error reading from serial port: "
             << ec.message() << endl;
        return "";
    }
    // Return the read data as a string
    return string(buffer, len);
}

// Function to write data to the serial port
void writeToSerialPort(asio::serial_port& serial,
                       const string& message)
{
    system::error_code ec;
    // Write data to the serial port
    asio::write(serial, asio::buffer(message), ec);
    if (ec) {
        cerr << "Error writing to serial port: "
             << ec.message() << endl;
    }
}

int main()
{
    asio::io_service io; // Create an IO service
    // Create a serial port object
    asio::serial_port serial(io);

    try {
        // Configure the serial port (replace with your port
        // name)
        configureSerialPort(serial, "/dev/ttyS1", 9600);
    }
    catch (const exception& e) {
        cerr << "Error configuring serial port: "
             << e.what() << endl;
        return 1;
    }

    string message = "Hello, Serial Port!";

    // Write the message to the serial port
    writeToSerialPort(serial, message);
    cout << "Message sent: " << message << endl;

    // Read the response from the server
    string response = readFromSerialPort(serial);
    if (!response.empty()) {
        cout << "Response received: " << response << endl;
    }

    serial.close(); // Close the serial port
    return 0;
}

// This code is contributed by Susobhan Akhuli


Output

Message sent: Hello, Serial Port!
Response received: Hello, Serial Port!

Compilation

To compile these programs, we need to have Boost installed. Below are the steps to compile and run the client and server programs on a Unix-like system:

1. Install Boost (if not already installed):

sudo apt-get install libboost-all-dev

3. Compile the Boost Example:

g++ -o serial_boost serial_boost.cpp -lboost_system -lpthread

5. Run the Boost Example:

./serial_boost

Note: Adjust the serial port names (/dev/ttyS1, /dev/ttyS2) according to system's configuration.




Next Article
Practice Tags :

Similar Reads