【QT常用技术讲解】QSerialPort串口开发,包含文件发送功能

前言

串口通信是很古老的通信方式,适合数据传输量少的设备搭建为通信模块,本篇不延展串口历史,而是用一个应用工具关联介绍一些应用场景。

效果图

本篇的源码可以通用编译(window、Linux等),源码请查看资源。

开源的串口工具

串口应用功能不复杂,网络上可以下载到相关的工具,很方便做技术调研,下面简要介绍下window系统和Linux系统常用的串口工具。

window串口工具

1、串口助手

功能比较齐全,可以以十六进制/字符进行发送/接收,提供文件发送/接收功能等。

2、串口模拟工具vspd

如上图是在右边填写COM1和COM2,并点击【添加端口】之后,在左边就看到有两个虚拟串口了,这个工具是帮助我们在window的驱动层常见了COM1->COM2,COM2->COM1的虚拟串口,这两个串口是绑定使用的,在下面的【设备管理器】界面更容易理解:

因为大部分的笔记本都没有串口了,使用这个工具就能在自己的笔记本上完成串口应用调试。

基于这样虚拟串口工具的特性,我们还能开发一个远程串口工具,流程如下:

终端A部署了[客户端]--通过socket发送信息-->终端B部署[服务端]--接收客户端发送过来的信息,把命令信息写入到串口COM1-->COM2绑定瘦终端C(比如读卡器)

绑定瘦终端C(比如读卡器)通过COM2--返回结果-->COM1--终端B[服务端]接收信息后,通过socket返回信息-->终端A[客户端]

有远程桌面操作串口需求场景的,可以使用以上思路构建。

Linux串口工具

1、自带的cutecom

Linux串口工具cuteCOM源码(工具包含发送文件功能)这个是我分享过的工具源码

其他的需要apt下载,功能都比较简单,我这里就不列举了,如果是用测试ARM架构的Linux,可以试试Minicom。

功能讲解

1、串并口文件设置

这个菜单是用来添加自定义的串口,如果你的信创终端,要增加多个串口,这些串口不一定是COM前缀开头的文件,这个时候,市面上通用的串口工具都没法用,本篇的应用来源于实际的信创终端项目串口检测应用。

配置完成之后,在串口测试下拉框就可以选择了,这里就不展开讲解了,提供过思路给刚好有此类需求场景的人。

2、串口测试

1、获取系统串口信息

通过QSerialPortInfo 获取

复制代码
// 搜索所有可用串口
    foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) {
        QSerialPort serial;
        serial.setPort(info);
        ui->comboBox->addItem(serial.portName());
        if (serial.open(QIODevice::ReadWrite)){
            qDebug() << "==>" << serial.portName();
        }
    }

2、波特率设置

手动设置上去的

3、打开串口

核心代码就是:serialPort->open(QIODevice::ReadWrite)

复制代码
void MainWindow::on_pushButton_8_clicked()
{
    if(ui->pushButton_8->text() == tr("打开"))
    {
        // 串口设置
        serialPort->setPortName(ui->comboBox->currentText());
        serialPort->setBaudRate(ui->comboBox_2->currentText().toInt());
        serialPort->setDataBits(QSerialPort::Data8);
        serialPort->setStopBits(QSerialPort::OneStop);
        serialPort->setParity(QSerialPort::NoParity);

        // 打开串口
        if (serialPort->open(QIODevice::ReadWrite))
        {
            qDebug() << "串口打开成功";
            m_recvData.clear();
            connect(serialPort, &QSerialPort::readyRead, this, &MainWindow::readSerialData);
        }
        else
        {
            qDebug() << "串口打开失败";
            QMessageBox::warning(this, "错误", "无法打开串口: " + serialPort->portName());
            return;
        }
        ui->pushButton_8->setText("关闭");
        ui->comboBox->setEnabled(false);
        ui->comboBox_2->setEnabled(false);
    }
    else
    {
        serialPort->close();
        qDebug() << "串口关闭成功";
        ui->pushButton_8->setText("打开");
        ui->comboBox->setEnabled(true);
        ui->comboBox_2->setEnabled(true);
    }
}

4、串口发送功能

核心代码是:serialPort->write(data);

复制代码
// 发送数据函数
void MainWindow::sendData(const QByteArray &data)
{
    if (!serialPort->isOpen()) {
        QMessageBox::warning(this, "警告", "请先打开串口!");
        return;
    }

    qint64 bytesWritten = serialPort->write(data);
    if (bytesWritten == -1) {
        QMessageBox::warning(this, "错误", "发送数据失败");
    }
    else if (bytesWritten != data.size()) {
        QMessageBox::warning(this, "警告", "数据未完全发送");
    }
}

