QT5串口编程----线程循环发送不成功问题

2023-11-19

今天想写一个QT5的串口编程,能够循环发送数据,想具体到us级别,不需要设置ms发送。所以想用一个线程一直发送。

关键问题是碰到在线程循环发送竟然发不出去,见鬼了。。。最后找到问题是要在每次发送后要判断waitForBytesWritten是否发送成功,否则串口再也发不出去了,这很关键。

if(!serial.waitForBytesWritten())   //这一句很关键,决定是否能发送成功
{
    qDebug()<<"serial write failed";
}

程序界面:

测试效果:我这里测试用了虚拟串口(vspd)虚拟了两个串口来测试:效果如图:

 

话不多说,直接贴代码。

首先是mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

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

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
public:
    void setAllState(bool state);
    void fillPortsParameters();
    QSerialPort serial;

protected:
    void run();
    void startThread();
    void stopThread();

private slots:
    void Serial_Read();

    void on_SerialClearRecButton_clicked();

    void on_SerialSendDataButton_clicked();

    void on_SeribalCheckButton_clicked();

    void on_SerialOpenButton_clicked();

    void on_SendTextEdit_textChanged();

    void on_LoopPushButton_clicked();


private:
    Ui::MainWindow *ui;
    std::atomic<bool> m_bRunThread = false;
};
#endif // MAINWINDOW_H

然后是mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMessageBox>
#include <QDebug>
#include <thread>
#include <QThread>

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


    //发送按键失能
    ui->SerialSendDataButton->setEnabled(false);
    ui->LoopPushButton->setEnabled(false);


    //connect
    connect(&serial, &QSerialPort::readyRead, this, &MainWindow::Serial_Read);

    //设置所有下拉框失能;
    setAllState(false);
    //加入设置参数
    fillPortsParameters();
}

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



// 串口读取数据函数
void MainWindow:: Serial_Read()
{
//    QByteArray buf;
//    buf = serial.readAll();
//    if(!buf.isEmpty())//如果读到的数据不为空
//    {
//       ui->ReceiveTextEdit->insertPlainText(buf);
//     }
//     buf.clear();
    QByteArray recv;
    recv = serial.readAll();
    QString recv_string = recv;
    qDebug() << recv_string<<endl;
    ui->ReceiveTextEdit->append(recv_string);
}


void MainWindow::on_SerialClearRecButton_clicked()
{
    ui->ReceiveTextEdit->clear();

}

void MainWindow::on_SerialSendDataButton_clicked()
{
    if(serial.isOpen())
    {
        //获取界面上的数据并转换成utf8格式的字节流
        QByteArray data = ui->SendTextEdit->toPlainText().toUtf8();
        qDebug()<<serial.write(data);
        if(!serial.waitForBytesWritten())
        {
             qDebug()<<"serial write error";
        }
    }
    else
         qDebug()<<"serial is not open";

}



void MainWindow::startThread()
{
    if(!m_bRunThread)
    {
        m_bRunThread = true;
        std::thread thrd(std::bind(&MainWindow::run,this));
        thrd.detach();
    }
}

void MainWindow::stopThread()
{
    m_bRunThread = false;
}


void MainWindow::run()
{
    qDebug()<<"loopsend thread start";
    while(m_bRunThread)
    {
        qDebug()<<"write data";
        //获取界面上的数据并转换成utf8格式的字节流
        QByteArray data = ui->SendTextEdit->toPlainText().toUtf8();
        serial.write(data);
        if(!serial.waitForBytesWritten())   //这一句很关键,决定是否能发送成功
        {
             qDebug()<<"serial write error";
        }
//        QThread::msleep(100);
    };
    qDebug()<<"loopsend thread quit";
}


void MainWindow::on_LoopPushButton_clicked()
{
    if(ui->LoopPushButton->text() == "LoopSend")
    {
        ui->LoopPushButton->setText(tr("STOP"));
        startThread();
    }
    else
    {
         ui->LoopPushButton->setText(tr("LoopSend"));
         stopThread();
    }
}


void MainWindow::on_SeribalCheckButton_clicked()
{
    ui->SerialNumberComb->clear();
    //通过QSerialPortInfo查找可用串口
    foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
    {
        ui->SerialNumberComb->addItem(info.portName());
    }
    if(ui->SerialNumberComb->currentIndex() != -1)
    {
        ui->SerialBaudrateComb->setEnabled(true);
        ui->SerialDataBitComb->setEnabled(true);
        ui->SerialParityBitComb->setEnabled(true);
        ui->SerialStopBitComb->setEnabled(true);
        ui->SerialFlowControlComb->setEnabled(true);
    }

}

