Qt 串口模块(QtSerialPort)是 Qt 框架中用于与串口设备通信的组件,提供了跨平台的串口访问能力。
QtSerialPort 模块包含两个核心类:
-
QSerialPort
- 提供对串口的配置和数据传输功能(打开 / 关闭串口、读写数据)。
- 支持异步和同步通信模式。
-
QSerialPortInfo
- 用于枚举系统中可用的串口设备(如 COM1、/dev/ttyUSB0)。
- 获取串口详细信息(描述、制造商、序列号等)。
一、环境配置
-
安装 Qt
下载并安装 Qt SDK(包含 Qt Creator IDE),推荐 Qt 5.15 或更高版本。
-
启用串口模块
在项目的
.pro
文件中添加:QT += serialport
-
包含必要头文件
#include <QSerialPort> // 串口类 #include <QSerialPortInfo> // 串口信息类
二、界面设计(UI 文件)
使用 Qt Designer 设计界面,通常包含:
-
串口设置区:
- 串口下拉框(选择 COM 口)
- 波特率下拉框(如 9600、115200)
- 数据位、停止位、校验位下拉框
- 打开 / 关闭串口按钮
-
数据收发区:
- 接收文本框(显示接收到的数据)
- 发送文本框(输入要发送的数据)
- 发送按钮