5、 十六进制模式方式发送

发送之前,对内容转换为十六进制

复制代码
        QByteArray data = hexStringToBytes(sendText);
        if (!data.isEmpty()) {
            qDebug() << "发送十六进制数据:" << bytesToHexString(data);
            sendData(data);
        }

// 十六进制字符串转字节数组
QByteArray MainWindow::hexStringToBytes(const QString &hexStr)
{
    QByteArray byteArray;
    QString trimmed = hexStr.trimmed();
    QStringList hexValues = trimmed.split(' ');

    for (const QString &hexValue : hexValues) {
        if (hexValue.isEmpty()) continue;

        bool ok;
        char byte = static_cast<char>(hexValue.toInt(&ok, 16));
        if (ok) {
            byteArray.append(byte);
        }
        else {
            QMessageBox::warning(this, "错误", "无效的十六进制值: " + hexValue);
            return QByteArray();
        }
    }

    return byteArray;
}

6、字符方式发送

发送之前,对内容转换为utf-8格式

复制代码
        // 字符模式
        QByteArray data = sendText.toUtf8();
        qDebug() << "发送字符数据:" << sendText;
        sendData(data);

7、文件发送

以块方式循环读取文件内容,然后发送到对端

复制代码
void MainWindow::on_pushButton_sendFile_clicked()
{
    if (!serialPort->isOpen()) {
        QMessageBox::warning(this, "警告", "请先打开串口!");
        return;
    }

    // 直接弹出文件选择对话框
    QString fileName = QFileDialog::getOpenFileName(this, "选择要发送的文件", "", "所有文件 (*)");
    if (fileName.isEmpty()) {
        return;
    }

    QFile file(fileName);
    if (!file.open(QIODevice::ReadOnly)) {
        QMessageBox::warning(this, "错误", "无法打开文件: " + fileName);
        return;
    }

    QFileInfo fileInfo(fileName);
    qDebug() << "准备发送文件:" << fileName << "大小:" << fileInfo.size() << "字节";

    // 创建进度对话框
    QProgressDialog progress("发送文件中...", "取消", 0, file.size(), this);
    progress.setWindowTitle("发送文件");
    progress.setWindowModality(Qt::WindowModal);
    progress.show();

    // 分块读取和发送文件
    const int chunkSize = 1024;
    qint64 totalSent = 0;
    QByteArray data;

    while (!file.atEnd()) {
        if (progress.wasCanceled()) {
            break;
        }

        data = file.read(chunkSize);

        qint64 bytesWritten = serialPort->write(data);
        if (bytesWritten == -1) {
            QMessageBox::warning(this, "错误", "发送文件失败");
            break;
        }

        if (!serialPort->waitForBytesWritten(5000)) {
            QMessageBox::warning(this, "错误", "写入超时");
            break;
        }

        totalSent += bytesWritten;
        progress.setValue(totalSent);
        QApplication::processEvents();

        // 添加小延迟,避免过快发送导致接收方处理不过来
        QThread::msleep(10);
    }

    file.close();

    if (totalSent == fileInfo.size()) {
        QMessageBox::information(this, "完成", "文件发送完成!\n发送字节数: " + QString::number(totalSent));
    } else {
        QMessageBox::information(this, "中断", "文件发送已中断\n已发送字节数: " + QString::number(totalSent));
    }
}

使用本应用的文件发送功能,发送给串口助手,经过测试,支持文本文件、图片文件传输。可能你会绝得串口工具没必要传输这么多字符的内容,常用场景确实是这样。但是,在不方便使用USB、网络挂载的情况下,串口通常是可以作为临时传输通道的,这个不好明说。

相关推荐
Larry_Yanan3 小时前
Qt网络开发之基于 QWebEngine 实现简易内嵌浏览器
linux·开发语言·网络·c++·笔记·qt·学习
一然明月5 小时前
Qt QML 锚定(Anchors)全解析
java·数据库·qt
一只爱学习的小鱼儿5 小时前
使用QT编写粒子显示热力图效果
开发语言·qt
大树学长5 小时前
【QT开发】Redis通信相关(一)
redis·qt
笨笨马甲5 小时前
Qt 人脸识别
开发语言·qt
山上三树6 小时前
Qt QObject介绍
开发语言·qt
山上三树6 小时前
QObject、QWidget、Widget三者的关系
qt
坚定学代码7 小时前
qt c++ 局域网聊天小工具
c++·qt·个人开发
笨笨马甲8 小时前
Qt network开发
开发语言·qt
mengzhi啊1 天前
Qt Designer UI 界面 拖的两个 QLineEdit,想按 Tab 从第一个跳到第二个
qt