void MainWindow::on_SerialOpenButton_clicked()
{
    if(ui->SerialOpenButton->text()==QString("打开串口"))
    {
        if(!serial.isOpen())
        {
            //设置串口名
            serial.setPortName(ui->SerialNumberComb->currentText());
            //设置波特率
            serial.setBaudRate(static_cast<QSerialPort::Parity>(ui->SerialBaudrateComb->itemData(ui->SerialBaudrateComb->currentIndex()).toInt()));
            //设置数据位数
            serial.setDataBits(static_cast<QSerialPort::DataBits>(ui->SerialDataBitComb->itemData(ui->SerialDataBitComb->currentIndex()).toInt()));
            //设置奇偶校验
            serial.setParity(static_cast<QSerialPort::Parity>(ui->SerialParityBitComb->itemData(ui->SerialParityBitComb->currentIndex()).toInt()));
            //设置停止位
            serial.setStopBits(static_cast<QSerialPort::StopBits>(ui->SerialStopBitComb->itemData(ui->SerialStopBitComb->currentIndex()).toInt()));
            //设置流控制
            serial.setFlowControl(static_cast<QSerialPort::FlowControl>(ui->SerialFlowControlComb->itemData(ui->SerialFlowControlComb->currentIndex()).toInt()));
            //打开串口
            if(!serial.open(QIODevice::ReadWrite))
            {
                QMessageBox::about(NULL,"提示","无法打开串口!");
                return;
            }
            setAllState(false);
            ui->SerialNumberComb->setEnabled(false);
            ui->SerialOpenButton->setText(QString("关闭串口"));
        }
    }
    else
    {
        if(serial.isOpen())
        {
            //关闭串口
            serial.close();
            //设置串口参数可设置
            setAllState(true);
            stopThread();
            ui->SerialNumberComb->setEnabled(true);
            ui->SerialOpenButton->setText(QString("打开串口"));
        }
    }

}


void MainWindow::setAllState(bool state)
{
    if(state)
    {
        ui->SerialBaudrateComb->setEnabled(true);
        ui->SerialDataBitComb->setEnabled(true);
        ui->SerialParityBitComb->setEnabled(true);
        ui->SerialStopBitComb->setEnabled(true);
        ui->SerialFlowControlComb->setEnabled(true);
    }
    else
    {
        ui->SerialBaudrateComb->setEnabled(false);
        ui->SerialDataBitComb->setEnabled(false);
        ui->SerialParityBitComb->setEnabled(false);
        ui->SerialStopBitComb->setEnabled(false);
        ui->SerialFlowControlComb->setEnabled(false);
    }

}

void MainWindow::fillPortsParameters()
{
    ui->SerialBaudrateComb->addItem(QStringLiteral("9600"), QSerialPort::Baud9600);
    ui->SerialBaudrateComb->addItem(QStringLiteral("19200"), QSerialPort::Baud19200);
    ui->SerialBaudrateComb->addItem(QStringLiteral("38400"), QSerialPort::Baud38400);
    ui->SerialBaudrateComb->addItem(QStringLiteral("38400"), QSerialPort::Baud57600);
    ui->SerialBaudrateComb->addItem(QStringLiteral("115200"), QSerialPort::Baud115200);

    ui->SerialDataBitComb->addItem(QStringLiteral("5"), QSerialPort::Data5);
    ui->SerialDataBitComb->addItem(QStringLiteral("6"), QSerialPort::Data6);
    ui->SerialDataBitComb->addItem(QStringLiteral("7"), QSerialPort::Data7);
    ui->SerialDataBitComb->addItem(QStringLiteral("8"), QSerialPort::Data8);
    ui->SerialDataBitComb->setCurrentIndex(3);

    ui->SerialParityBitComb->addItem(tr("None"), QSerialPort::NoParity);
    ui->SerialParityBitComb->addItem(tr("Even"), QSerialPort::EvenParity);
    ui->SerialParityBitComb->addItem(tr("Odd"), QSerialPort::OddParity);
    ui->SerialParityBitComb->addItem(tr("Mark"), QSerialPort::MarkParity);
    ui->SerialParityBitComb->addItem(tr("Space"), QSerialPort::SpaceParity);

    ui->SerialStopBitComb->addItem(QStringLiteral("1"), QSerialPort::OneStop);
#ifdef Q_OS_WIN
    ui->SerialStopBitComb->addItem(tr("1.5"), QSerialPort::OneAndHalfStop);
#endif
    ui->SerialStopBitComb->addItem(QStringLiteral("2"), QSerialPort::TwoStop);

    ui->SerialFlowControlComb->addItem(tr("None"), QSerialPort::NoFlowControl);
    ui->SerialFlowControlComb->addItem(tr("RTS/CTS"), QSerialPort::HardwareControl);
    ui->SerialFlowControlComb->addItem(tr("XON/XOFF"), QSerialPort::SoftwareControl);

}

