串行终端

演示如何使用QSerialPort 的各种功能。

终端显示如何通过使用 Qt Serial Port.

该示例展示了QSerialPort 类的主要功能,如配置、I/O 实现等。此外,还调用了QSerialPortInfo 类来显示系统中可用串行端口的信息。

QSerialPort 串行接口类支持两种一般的编程方法:

  • 异步(非阻塞)方式。当控件返回 Qt 的事件循环时,会安排并执行操作。当操作完成时,QSerialPort 会发出一个信号。例如,QSerialPort::write() 会立即返回。当数据发送到串行端口时,QSerialPort 会发出bytesWritten() 信号。
  • 同步(阻塞)方法。在非图形用户界面和多线程应用程序中,可以调用waitFor...() 函数(即QSerialPort::waitForReadyRead() )来暂停调用线程,直到操作完成。

本例演示的是异步方法。阻塞接收器示例则说明了同步方法。

我们的示例包含一些图形用户界面部件:

  • MainWindow ( ) - 是主应用程序窗口,包含串行端口编程的所有工作逻辑,包括配置、I/O 处理等,同时继承了 QMainWindow。terminal/mainwindow.cpp
  • Console ( ) - 是主窗口的中心窗口部件,显示传输或接收的数据。该 widget 源自 QPlainTextEdit 类。terminal/console.cpp
  • SettingsDialog ( ) - 这是一个用于配置串行端口的对话框,也用于显示可用的串行端口及其相关信息。terminal/settingsdialog.cpp

串行端口在MainWindow 构造函数中实例化。主 Widget 作为父对象传递,因此对象的删除会根据 Qt 中的父子机制自动进行:

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    m_ui(new Ui::MainWindow),
    m_serial(new QSerialPort(this))
{
    ...

本示例演示了以下QSerialPort 信号:

  • readyRead() - 显示已收到新数据,因此可用
  • bytesWritten() - 用于检查是否已成功写入所有数据
    ...
    connect(m_serial, &QSerialPort::readyRead, this, &MainWindow::readData);
    connect(m_serial, &QSerialPort::bytesWritten, this, &MainWindow::handleBytesWritten);
    ...
}

点击连接按钮会调用openSerialPort() 插槽:

void MainWindow::openSerialPort()
{
    const SettingsDialog::Settings p = m_settings->settings();
    m_serial->setPortName(p.name);
    m_serial->setBaudRate(p.baudRate);
    m_serial->setDataBits(p.dataBits);
    m_serial->setParity(p.parity);
    m_serial->setStopBits(p.stopBits);
    m_serial->setFlowControl(p.flowControl);
    if (m_serial->open(QIODevice::ReadWrite)) {
        m_console->setEnabled(true);
        m_console->setLocalEchoEnabled(p.localEchoEnabled);
        m_ui->actionConnect->setEnabled(false);
        m_ui->actionDisconnect->setEnabled(true);
        m_ui->actionConfigure->setEnabled(false);
        showStatusMessage(tr("Connected to %1 : %2, %3, %4, %5, %6")
                          .arg(p.name, p.stringBaudRate, p.stringDataBits,
                               p.stringParity, p.stringStopBits, p.stringFlowControl));
    } else {
        QMessageBox::critical(this, tr("Error"), m_serial->errorString());

        showStatusMessage(tr("Open error"));
    }
}

在此槽中,将从SettingsDialog 读取设置,并尝试打开和初始化串行端口。如果成功,状态栏会显示一条信息,说明使用给定配置打开成功;否则,信息框会显示相应的错误代码和信息。如果从未调用过串行端口设置,终端会尝试使用默认设置打开端口:9600 8N1.

单击断开按钮会调用closeSerialPort() 插槽:

void MainWindow::closeSerialPort()
{
    if (m_serial->isOpen())
        m_serial->close();
    m_console->setEnabled(false);
    m_ui->actionConnect->setEnabled(true);
    m_ui->actionDisconnect->setEnabled(false);
    m_ui->actionConfigure->setEnabled(true);
    showStatusMessage(tr("Disconnected"));
}

在这种情况下,通过关闭串行端口来处理。

单击 "配置"按钮会调用属于SettingsDialog widget 的show() 插槽。

该方法 (terminal/settingsdialog.cpp) 显示SettingsDialog ,用户可在其中选择所需的串行端口,查看所选端口的相关信息,并设置给定串行端口的所需参数。

写入数据

在控制台中键入字符会调用writeData() 插槽:

void MainWindow::writeData(const QByteArray &data)
{
    const qint64 written = m_serial->write(data);
    if (written == data.size()) {
        m_bytesToWrite += written;
        m_timer->start(kWriteTimeout);
    } else {
        const QString error = tr("Failed to write all data to port %1.\n"
                                 "Error: %2").arg(m_serial->portName(),
                                                  m_serial->errorString());
        showWriteError(error);
    }
}

该槽将在给定的控制台 widget 中键入的字符发送到串行端口 - 参见terminal/console.cpp 。它还会启动一个计时器,跟踪写入是否成功。我们使用bytesWritten() 信号来确保所有字节都已写入。它连接到MainWindow::handleBytesWritten() 插槽:

void MainWindow::handleBytesWritten(qint64 bytes)
{
    m_bytesToWrite -= bytes;
    if (m_bytesToWrite == 0)
        m_timer->stop();
}
读取数据

当串行端口接收到新数据时,会发出readyRead() 信号,该信号与MainWindow::readData() 插槽相连:

void MainWindow::readData()
{
    const QByteArray data = m_serial->readAll();
    m_console->putData(data);
}

该槽从串行端口读取数据并显示在控制台部件中。

运行示例

要从 Qt Creator,打开Welcome 模式,并从Examples 中选择示例。更多信息,请参阅Qt Creator: 教程:构建并运行

示例项目 @ code.qt.io

另请参阅 Blocking Receiver

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.