Overview

The project is a simple application built using the Qt framework for facilitating serial communication between a computer and external devices, such as microcontrollers, sensors, or other hardware components. The application provides a graphical user interface (GUI) for users to interact with the serial port, send commands, receive data, and log communication activities.

Software Requirements

  • QT Creator
  • Arduino Ide

Hardware Requirements

S.NoCOMPONENTSQUANTITY
1FTDI FT232Rl FT2321Buy FTDI Module From Amazon
2USB 2.0 Cable – A-Male to Mini-B3Buy USB 2.0 Cbale – A-Male to Mini-B
3Breadboard1Buy Breadboard From Amazon
4Jumper Wires1(set)Buy Jumper Wires From Amazon

Key Features

  1. Port Selection: Users can select the desired serial port from a list of available ports detected by the system.
  2. Baud Rate Configuration: The application allows users to configure the baud rate for establishing communication with the connected device. It also supports custom baud rates.
  3. Connection Management: Users can establish and terminate connections to the selected serial port with dedicated connect and disconnect buttons.
  4. Data Reception: The application continuously monitors the serial port for incoming data. Received data is displayed in real-time on the user interface.
  5. Timestamping: Each received data packet is timestamped to record the time of reception, providing a chronological log of communication events.
  6. Data Logging: Users can save the received data along with timestamps to a text file for future analysis or reference.
  7. User Feedback: The application provides feedback messages to users, informing them about the status of serial port connections and the success of file-saving operations.

Usage Scenario

The application is useful for developers, hobbyists, and engineers who need to interface with external devices via serial communication. It simplifies the process of establishing and managing serial connections, allowing users to focus on data exchange and analysis. The ability to log communication activities enhances debugging and troubleshooting efforts, while the intuitive user interface improves overall usability.

Future Improvements

Future iterations of the application could include additional features such as:

  • Support for different serial protocols (e.g., RS-232, RS-485).
  • Enhanced error handling and recovery mechanisms.
  • Graphical visualization of received data.
  • Integration with other Qt modules for extended functionality.

Step by step code execution process

Step 1 Create UI

  1. QLineEditor: for serial port communication display
  2. Qcombobox : for BaurdRate selection
  3. QPushButton: for Connect button
  4. QPushButton: for Disconnect button
  5. QPushButton: for Clear button
  6. QTestEdit : for serial Received_RawData
  7. QPushButton: for SaveButton button

Step 2: Constructor

The constructor initializes the UI components and sets up the serial port list. It also connects the signal currentIndexChanged(int) from the BaudRate ComboBox to the slot checkCustomBaudRatePolicy(int)

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include <QDebug>
#include <QTimer>
#include <QFileDialog>
#include <QMessageBox>
#include <QDateTime>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    // Update the list of available serial ports when the application starts
    // Clear existing port list
    ui->ComPort->clear();

    // Get list of available serial ports
    QList<QSerialPortInfo> availablePorts = QSerialPortInfo::availablePorts();

    // Populate the ComboBox with port names
    for(const QSerialPortInfo &portInfo : availablePorts) {
        ui->ComPort->addItem(portInfo.portName());
    }

    // Connect the activated signal of the BaudRate ComboBox to checkCustomBaudRatePolicy slot
    connect(ui->BaudRate, SIGNAL(currentIndexChanged(int)), this, SLOT(checkCustomBaudRatePolicy(int)));
}

Explanation

  1. The constructor initializes the UI components defined in ui_mainwindow.h.
  2. It retrieves a list of available serial ports and populates them into the ComboBox named ComPort.
  3. It connects the signal currentIndexChanged(int) from the BaudRate ComboBox to the slot checkCustomBaudRatePolicy(int).

Step 3 QComboBox for COM Port Selection

// Get list of available serial ports
QList<QSerialPortInfo> availablePorts = QSerialPortInfo::availablePorts();

// Populate the ComboBox with port names
for(const QSerialPortInfo &portInfo : availablePorts) {
    ui->ComPort->addItem(portInfo.portName());
}

Explanation

  1. This QComboBox widget named ComPort is used for selecting the serial port for communication.
  2. When the application starts (in the constructor), it retrieves a list of available serial ports using QSerialPortInfo::availablePorts().
  3. Then, it populates the ComboBox with the names of these available ports using addItem().

Step 4: Connect Button Slot

The on_Connect_clicked() function is a slot connected to the Connect button. It sets up a serial port connection based on the selected port and baud rate.

void MainWindow::on_Connect_clicked()
{
    // Create a new QSerialPort instance
    serial = new QSerialPort(this);
    timer = new QTimer(this);

    // Set the selected port name and baud rate
    serial->setPortName(ui->ComPort->currentText());
    serial->setBaudRate(ui->BaudRate->currentText().toInt());

    // Set serial port parameters
    serial->setDataBits(QSerialPort::Data8);
    serial->setParity(QSerialPort::NoParity);
    serial->setStopBits(QSerialPort::OneStop);
    serial->setFlowControl(QSerialPort::NoFlowControl);

    // Open the serial port
    serial->open(QIODevice::ReadWrite);

    // Update UI with connection status
    if(serial->isOpen()){
        qDebug()<< "Serial Port is Connected.";
        ui->Connection->setText("Serial Port is Connected.");
    } else {
        ui->Connection->setText("Serial Port is not Connected.");
        qDebug()<< "Serial Port is not Connected.";
        qDebug()<< serial->error();
    }

    // Connect timer's timeout signal to Receive_Data slot
    connect(timer, &QTimer::timeout, this, &MainWindow::Receive_Data);
    timer->start(1000); // Start timer for periodic data reception
}