void MainWindow::on_SendTextEdit_textChanged()
{
    if(ui->SendTextEdit->toPlainText().toUtf8() == "")
    {
         ui->SerialSendDataButton->setEnabled(false);
         ui->LoopPushButton->setEnabled(false);
    }
    else
    {
        ui->SerialSendDataButton->setEnabled(true);
        ui->LoopPushButton->setEnabled(true);
    }
}



再然后是 main.cpp

#include "mainwindow.h"

#include <QApplication>

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

 

程序源码放在这个地址,大家可以去下载。

https://download.csdn.net/download/u010505080/12361152

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

QT5串口编程----线程循环发送不成功问题 的相关文章

  • 关于 GUI 计时器显示后台线程已用时间的建议?

    Issue 我有一个 PyQt GUI 用户按下按钮即可启动后台线程 workerThread 它是从QThread 我想要一个计时器显示 以QLabel 显示自此以来已经过去了多少时间workerThread开始 我希望这个计时器在wor
  • Qt 远程文件浏览器

    我想知道是否有人使用过 Qt 远程文件浏览器 根据我的理解 我有两个选择 当涉及到远程文件时 将 QFileDilaog 与自定义代理模型结合使用 该模型将负责提供远程文件 目录结构 使用自定义对话框 并为本地文件提供标准文件系统模型 为远
  • 删除 QComboBox“下拉”动画

    我正在使用 Qt 4 8 并且想在单击 QComboBox 时摆脱 下拉 动画 我也想稍微移动一下 到目前为止 我一直在考虑重新实现 showPopup 和 hidePopup 但不知道如何使其工作 此外 每次我尝试使用 CSS 进行移动或
  • 在哪里可以找到 Qt 的 dll 的 pdb 文件?

    我正在调试 Qt 应用程序 在哪里可以找到 Qt 的调试 dll 我在windows上使用的是vs2010 它说它需要 Qt 中的许多 dll 的 pdb 文件 从 Qt 5 9 开始 与 Windows 发行版相对应的 PDB 可作为单独
  • 获取小部件的背景颜色 - 真的

    我无法获取小部件的实际背景颜色 在我的特殊情况下 我在使用 QTabWidget 中的小部件时遇到问题 这是在Windows7上 因此 经典的小部件有一些灰色背景 而选项卡内的小部件通常用白色背景绘制 I tried def bgcolor
  • Windows 消息循环而不是 QApplication::exec() / QApplication::processEvents()

    我是否想念任何一个Qt如果我替换功能QApplication exec 使用标准 Windows 消息循环实现 这应该可以澄清我的意思 运行事件处理的常用 Qt 方式 int main int argc char argv QApplica
  • 安装多个版本的 Qt 库

    我在windows中安装了QtSDK 它的Qt库版本是4 7 0 现在我想为 mingw 和 VS2008 安装 Qt 库版本 4 8 2 我怎样才能做到这一点 如何向QtCreator引入多个版本 注意 我已经从以下位置下载了库http
  • QTableView 中的虚拟列?

    我开始学习 Qt4 模型 视图编程 我有初学者问题 我有一个简单的应用程序 其中显示 sqlite 表QTableView class Model QtSql QSqlTableModel def init self parent None
  • 从 QML 实例化 C++ 对象会产生巨大的内存使用开销

    实例化一个QObjectC 堆中的派生类为每个对象提供了大约 160 个字节 通过注册相同的对象qmlRegisterType 用于从 QML 创建并通过以下方式动态创建对象createObject 每个对象给我 2000 多个字节 这是完
  • 如何在 Qt-Embedded 中(正确)输出多语言文本?

    我的目标系统是 linux 3 3 7 Qt Embedded 开源版 4 8 Droid 字体 取自 fonts droid 20111207 git 1 all deb Debian 软件包并复制到 usr lib fonts目录 主要
  • Qt/c++ 随机字符串生成[重复]

    这个问题在这里已经有答案了 我正在创建一个应用程序 需要生成多个随机字符串 几乎就像一个由一定长度的 ASCII 字符组成的唯一 ID 这些字符混合有大写 小写 数字字符 有没有 Qt 库可以实现这一点 如果没有 在纯 C 中生成多个随机字
  • 如何创建QWidget的屏幕截图?

    我在 Qt Creator 中做作业 在其中绘制 QWidget 并且需要保存此 QWdiget 的某些部分 我试图解决这个问题 QPixmap pixmap pixmap copy rectangle rectangle is part
  • GoQt 致命错误:QAbstractAnimation:没有这样的文件或目录

    我尝试编译 Qt 来开发桌面应用程序 我按照 Qt 网站上的官方 wiki 指南的说明进行操作 当我尝试go run示例文件夹中的示例 我收到错误 去运行 home pinkya rabbit workspace go1programs s
  • 加权 Voronoi 的 CGAL 2D APOLLONIUS 图 - 如何生成和获取面和顶点?

    我正在尝试根据阿波罗尼乌斯图生成加权沃罗诺伊 我正在使用 CGAL 库 我找不到如何从 apollonius 获取面和顶点的好例子 我有以下类型定义 typedef double NT typedef CGAL Cartesian lt N
  • 如何在 Qt 中以编程方式制作一条水平线

    我想弄清楚如何在 Qt 中制作一条水平线 这很容易在设计器中创建 但我想以编程方式创建一个 我已经做了一些谷歌搜索并查看了 ui 文件中的 xml 但无法弄清楚任何内容 ui 文件中的 xml 如下所示
  • 如何将图像显示为缩略图

    我有一个QTreeView显示硬盘驱动器和目录 我也有一个QListView显示图像文件如下 但我想将图像显示为缩略图 如下所示 My code mainWidget mainWidget QWidget parent QWidget pa
  • QToolButton:更改菜单位置

    使用菜单时QToolButton菜单显示在按钮的正下方 有没有办法在按钮的左侧 右侧显示菜单 我知道这个问题不久前已得到回答 但我想为此问题添加新答案 因为接受的答案不再有效 实际上 更改 QToolButton 上的菜单位置非常容易 您需
  • QCombobox 向下箭头图像

    如何更改Qcombobox向下箭头图像 现在我正在使用这个 QSS 代码 但这不起作用 我无法删除向下箭头边框 QComboBox border 0px QComboBox down arrow border 0px background
  • 如何在 QTabWidget Qt 中展开选项卡

    我有一个QTabWidget像这个 但我想展开选项卡以 填充 整个小部件宽度 如下所示 我怎样才能做到这一点 我在用Qt 5 3 2 and Qt 创建者 3 2 1 Update 我尝试使用setExpanding功能 ui gt myT
  • 使用 QtWebEngine 将 C++ 对象暴露给 Qt 中的 Javascript

    使用 QtWebkit 可以通过以下方式将 C 对象公开给 JavascriptQWebFrame addToJavaScriptWindowObject如中所述https stackoverflow com a 20685002 5959

