QT 实现的串口助手

发布于:2025-02-28 ⋅ 阅读:(9) ⋅ 点赞:(0)

一、前言

串口通信作为嵌入式开发和硬件调试的重要工具,在工业控制、物联网等领域广泛应用。本文将手把手教你使用QT框架实现一个跨平台的串口调试助手,支持Windows/Linux/macOS系统。

使用版本为Qt 6以上版本

二、效果

三、界面

控件

四、项目引用

在 .pro 文件中添加模块依赖:

QT       += serialport

五、头文件声明

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QSerialPort>
#include <QSerialPortInfo>

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_btnRefreshSerialPort_clicked();
    void initUiData();

    void on_btnOpen_clicked();
    void initSerialPort(QSerialPort *serialPort,QString name,int baudRate,int dataBit,QString parity,int stopBit);
    void on_btnSend_clicked();
    void receiveData();
    void controlEnable(bool isEnable);
    void on_btnClear_clicked();

    void on_btnSendClear_clicked();

private:
    Ui::MainWindow *ui;

    QList<QString> BaudRateList;
    QList<int> DataBitList;
    QList<QString> ParityList;
    QList<int> StopBitList;

    QSerialPort serialPort;
};
#endif // MAINWINDOW_H

六、Cpp代码

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMessageBox>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    initUiData();
}

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

//刷新串口
void MainWindow::on_btnRefreshSerialPort_clicked()
{
    ui->cboSerialPort->clear();
    QList<QSerialPortInfo> serialPostList = QSerialPortInfo::availablePorts();
    foreach(const QSerialPortInfo &info,serialPostList)
    {
        ui->cboSerialPort->addItem(info.portName());//添加串口名称
    }
}

void MainWindow::initUiData()
{
    on_btnRefreshSerialPort_clicked();

    BaudRateList.append("1200");
    BaudRateList.append("2400");
    BaudRateList.append("4800");
    BaudRateList.append("9600");
    BaudRateList.append("19200");
    BaudRateList.append("38400");
    BaudRateList.append("57600");
    BaudRateList.append("115200");

    DataBitList.append(5);
    DataBitList.append(6);
    DataBitList.append(7);
    DataBitList.append(8);

    ParityList.append("无");
    ParityList.append("奇校验");
    ParityList.append("偶校验");

    StopBitList.append(1);
    StopBitList.append(2);

    foreach (auto item, BaudRateList) {
        ui->cboBaudRate->addItem(item);
    }
    ui->cboBaudRate->setCurrentText("9600");

    foreach (auto item, DataBitList) {
        ui->cboDataBits->addItem(QString::number(item));
    }
    ui->cboDataBits->setCurrentText("8");
    foreach (auto item, ParityList) {
        ui->cboParityBit->addItem(item);
    }
    ui->cboParityBit->setCurrentText("无");
    foreach (auto item, StopBitList) {
        ui->cboStopBit->addItem(QString::number(item));
    }
    ui->cboStopBit->setCurrentText("1");
}

//打开串口
void MainWindow::on_btnOpen_clicked()
{
    if(serialPort.isOpen())
    {
        //关闭串口
        serialPort.close();
        ui->lbStatus->setText("未打开");
        ui->btnOpen->setText("打开串口");
        controlEnable(true);
        disconnect(&serialPort,&QSerialPort::readyRead,this,&MainWindow::receiveData);
    }
    else
    {
        //打开串口
        auto name = ui->cboSerialPort->currentText();
        int baudRate =  ui->cboBaudRate->currentText().toInt();
        int dataBit = ui->cboDataBits->currentText().toInt();
        auto parity = ui->cboParityBit->currentText();
        int stopBit = ui->cboStopBit->currentText().toInt();

        initSerialPort(&serialPort,name,baudRate,dataBit,parity,stopBit);
        bool isOk = serialPort.open(QIODevice::ReadWrite);
        if(isOk)
        {
            //接收数据
            connect(&serialPort,&QSerialPort::readyRead,this,&MainWindow::receiveData);

            ui->lbStatus->setText("打开成功");
            ui->btnOpen->setText("关闭串口");
            controlEnable(false);
        }
        else
        {
            ui->lbStatus->setText("打开失败");
        }
    }
}

void MainWindow::initSerialPort(QSerialPort *serialPort,QString name,int baudRate,int dataBit,QString parity,int stopBit)
{
    serialPort->setPortName(name);
    serialPort->setBaudRate(baudRate);
    switch(dataBit)
    {
        case 5:
            serialPort->setDataBits(QSerialPort::Data5);
            break;
        case 6:
            serialPort->setDataBits(QSerialPort::Data6);
            break;
        case 7:
            serialPort->setDataBits(QSerialPort::Data7);
            break;
        case 8:
            serialPort->setDataBits(QSerialPort::Data8);
            break;
    }
    if(parity == "无")
    {
        serialPort->setParity(QSerialPort::NoParity);
    }
    else if(parity == "奇校验")
    {
        serialPort->setParity(QSerialPort::OddParity);
    }
    else if(parity == "偶校验")
    {
        serialPort->setParity(QSerialPort::EvenParity);
    }

    if(stopBit == 1)
    {
        serialPort->setStopBits(QSerialPort::OneStop);
    }
    else if(stopBit == 1)
    {
        serialPort->setStopBits(QSerialPort::TwoStop);
    }
    serialPort->setFlowControl(QSerialPort::NoFlowControl); // 设置流控
}


//发送 按钮
void MainWindow::on_btnSend_clicked()
{
    if(serialPort.isOpen() == true)
    {
        auto data = ui->txtInputData->toPlainText();
        if(data.length() > 0)
        {
            if(ui->chkAddEndMark->checkState() == Qt::Checked)
            {
                data += "\r\n";
            }

            //将字符串转为QByteArray
            if(ui->chkHexSend->checkState() == Qt::Checked)
            {
                //16进制发送
                QByteArray byteArray = QByteArray::fromHex(data.toUtf8());
                serialPort.write(byteArray);
            }
            else
            {
                serialPort.write(data.toUtf8());
            }
            ui->textBrowser->append("<font color='green'>发送:"+data.toUtf8());
        }
        else
        {
            QMessageBox::information(this,"系统提示","发送内容不能为空!");
        }
    }
    else
    {
        QMessageBox::information(this,"系统提示","串口未打开,请先打开串口!");
    }
}

void MainWindow::receiveData()
{
    QByteArray receiveData = serialPort.readAll();
    if(ui->chkHexReceive->checkState() == Qt::Checked)
    {
        QString hexData = receiveData.toHex(' '); // 将字节数组转换为16进制字符串,每个字节之间有空格分隔
        ui->textBrowser->append("<font color='blue'>接收:"+hexData);
    }
    else
    {
        ui->textBrowser->append("<font color='blue'>接收:"+QString(receiveData));
    }
}

void MainWindow::controlEnable(bool isEnable)
{
    ui->cboSerialPort->setEnabled(isEnable);
    ui->cboBaudRate->setEnabled(isEnable);
    ui->cboDataBits->setEnabled(isEnable);
    ui->cboParityBit->setEnabled(isEnable);
    ui->cboStopBit->setEnabled(isEnable);
}


void MainWindow::on_btnClear_clicked()
{
    ui->textBrowser->clear();
}


void MainWindow::on_btnSendClear_clicked()
{
    ui->txtInputData->clear();
}