You need to enable JavaScript to run this app. QT串口开发:serial->write放入while循环后主窗口无法弹出
优惠活动
大模型
产品
解决方案
定价
更多

QT串口开发:serial->write放入while循环后主窗口无法弹出

问题根因定位
  • 核心阻塞原因:无限循环while(1)放置于Widget类的构造函数执行流程中。Qt的界面渲染、事件响应完全依赖主线程的事件循环驱动,构造函数执行阶段处于主线程流程中,一旦进入无退出条件的循环,程序会直接卡死在构造逻辑环节,后续w.show()窗口渲染、事件循环启动的流程完全无法执行,最终表现为主窗口不弹出。
  • 配置类错误:
    • 端口参数不匹配:测试阶段用Hercules打开的是COM6,代码中硬编码端口名为COM1,即使循环不阻塞,也无法匹配实际串口设备。
    • 发送逻辑缺陷:无间隔连续调用serial->write()会瞬间打满串口内核缓冲区,引发数据丢包、CPU占用率异常升高。
可直接落地的修复方案

完全遵循Qt事件驱动的开发规范,使用内置的QTimer实现周期性串口发送,完全避免阻塞UI线程,同时修正所有配置错误:

第一步:修改widget.h头文件

在原有代码基础上增加定时器、发送槽函数的声明:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QtSerialPort/QSerialPort>
#include <QTimer>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void on_pushButton_clicked();
    // 定时器触发的串口发送槽函数
    void sendSerialData();

private:
    Ui::Widget *ui;
    QSerialPort *serial;
    QTimer *sendTimer;
};

#endif // WIDGET_H

第二步:修改widget.cpp实现逻辑

彻底移除构造函数中的死循环,调整端口配置,接入定时器触发发送逻辑:

#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QtSerialPort/QSerialPort>
#include <QSerialPortInfo>

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

    serial = new QSerialPort(this);
    // 修正端口为测试使用的COM6
    serial->setPortName("COM6");

    // 打印所有可用串口,方便排查端口匹配问题
    for(const auto &serialPortInfo : QSerialPortInfo::availablePorts())
    {
        qDebug() << "find serial port: " << serialPortInfo.portName();
    }

    // 打开串口
    if(serial->open(QIODevice::ReadWrite))
    {
        // 串口打开成功后配置通信参数
        serial->setBaudRate(QSerialPort::Baud9600);
        serial->setDataBits(QSerialPort::Data8);
        serial->setParity(QSerialPort::NoParity);
        serial->setStopBits(QSerialPort::OneStop);
        serial->setFlowControl(QSerialPort::NoFlowControl);

        // 初始化定时器:每100ms触发一次发送,间隔可根据需求调整
        sendTimer = new QTimer(this);
        connect(sendTimer, &QTimer::timeout, this, &Widget::sendSerialData);
        sendTimer->start(100);
    }
    else
    {
        qDebug() << "can't open the port, error:" << serial->errorString();
    }
}

// 串口发送逻辑实现
void Widget::sendSerialData()
{
    // 写入前判断串口状态,避免无效操作报错
    if(serial->isOpen())
    {
        serial->write("ok");
    }
}

Widget::~Widget()
{
    // 退出时先停止定时器、关闭串口,再释放UI资源
    sendTimer->stop();
    if(serial->isOpen())
    {
        serial->close();
    }
    delete ui;
}

void Widget::on_pushButton_clicked()
{
    qDebug() << "salam";
}

第三步:main.cpp无需调整

原有启动逻辑完全符合Qt应用规范,不需要修改。

补充说明
  • 单独运行单句serial->write("ok")能正常通信的原因:没有死循环阻塞,构造函数可以正常执行完成,后续窗口渲染、事件循环流程都能顺利跑通。
  • 定时器触发间隔可根据实际通信带宽调整,过短的间隔容易造成串口缓冲区溢出,一般建议设置在100ms~1000ms区间。
  • 如果需要更复杂的循环发送逻辑,不要直接在UI线程写死循环,可以把串口发送逻辑放到独立的QThread子线程执行,通过信号槽和UI线程通信,避免界面失去响应。

内容的提问来源于stack exchange,提问作者Nanor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.07 18:54:02