Explanation:

  • This function is called when the Connect button is clicked.
  • It creates a new QSerialPort instance and sets its properties like port name, baud rate, data bits, parity, stop bits, and flow control.
  • Then it opens the serial port for reading and writing.
  • If the port is opened successfully, it updates the UI with the connection status.
  • It also starts a timer to periodically check for received data.

Step 5: Baud Rate Policy Checker

The checkCustomBaudRatePolicy(int idx) function checks if the selected baud rate is a custom value and allows the user to input their own baud rate if needed.

void MainWindow::checkCustomBaudRatePolicy(int idx)
{
    const bool isCustomBaudRate = !ui->BaudRate->itemData(idx).isValid();
    ui->BaudRate->setEditable(isCustomBaudRate); // Allow editing if it's a custom baud rate
    if(isCustomBaudRate){
        ui->BaudRate->clearEditText();
        QLineEdit *edit = ui->BaudRate->lineEdit();
        QIntValidator *validator = new QIntValidator(0, 400000, this); // Validate custom baud rate
        edit->setValidator(validator);
    }
}

Explanation

  • This function is called when the Baud Rate ComboBox’s selection changes.
  • It checks if the selected baud rate is a custom
    // Connect the activated signal of the BaudRate ComboBox to checkCustomBaudRatePolicy slot
    connect(ui->BaudRate, SIGNAL(currentIndexChanged(int)), this, SLOT(checkCustomBaudRatePolicy(int)));

Explanation

  • It connects the signal currentIndexChanged(int) from the BaudRate ComboBox to the slot checkCustomBaudRatePolicy(int).

Step 6: Disconnect Button Slot

  • The on_Disconnect_clicked() function is a slot connected to the Disconnect button. It closes the serial port connection.
void MainWindow::on_Disconnect_clicked()
{
    if(serial->isOpen())
    {
        serial->close(); // Close the serial port
        timer->stop(); // Stop the timer
        ui->Connection->setText("Disconnected"); // Update UI with disconnection status
    }
}

Explanation:

  • This function is called when the Disconnect button is clicked.
  • It checks if the serial port is open. If it is, it closes the port and stops the timer.
  • Finally, it updates the UI to show the disconnection status.

Step 7: Clear Button Slot

The on_Clear_clicked() function is a slot connected to the Clear button. It clears the received data display area.

void MainWindow::on_Clear_clicked()
{
    ui->Received_RawData->clear(); // Clear the received data display area
}

Explanation

  • This function is called when the Clear button is clicked.
  • It clears the text displayed in the Received_RawData QTextEdit widget.

Step 8: Receive Data Slot

The Receive_Data() function is a slot that is periodically called by a timer to read data from the serial port.

void MainWindow::Receive_Data()
{
    if (serial->isOpen()) {
        QByteArray data = serial->readAll(); // Read data from the serial port
        QString receivedData = QString::fromLatin1(data); // Convert the data to a QString
        QString timestamp = QDateTime::currentDateTime().toString("[HH:mm:ss.zzz] "); // Get current timestamp
        ui->Received_RawData->append(receivedData); // Append received data to the display area
        logData.append(timestamp + receivedData); // Append received data with timestamp to log
    }
}

Explanation

  • This function is called periodically by the timer to read data from the serial port.
  • If the serial port is open, it reads all available data from the port.
  • It converts the received data to a QString and appends it to the Received_RawData QTextEdit widget.
  • It also appends the received data along with a timestamp to a log for later reference.

step 9  QPushButton for Saving Data

void MainWindow::on_SaveButton_clicked()
{
    QString filePath = QFileDialog::getSaveFileName(this, tr("Save File"), "", tr("Text Files (*.txt)"));
    if (filePath.isEmpty()) {
        return; // User canceled the dialog
    }

    QFile file(filePath);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        QMessageBox::critical(this, tr("Error"), tr("Could not open file for writing"));
        return;
    }

    // Write log data with timestamps to the file
    QTextStream out(&file);
    out << logData;

    file.close();

    QMessageBox::information(this, tr("Success"), tr("File saved successfully"));
}

Explanation

  • This QPushButton widget, named SaveButton, allows users to save the received data log to a text file.
  • When clicked, it triggers the on_SaveButton_clicked() function.
  • Inside this function, a file dialog (QFileDialog) is opened for the user to choose a location to save the file.
  • If the user cancels the dialog or doesn’t provide a file name, the function returns without further action.
  • If a file is selected, it opens the file in write-only text mode using QFile.
  • It then writes the log data (stored in logData) to the selected file using a QTextStream.
  • Finally, it displays a success message using QMessageBox if the file is saved successfully.