随机推荐

  • 使用SQL进行递归查询

    使用SQL进行递归查询 在工作当中会经常用到递归 比如菜单的展示 一种方法就是从 数据库中取出所有的数据 然后在程序中循环获取符合条件的数据 另外一种方法就是使用SQL直接读取符合条件的数据 对于递归查询 T SQL和PL SQL进行了不同
  • Ubuntu 18.04 + DSO-slam配置、运行数据集、摄像头实时运行

    一 写在前面 前段时间老师布置了课程任务 让全班同学分组配置和运行slam 我们组选择的是DSO slam 由于选择的时候并没有对slam并没有什么了解 只有老师上课时一些科普性质的讲解 所以相当于是从0开始 这一周一直用空闲时间配置环境
  • 【GPLT】【2022天梯赛真题题解】

    L1 1 今天我要赢 5分 题目描述 2018 年我们曾经出过一题 是输出 2018 我们要赢 今年是 2022 年 你要输出的句子变成了 我要赢 就在今天 然后以比赛当天的日期落款 输入格式 本题没有输入 输出格式 输出分 2 行 在第一
  • RocketMQ消费者可以手动消费但无法主动消费问题,或生成者发送超时

    1 大多数是配置问题 修改rocketmq文件夹broker conf 2 配置与集群IP或本地IPV4一样 重启 在RocketMQ独享实例中支持IPv4和IPv6双栈 主要是通过在网络层面上同时支持IPv4和IPv6协议栈来实现的 Ro
  • java之二进制与数据类型(二)

    一 各数据类型的最大值和最小值 整数 以byte为例 我们知道 byte共有8个bit位 最大值是0111111 最小值是10000000 用十进制来表示就是 128 127 即 2 7 2 7 依照上面的推理方式可知 总结下表 数据类型
  • Redis学习总结

    Redis Redis 是完全开源免费的 遵守BSD协议 是一个高性能的key value数据库 Redis支持数据的持久化 可以将内存中的数据保存在磁盘中 重启的时候可以再次加载进行使用 Redis的优势 性能极高 Redis读的速度可达
  • 格雷码介绍与应用

    注 学习 交流就在博主的个人weixin公众号 FPGA动力联盟 留言或直接 博主weixin fpga start 私信 学过晶体管知识的朋友们都知道 数据位跳变就相当于硬件电路中的晶体管翻转 许多位同时跳变就相当于多个晶体管同时翻转 会
  • SHELL 文件内容的行数打印、统计,空行处理,每行字段的逆序输出

    file txt 用来实验的文本文件 how they are implemented and applied in computer that is your bag is this your bag to the degree or e
  • 服务器系统怎么重新启动,服务器win7系统不能重新启动

    1 电脑关不机 有很多因素 有可能是中毒了 有可能是系统问题 有可能是硬件问题 也有可能是设置问题 所以我们要一个个的排除 2 第一 中毒可能性 如果电脑可能中毒导致关不了机 就需要下载杀毒软件 然后进行木马杳然 点击全盘杀毒 一个也不能放
  • iOS开发助手、ipa便捷上传工具!

    ipa上传助手Appuploader是一个iOS APP上架辅助助手 帮助开发者可以快速的申请iOS证书打包ipa文件上传到App Store审核 非常方便的iOS上架助手 提升上架效率 ipa上传助手Appuploader官网http w
  • 【C++】类:构造函数、默认构造函数模板

    目录 模板一 两个类名构造函数 一个传参 一个不传参 模板二 成员初始化列表 推荐 性能高 构造函数 默认构造函数的作用 构造函数 传一些参数进来 用于给类的成员变量赋值 默认构造函数 程序员给类的成员变量设定一个默认值 也是用于给类的成员
  • 逻辑回归(二):Loss易导

    目录 回顾 梯度下降 对Loss函数求偏导 更新公式 多分类问题 总结 回顾 书接上回 讲到了逻辑回归的Loss函数的一般形式 大体如下 L 1
  • AWVS使用教程

    AWVS可以用来 Site Crawler 爬取URL Target Finder IP端口扫描 Subdomain Scanner 用DNS进行域名解析 找域名下的子域及其主机名 Blind SQL Injector 在相应参数位置按 添
  • sql的几种约束,非空,不重

    NOT NULL 用于控制字段的内容一定不能为空 NULL UNIQUE 控件字段内容不能重复 一个表允许有多个 Unique 约束 PRIMARY KEY 也是用于控件字段内容不能重复 但它在一个表只允许出现一个 FOREIGN KEY
  • 位移运算使用技巧

    位移运算使用技巧 左位移 lt lt 右位移 gt gt 左位移 lt lt 将二进制数向左位移操作 高位溢出则丢弃 地位补0 int a 11 int b a lt lt 1 b 22 位移前 0000 1011 位移后 0001 011
  • 达芬奇传

    列奥纳多 迪 皮耶罗 达 芬奇 出生于1452年 1519年逝世 享年67岁 画家 发明家 科学家 生物学家 工程师 达 芬奇的意思是 来自芬奇镇 他的名字叫做列奥纳多 达 芬奇的父亲叫瑟 皮耶罗 达 芬奇 是佛罗伦萨的法律公证员 因此十分
  • git:批处理启动Git-Bash窗口并显示特定目录

    参考 使用批处理脚本 在特定目录中启动Git Bash窗口
  • 【数据结构】复杂度

    博客主页 小王又困了 系列专栏 数据结构 人之为学 不日近则日退 感谢大家点赞 收藏 评论 目录 一 什么是数据结构 二 什么是算法 三 算法的效率 四 时间复杂度 4 1大O渐进表示法 4 2常见时间复杂度计算举例 4 3例题 消失的数字
  • StarkNet 批量交互 mint 铸造 js 脚本

    代码使用 starknet 模块与 StarkNet 网络进行交互 通过读取私钥文件和执行铸造操作来创建 NFT 非同质化代币 它通过批量运行的方式处理多个私钥和地址对 并将结果输出到控制台和日志文件中 代码的详细步骤 导入模块和变量 co
  • QT5串口编程----线程循环发送不成功问题

    今天想写一个QT5的串口编程 能够循环发送数据 想具体到us级别 不需要设置ms发送 所以想用一个线程一直发送 关键问题是碰到在线程循环发送竟然发不出去 见鬼了 最后找到问题是要在每次发送后要判断waitForBytesWritten是否发