串行终端

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

终端 展示如何通过 Qt 串行端口 创建一个简单的串行界面的终端。

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

QSerialPort 支持两种通用的编程方法

  • 异步(非阻塞)方法。 在控制权返回到 Qt 的事件循环时安排和执行操作。当操作完成时,QSerialPort 发出信号。例如,QSerialPort::write() 立即返回。当数据发送到串行端口时,QSerialPort 发出 bytesWritten()。
  • 同步(阻塞)方法。 在非 GUI 和多线程应用程序中,可以调用 (i.e. QSerialPort::waitForReadyRead()) 以挂起调用线程,直到操作完成。

在此示例中,演示了异步方法。Blocking Receiver 示例说明了同步方法。

我们的示例包含一些 GUI 小部件

  • MainWindow (terminal/mainwindow.cpp) - 是主应用程序窗口,包含串行端口编程的所有工作逻辑,包括配置、I/O 处理等等,同时继承自 QMainWindow。
  • Console (terminal/console.cpp) - 是主窗口的中心小部件,显示已发送或接收的数据。该小部件是从 QPlainTextEdit 类派生而来的。
  • SettingsDialog (terminal/settingsdialog.cpp) - 是用于配置串行端口的对话框,以及显示可用的串行端口及其信息。

串行端口在 MainWindow 构造函数中实例化。主小部件被作为父对象传递,所以对象删除将根据 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小部件的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);
    }
}

此槽将给定的控制台小部件中输入的字符发送到串行端口 - 请参阅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运行示例,请打开欢迎模式,并从示例中选择示例。更多信息,请访问构建和运行示例

示例项目 @ code.qt.io

另请参阅阻塞接收器

© 2024 The Qt Company Ltd. 本文档中的贡献版权属于各自的拥有者。提供的文档受GNU自由文档许可证版本1.3的条款约束,由自由软件基金会发布。Qt及其相应的标志是The Qt Company Ltd在芬兰和其他国家的商标。所有其他商标均为其各自所有者的财产。