三、核心代码实现
1. 初始化串口管理类
// mainwindow.h
#include <QMainWindow>
#include <QSerialPort>
#include <QSerialPortInfo>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_pushButton_open_clicked(); // 打开/关闭串口按钮槽函数
void on_pushButton_send_clicked(); // 发送数据按钮槽函数
void readData(); // 读取串口数据的槽函数
private:
Ui::MainWindow *ui;
QSerialPort *serialPort; // 串口对象指针
};
2. 构造函数初始化
// mainwindow.cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
serialPort = new QSerialPort(this);
// 扫描并添加可用串口到下拉框
foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) {
ui->comboBox_port->addItem(info.portName());
}
// 添加常用波特率选项
ui->comboBox_baud->addItems({"9600", "115200", "19200", "38400"});
// 设置默认选项
ui->comboBox_baud->setCurrentText("115200");
ui->comboBox_dataBits->setCurrentText("8");
ui->comboBox_stopBits->setCurrentText("1");
ui->comboBox_parity->setCurrentText("None");
// 连接信号和槽
connect(serialPort, &QSerialPort::readyRead, this, &MainWindow::readData);
}
3. 打开 / 关闭串口功能
void MainWindow::on_pushButton_open_clicked()
{
if (serialPort->isOpen()) {
// 关闭串口
serialPort->close();
ui->pushButton_open->setText("打开串口");
ui->statusBar->showMessage("串口已关闭");
} else {
// 设置串口参数
serialPort->setPortName(ui->comboBox_port->currentText());
serialPort->setBaudRate(ui->comboBox_baud->currentText().toInt());
// 设置数据位
switch (ui->comboBox_dataBits->currentText().toInt()) {
case 5: serialPort->setDataBits(QSerialPort::Data5); break;
case 6: serialPort->setDataBits(QSerialPort::Data6); break;
case 7: serialPort->setDataBits(QSerialPort::Data7); break;
case 8: serialPort->setDataBits(QSerialPort::Data8); break;
default: serialPort->setDataBits(QSerialPort::Data8); break;
}
// 设置停止位和校验位(类似逻辑)
// ...
// 尝试打开串口
if (serialPort->open(QIODevice::ReadWrite)) {
ui->pushButton_open->setText("关闭串口");
ui->statusBar->showMessage("串口已打开");
} else {
ui->statusBar->showMessage("串口打开失败: " + serialPort->errorString());
}
}
}
4. 数据接收功能
void MainWindow::readData()
{
QByteArray data = serialPort->readAll();
// 显示接收到的数据
ui->textEdit_receive->append(data);
}
5. 数据发送功能
void MainWindow::on_pushButton_send_clicked()
{
if (serialPort->isOpen()) {
QString sendData = ui->textEdit_send->toPlainText();
serialPort->write(sendData.toUtf8());
ui->statusBar->showMessage("数据已发送");
} else {
ui->statusBar->showMessage("请先打开串口");
}
}
四、完整实现示例
以下是一个完整的串口收发平台代码:
// mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QSerialPort>
#include <QSerialPortInfo>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_pushButton_open_clicked();
void on_pushButton_send_clicked();
void readData();
private:
Ui::MainWindow *ui;
QSerialPort *serialPort;
};
#endif // MAINWINDOW_H
// mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
serialPort = new QSerialPort(this);
// 扫描可用串口
foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) {
ui->comboBox_port->addItem(info.portName());
}
// 设置波特率选项
ui->comboBox_baud->addItems({"9600", "115200", "19200", "38400"});
ui->comboBox_baud->setCurrentText("115200");
// 设置数据位选项
ui->comboBox_dataBits->addItems({"5", "6", "7", "8"});
ui->comboBox_dataBits->setCurrentText("8");
// 设置停止位选项
ui->comboBox_stopBits->addItems({"1", "1.5", "2"});
ui->comboBox_stopBits->setCurrentText("1");
// 设置校验位选项
ui->comboBox_parity->addItems({"None", "Even", "Odd", "Space", "Mark"});
ui->comboBox_parity->setCurrentText("None");
// 连接信号和槽
connect(serialPort, &QSerialPort::readyRead, this, &MainWindow::readData);
}
MainWindow::~MainWindow()
{
if (serialPort->isOpen()) {
serialPort->close();
}
delete ui;
}
void MainWindow::on_pushButton_open_clicked()
{
if (serialPort->isOpen()) {
serialPort->close();
ui->pushButton_open->setText("打开串口");
ui->statusBar->showMessage("串口已关闭");
} else {
// 设置串口参数
serialPort->setPortName(ui->comboBox_port->currentText());
serialPort->setBaudRate(ui->comboBox_baud->currentText().toInt());
// 设置数据位
switch (ui->comboBox_dataBits->currentText().toInt()) {
case 5: serialPort->setDataBits(QSerialPort::Data5); break;
case 6: serialPort->setDataBits(QSerialPort::Data6); break;
case 7: serialPort->setDataBits(QSerialPort::Data7); break;
case 8: serialPort->setDataBits(QSerialPort::Data8); break;
default: serialPort->setDataBits(QSerialPort::Data8); break;
}
// 设置停止位
if (ui->comboBox_stopBits->currentText() == "1") {
serialPort->setStopBits(QSerialPort::OneStop);
} else if (ui->comboBox_stopBits->currentText() == "1.5") {
serialPort->setStopBits(QSerialPort::OneAndHalfStop);
} else if (ui->comboBox_stopBits->currentText() == "2") {
serialPort->setStopBits(QSerialPort::TwoStop);
}
// 设置校验位
if (ui->comboBox_parity->currentText() == "None") {
serialPort->setParity(QSerialPort::NoParity);
} else if (ui->comboBox_parity->currentText() == "Even") {
serialPort->setParity(QSerialPort::EvenParity);
} else if (ui->comboBox_parity->currentText() == "Odd") {
serialPort->setParity(QSerialPort::OddParity);
}
// 打开串口
if (serialPort->open(QIODevice::ReadWrite)) {
ui->pushButton_open->setText("关闭串口");
ui->statusBar->showMessage("串口已打开");
} else {
ui->statusBar->showMessage("串口打开失败: " + serialPort->errorString());
}
}
}
void MainWindow::on_pushButton_send_clicked()
{
if (serialPort->isOpen()) {
QString sendData = ui->textEdit_send->toPlainText();
serialPort->write(sendData.toUtf8());
ui->statusBar->showMessage("数据已发送");
} else {
ui->statusBar->showMessage("请先打开串口");
}
}
void MainWindow::readData()
{
QByteArray data = serialPort->readAll();
ui->textEdit_receive->append(data);
}
// main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
五、关键特性技巧
1. 异步通信
-
通过信号槽机制处理数据接收(推荐方式):
connect(&serial, &QSerialPort::readyRead, this, [&]() { // 处理接收到的数据 });
2. 同步通信
-
使用
waitForReadyRead()
、waitForBytesWritten()
等阻塞函数(不推荐在 UI 线程中使用):if (serial.waitForReadyRead(1000)) { QByteArray data = serial.readAll(); }
3. 错误处理
-
通过
error()
信号或errorString()
获取错误信息:connect(&serial, &QSerialPort::errorOccurred, this, [](QSerialPort::SerialPortError error) { qDebug() << "串口错误:" << error; });
4. 超时设置
-
可设置读写超时时间(仅对同步模式有效):
serial.setReadBufferSize(1024); // 设置接收缓冲区大小
六、注意事项
-
跨平台兼容性 :
QtSerialPort 支持 Windows、Linux、macOS 等,但不同系统的串口名称格式不同(如 COM1、/dev/ttyUSB0)。
-
线程安全 :
串口数据接收是异步的,在复杂应用中需注意线程安全问题(可使用信号槽机制)。
-
性能优化 :
大量数据收发时,需考虑缓冲区处理和界面刷新频率,避免 UI 卡顿。