Final Source Code

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include <QDebug>
#include <QTimer>
#include <QFileDialog>
#include <QMessageBox>
#include <QDateTime>


MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    // Update the list of available serial ports when the application starts
    // Clear existing port list
    ui->ComPort->clear();

    // Get list of available serial ports
    QList<QSerialPortInfo> availablePorts = QSerialPortInfo::availablePorts();

    // Populate the ComboBox with port names
    for(const QSerialPortInfo &portInfo : availablePorts) {
        ui->ComPort->addItem(portInfo.portName());

    }
    // Connect the activated signal of the BaudRate ComboBox to checkCustomBaudRatePolicy slot
    connect(ui->BaurdRate, SIGNAL(currentIndexChanged(int)), this, SLOT(checkCustomBaudRatePolicy(int)));
//    connect(ui->SaveButton, &QPushButton::clicked, this, &MainWindow::on_SaveButton_clicked);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_Connect_clicked()
{

    serial = new QSerialPort(this);                                             //making object of class QSerialPort
    timer = new QTimer(this);
    serial->setPortName(ui->ComPort->currentText());
    serial->setBaudRate(ui->BaurdRate->currentText().toInt()); // Set baud rate based on current /*selection*/

    serial->setBaudRate(ui->BaurdRate->currentText().toInt());
    //    serial->setBaudRate(QSerialPort::Baud9600);
    serial->setDataBits(QSerialPort::Data8);
    serial->setParity(QSerialPort::NoParity);
    serial->setStopBits(QSerialPort::OneStop);
    serial->setFlowControl(QSerialPort::NoFlowControl);
    serial->open(QIODevice::ReadWrite);                                       //connecting the serial port

    if(serial->isOpen()){

        qDebug()<< "Serial Port is Connected.";
        ui->Connection->setText("Serial Port is Connected.");
    }
    else{
        ui->Connection->setText("Serial Port is not Connected.");
        qDebug()<< "Serial Port is not Connected.";
        qDebug()<< serial->error();
    }
    connect(timer,&QTimer::timeout,this,&MainWindow::Receive_Data);
    timer->start(1000);

}

void MainWindow::on_Disconnect_clicked()
{
    if(serial->isOpen())
    {
        serial->close();
        timer->stop(); // Stop timer when disconnected
        ui->Connection->setText("Disconnected");
    }
}

void MainWindow::on_Clear_clicked()
{
    ui->Received_RawData->clear();
}

void MainWindow::Receive_Data()
{
    if (serial->isOpen()) {
        QByteArray data = serial->readAll();
        QString receivedData = QString::fromLatin1(data);
        QString timestamp = QDateTime::currentDateTime().toString("[HH:mm:ss.zzz] "); // Change timestamp format as desired
        ui->Received_RawData->append(receivedData);
        logData.append(timestamp + receivedData); // Append to log data
    }
}



void MainWindow::checkCustomBaurdatepolity(int idx)
{
    const bool isCustomBaudRate = !ui->BaurdRate->itemData(idx).isValid();
    ui->BaurdRate->setEditable(isCustomBaudRate);
    if(isCustomBaudRate){
        ui->BaurdRate->clearEditText();
        QLineEdit *edit = ui->BaurdRate->lineEdit();
        QIntValidator *validator = new QIntValidator(0,400000, this);
        edit->setValidator(validator);
    }
}

void MainWindow::on_SaveButton_clicked()
{
    QString filePath = QFileDialog::getSaveFileName(this, tr("Save File"), "", tr("Text Files (*.txt)"));
    if (filePath.isEmpty()) {
        return; // User canceled the dialog
    }

    QFile file(filePath);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        QMessageBox::critical(this, tr("Error"), tr("Could not open file for writing"));
        return;
    }

    // Write log data with timestamps to the file
    QTextStream out(&file);
    out << logData;

    file.close();

    QMessageBox::information(this, tr("Success"), tr("File saved successfully"));
}

main.cpp

#include "mainwindow.h"

#include <QApplication>
#include <QtSerialPort/QSerialPort>
#include <QDebug>
#include <QTime>
#include <QTimer>

#include <QSerialPortInfo>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QSerialPort>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_Connect_clicked();

    void on_Disconnect_clicked();

    void on_Clear_clicked();
    void Receive_Data();

    void on_SaveButton_clicked();
    void checkCustomBaurdatepolity(int idx);
private:
    Ui::MainWindow *ui;
    QSerialPort *serial;
    QTimer *timer;
    QString logData; // Declare logData variable
};
#endif // MAINWINDOW_H

Serial_Communication.pro

QT       += core gui serialport

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    mainwindow.cpp

HEADERS += \
    mainwindow.h

FORMS += \
    mainwindow.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

By Devilal

One thought on “Revolutionize Serial Communication with this Qt-Based Application”

Leave a Reply

Your email address will not be published. Required fields are marked *