【QT开发】串口通信管理QSerialPort类详解及实战应用

CSDN 2024-08-20 12:35:02 阅读 64

QSerialPort 是 Qt 提供的一个功能强大、简单易用的串口通信类。通过本文的学习,您应该对 QSerialPort 的基本使用、高级应用技巧及相关注意事项有了全面的理解。在实际项目中,QSerialPort 可以帮助实现与外部设备的串口通信,确保数据的可靠传输和接收。希望本文能帮助您更好地理解和使用 QSerialPort,在各种应用场景中实现高效稳定的串口通信。


🧑 博主简介:现任阿里巴巴嵌入式技术专家,15年工作经验,深耕嵌入式+人工智能领域,精通嵌入式领域开发、技术管理、简历招聘面试。CSDN优质创作者,提供产品测评、学习辅导、简历面试辅导、毕设辅导、项目开发、C/C++/Java/Python/Linux/AI等方面的服务,如有需要请站内私信或者联系任意文章底部的的VX名片(ID:<code>gylzbk)

💬 博主粉丝群介绍:① 群内初中生、高中生、本科生、研究生、博士生遍布,可互相学习,交流困惑。② 热榜top10的常客也在群里,也有数不清的万粉大佬,可以交流写作技巧,上榜经验,涨粉秘籍。③ 群内也有职场精英,大厂大佬,可交流技术、面试、找工作的经验。④ 进群免费赠送写作秘籍一份,助你由写作小白晋升为创作大佬。⑤ 进群赠送CSDN评论防封脚本,送真活跃粉丝,助你提升文章热度。有兴趣的加文末联系方式,备注自己的CSDN昵称,拉你进群,互相学习共同进步。

在这里插入图片描述

在这里插入图片描述

【QT开发】串口通信管理QSerialPort类详解及实战应用

🌟 概述📖 QSerialPort 类介绍常用方法信号和槽机制常用枚举类型

💻 示例代码示例:基本串口通信操作头文件:mainwindow.h源文件:mainwindow.cpp

代码解释方法分析高级应用技巧1. 实现串口数据完整性校验2. 使用线程处理串口通信3. 使用信号槽机制处理串口事件4. 动态调整串口参数

🚩 常见问题及解决方法1. 串口无法打开2. 数据丢失或乱码3. 串口通信延迟

📌 总结

🌟 概述

QSerialPort 是 Qt 串口通信模块中的一个类,用于管理和控制串行端口通信。它提供了一种与串行设备(如传感器、终端、工业设备等)进行数据通信的便捷方式。通过 QSerialPort,您可以打开和配置串口、发送和接收数据、处理串口错误等。

QSerialPort 常用于需要与硬件设备进行串口通信的场景,比如串口调试工具,工业自动化系统,嵌入式系统通信等。

📖 QSerialPort 类介绍

在 Qt 官方文档中,<code>QSerialPort 类的定义如下:

class QSerialPort : public QIODevice

{ -- -->

Q_OBJECT

//...

}

QSerialPort 继承自 QIODevice,是一个用于串口通信的类。以下是一些关键特性和功能:

打开和关闭串口:能够打开和关闭指定的串口。配置串口参数:支持设置串口的波特率、数据位、停止位、校验位和流控制。读写数据:能够发送和接收数据。事件处理:通过信号槽机制处理串口的各种事件(如数据可读、错误发生等)。

常用方法

以下是 QSerialPort 类中一些常用的方法及其简要介绍:

构造函数和析构函数:

QSerialPort(QObject *parent = nullptr):默认构造函数。QSerialPort(const QString &name, QObject *parent = nullptr):通过串口名称构造。QSerialPort(const QSerialPortInfo &info, QObject *parent = nullptr):通过 QSerialPortInfo 对象构造。~QSerialPort():析构函数,关闭串口并释放资源。

打开和关闭串口:

bool open(QIODevice::OpenMode mode):以指定模式打开串口。void close():关闭串口。

配置串口参数:

bool setBaudRate(qint32 baudRate, Directions directions = AllDirections):设置波特率。qint32 baudRate(Directions directions = AllDirections) const:返回当前波特率。bool setDataBits(QSerialPort::DataBits dataBits):设置数据位。QSerialPort::DataBits dataBits() const:返回当前数据位。bool setParity(QSerialPort::Parity parity):设置校验位。QSerialPort::Parity parity() const:返回当前校验位。bool setStopBits(QSerialPort::StopBits stopBits):设置停止位。QSerialPort::StopBits stopBits() const:返回当前停止位。bool setFlowControl(QSerialPort::FlowControl flowControl):设置流控制。QSerialPort::FlowControl flowControl() const:返回当前流控制。

读写数据:

qint64 write(const char *data, qint64 maxSize):写入数据到串口。qint64 write(const QByteArray &byteArray):写入数据到串口。QByteArray readAll():读取所有可用数据。qint64 read(char *data, qint64 maxSize):读取数据。qint64 bytesAvailable() const:返回可读的字节数。bool waitForReadyRead(int msecs):等待数据可读。

串口控制:

bool setBreakEnabled(bool set):设置或清除串口的断点信号。bool flush():刷新串口缓冲区。

信号和槽机制

以下是 QSerialPort 类中一些常用的信号及其简要介绍:

信号:

void readyRead():当有数据可读时发出信号。void bytesWritten(qint64 bytes):当数据写入完成时发出信号。void errorOccurred(QSerialPort::SerialPortError error):当错误发生时发出信号。

常用枚举类型

以下是 QSerialPort 类中一些常用的枚举类型及其简要介绍:

QSerialPort::BaudRate:波特率。

Baud1200Baud2400Baud4800Baud9600Baud19200Baud38400Baud57600Baud115200UnknownBaud

QSerialPort::DataBits:数据位。

Data5Data6Data7Data8UnknownDataBits

QSerialPort::Parity:校验位。

NoParityEvenParityOddParityMarkParitySpaceParityUnknownParity

QSerialPort::StopBits:停止位。

OneStopOneAndHalfStopTwoStopUnknownStopBits

QSerialPort::FlowControl:流控制。

NoFlowControlHardwareControlSoftwareControlUnknownFlowControl

QSerialPort::SerialPortError:串口错误类型。

NoErrorDeviceNotFoundErrorPermissionErrorOpenErrorParityErrorFramingErrorBreakConditionErrorWriteErrorReadErrorResourceErrorUnsupportedOperationErrorUnknownError

💻 示例代码

下面是一个简单的示例,用来演示如何使用 QSerialPort 进行基本的串口通信操作。该示例展示了如何打开和关闭串口、配置串口参数、发送和接收数据以及处理串口错误。

示例:基本串口通信操作

头文件:mainwindow.h

#ifndef MAINWINDOW_H

#define MAINWINDOW_H

#include <QMainWindow>

#include <QSerialPort>

#include <QPushButton>

#include <QVBoxLayout>

#include <QTextEdit>

#include <QLabel>

#include <QComboBox>

#include <QLineEdit>

class MainWindow : public QMainWindow

{

Q_OBJECT

public:

MainWindow(QWidget *parent = nullptr);

~MainWindow();

private slots:

void openSerialPort();

void closeSerialPort();

void sendData();

void readData();

void handleError(QSerialPort::SerialPortError error);

private:

QSerialPort *serialPort;

QTextEdit *outputTextEdit;

QLineEdit *inputLineEdit;

QPushButton *openButton;

QPushButton *closeButton;

QPushButton *sendButton;

QComboBox *portNameComboBox;

QComboBox *baudRateComboBox;

};

#endif // MAINWINDOW_H

源文件:mainwindow.cpp

#include "mainwindow.h"

#include <QSerialPortInfo>

MainWindow::MainWindow(QWidget *parent)

: QMainWindow(parent), serialPort(new QSerialPort(this))

{

setWindowTitle("QSerialPort Example");

resize(400, 300);

// 创建UI组件

portNameComboBox = new QComboBox();

baudRateComboBox = new QComboBox();

openButton = new QPushButton("Open Serial Port");

closeButton = new QPushButton("Close Serial Port");

sendButton = new QPushButton("Send Data");

inputLineEdit = new QLineEdit();

outputTextEdit = new QTextEdit();

outputTextEdit->setReadOnly(true);

// 填充端口名称和波特率

foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) {

portNameComboBox->addItem(info.portName());

}

baudRateComboBox->addItem("9600", QSerialPort::Baud9600);

baudRateComboBox->addItem("19200", QSerialPort::Baud19200);

baudRateComboBox->addItem("38400", QSerialPort::Baud38400);

baudRateComboBox->addItem("115200", QSerialPort::Baud115200);

// 布局管理

QVBoxLayout *layout = new QVBoxLayout;

layout->addWidget(new QLabel("Port Name:"));

layout->addWidget(portNameComboBox);

layout->addWidget(new QLabel("Baud Rate:"));

layout->addWidget(baudRateComboBox);

layout->addWidget(openButton);

layout->addWidget(closeButton);

layout->addWidget(new QLabel("Input:"));

layout->addWidget(inputLineEdit);

layout->addWidget(sendButton);

layout->addWidget(new QLabel("Output:"));

layout->addWidget(outputTextEdit);

QWidget *centralWidget = new QWidget;

centralWidget->setLayout(layout);

setCentralWidget(centralWidget);

// 连接信号和槽

connect(openButton, &QPushButton::clicked, this, &MainWindow::openSerialPort);

connect(closeButton, &QPushButton::clicked, this, &MainWindow::closeSerialPort);

connect(sendButton, &QPushButton::clicked, this, &MainWindow::sendData);

connect(serialPort, &QSerialPort::readyRead, this, &MainWindow::readData);

connect(serialPort, &QSerialPort::errorOccurred, this, &MainWindow::handleError);

}

MainWindow::~MainWindow() = default;

void MainWindow::openSerialPort()

{

serialPort->setPortName(portNameComboBox->currentText());

serialPort->setBaudRate(static_cast<QSerialPort::BaudRate>(baudRateComboBox->currentData().toInt()));

serialPort->setDataBits(QSerialPort::Data8);

serialPort->setParity(QSerialPort::NoParity);

serialPort->setStopBits(QSerialPort::OneStop);

serialPort->setFlowControl(QSerialPort::NoFlowControl);

if (serialPort->open(QIODevice::ReadWrite)) {

outputTextEdit->append("Serial port opened.");

} else {

outputTextEdit->append("Failed to open serial port: " + serialPort->errorString());

}

}

void MainWindow::closeSerialPort()

{

if (serialPort->isOpen())

serialPort->close();

outputTextEdit->append("Serial port closed.");

}

void MainWindow::sendData()

{

if (serialPort->isOpen()) {

QByteArray data = inputLineEdit->text().toUtf8();

serialPort->write(data);

outputTextEdit->append("Data sent: " + data);

} else {

outputTextEdit->append("Serial port is not open.");

}

}

void MainWindow::readData()

{

QByteArray data = serialPort->readAll();

outputTextEdit->append("Data received: " + data);

}

void MainWindow::handleError(QSerialPort::SerialPortError error)

{

if (error == QSerialPort::ResourceError) {

outputTextEdit->append("Critical Error: " + serialPort->errorString());

closeSerialPort();

}

}

代码解释

创建主窗口,并设置其标题和大小:

MainWindow(QWidget *parent)

: QMainWindow(parent), serialPort(new QSerialPort(this))

{

setWindowTitle("QSerialPort Example");

resize(400, 300);

}

创建 QSerialPort 对象:

serialPort = new QSerialPort(this);

创建 UI 组件,包括端口名选择框、波特率选择框、按钮、文本编辑区域等:

portNameComboBox = new QComboBox();

baudRateComboBox = new QComboBox();

openButton = new QPushButton("Open Serial Port");

closeButton = new QPushButton("Close Serial Port");

sendButton = new QPushButton("Send Data");

inputLineEdit = new QLineEdit();

outputTextEdit = new QTextEdit();

outputTextEdit->setReadOnly(true);

填充端口名称和波特率:

foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) {

portNameComboBox->addItem(info.portName());

}

baudRateComboBox->addItem("9600", QSerialPort::Baud9600);

baudRateComboBox->addItem("19200", QSerialPort::Baud19200);

baudRateComboBox->addItem("38400", QSerialPort::Baud38400);

baudRateComboBox->addItem("115200", QSerialPort::Baud115200);

布局管理,将 UI 组件添加到布局中并设置为窗口中央控件:

QVBoxLayout *layout = new QVBoxLayout;

layout->addWidget(new QLabel("Port Name:"));

layout->addWidget(portNameComboBox);

layout->addWidget(new QLabel("Baud Rate:"));

layout->addWidget(baudRateComboBox);

layout->addWidget(openButton);

layout->addWidget(closeButton);

layout->addWidget(new QLabel("Input:"));

layout->addWidget(inputLineEdit);

layout->addWidget(sendButton);

layout->addWidget(new QLabel("Output:"));

layout->addWidget(outputTextEdit);

QWidget *centralWidget = new QWidget;

centralWidget->setLayout(layout);

setCentralWidget(centralWidget);

连接按钮点击信号和 QSerialPort 信号到槽函数:

connect(openButton, &QPushButton::clicked, this, &MainWindow::openSerialPort);

connect(closeButton, &QPushButton::clicked, this, &MainWindow::closeSerialPort);

connect(sendButton, &QPushButton::clicked, this, &MainWindow::sendData);

connect(serialPort, &QSerialPort::readyRead, this, &MainWindow::readData);

connect(serialPort, &QSerialPort::errorOccurred, this, &MainWindow::handleError);

实现打开串口的槽函数:

void MainWindow::openSerialPort()

{

serialPort->setPortName(portNameComboBox->currentText());

serialPort->setBaudRate(static_cast<QSerialPort::BaudRate>(baudRateComboBox->currentData().toInt()));

serialPort->setDataBits(QSerialPort::Data8);

serialPort->setParity(QSerialPort::NoParity);

serialPort->setStopBits(QSerialPort::OneStop);

serialPort->setFlowControl(QSerialPort::NoFlowControl);

if (serialPort->open(QIODevice::ReadWrite)) {

outputTextEdit->append("Serial port opened.");

} else {

outputTextEdit->append("Failed to open serial port: " + serialPort->errorString());

}

}

实现关闭串口的槽函数:

void MainWindow::closeSerialPort()

{

if (serialPort->isOpen())

serialPort->close();

outputTextEdit->append("Serial port closed.");

}

实现发送数据的槽函数:

void MainWindow::sendData()

{

if (serialPort->isOpen()) {

QByteArray data = inputLineEdit->text().toUtf8();

serialPort->write(data);

outputTextEdit->append("Data sent: " + data);

} else {

outputTextEdit->append("Serial port is not open.");

}

}

实现接收数据的槽函数:

void MainWindow::readData()

{

QByteArray data = serialPort->readAll();

outputTextEdit->append("Data received: " + data);

}

实现处理串口错误的槽函数:

void MainWindow::handleError(QSerialPort::SerialPortError error)

{

if (error == QSerialPort::ResourceError) {

outputTextEdit->append("Critical Error: " + serialPort->errorString());

closeSerialPort();

}

}

方法分析

构造函数:

QSerialPort(QObject *parent = nullptr)

QSerialPort(const QString &name, QObject *parent = nullptr)

QSerialPort(const QSerialPortInfo &info, QObject *parent = nullptr)

用于创建一个 QSerialPort 对象,指定串口名称或通过 QSerialPortInfo 对象来创建。

示例:

QSerialPort serialPort1;

QSerialPort serialPort2("COM1");

QSerialPortInfo portInfo;

QSerialPort serialPort3(portInfo);

bool open(QIODevice::OpenMode mode):以指定模式打开串口,可以是 QIODevice::ReadOnly, QIODevice::WriteOnly, 或 QIODevice::ReadWrite

bool open(QIODevice::OpenMode mode)

以指定的模式打开串口,返回值表示操作是否成功。

示例:

if (serialPort.open(QIODevice::ReadWrite)) {

qDebug() << "Serial port opened successfully.";

} else {

qDebug() << "Failed to open serial port:" << serialPort.errorString();

}

void close():关闭串口。

void close()

关闭当前打开的串口。

示例:

serialPort.close();

qDebug() << "Serial port closed.";

bool setBaudRate(qint32 baudRate, Directions directions = AllDirections):设置串口的波特率。

bool setBaudRate(qint32 baudRate, Directions directions = AllDirections)

设置串口的波特率,可以指定方向(读、写或两者)。返回值表示操作是否成功。

示例:

if (serialPort.setBaudRate(QSerialPort::Baud9600)) {

qDebug() << "Baud rate set to 9600.";

} else {

qDebug() << "Failed to set baud rate:" << serialPort.errorString();

}

qint32 baudRate(Directions directions = AllDirections) const:返回当前波特率。

qint32 baudRate(Directions directions = AllDirections) const

返回当前设置的波特率。

示例:

qint32 currentBaudRate = serialPort.baudRate();

qDebug() << "Current baud rate:" << currentBaudRate;

bool setDataBits(QSerialPort::DataBits dataBits):设置数据位。

bool setDataBits(QSerialPort::DataBits dataBits)

设置串口的数据位,常用值包括:QSerialPort::Data8QSerialPort::Data7等。返回值表示操作是否成功。

示例:

if (serialPort.setDataBits(QSerialPort::Data8)) {

qDebug() << "Data bits set to 8.";

} else {

qDebug() << "Failed to set data bits:" << serialPort.errorString();

}

QSerialPort::DataBits dataBits() const:返回当前数据位。

QSerialPort::DataBits dataBits() const

返回当前设置的数据位。

示例:

QSerialPort::DataBits currentDataBits = serialPort.dataBits();

qDebug() << "Current data bits:" << currentDataBits;

bool setParity(QSerialPort::Parity parity):设置校验位。

bool setParity(QSerialPort::Parity parity)

设置串口的校验位,包括:无校验(QSerialPort::NoParity)、偶校验(QSerialPort::EvenParity)、奇校验(QSerialPort::OddParity)等。返回值表示操作是否成功。

示例:

if (serialPort.setParity(QSerialPort::NoParity)) {

qDebug() << "No parity set.";

} else {

qDebug() << "Failed to set parity:" << serialPort.errorString();

}

QSerialPort::Parity parity() const:返回当前校验位。

QSerialPort::Parity parity() const

返回当前设置的校验位。

示例:

QSerialPort::Parity currentParity = serialPort.parity();

qDebug() << "Current parity:" << currentParity;

bool setStopBits(QSerialPort::StopBits stopBits):设置停止位。

bool setStopBits(QSerialPort::StopBits stopBits)

设置串口的停止位,包括:一个停止位(QSerialPort::OneStop)和两个停止位(QSerialPort::TwoStop)等。返回值表示操作是否成功。

示例:

if (serialPort.setStopBits(QSerialPort::OneStop)) {

qDebug() << "Stop bits set to one.";

} else {

qDebug() << "Failed to set stop bits:" << serialPort.errorString();

}

QSerialPort::StopBits stopBits() const:返回当前停止位。

QSerialPort::StopBits stopBits() const

返回当前设置的停止位。

示例:

QSerialPort::StopBits currentStopBits = serialPort.stopBits();

qDebug() << "Current stop bits:" << currentStopBits;

bool setFlowControl(QSerialPort::FlowControl flowControl):设置流控制。

bool setFlowControl(QSerialPort::FlowControl flowControl)

设置串口的流控制,包括:无流控制(QSerialPort::NoFlowControl)、硬件流控制(QSerialPort::HardwareControl)、软件流控制(QSerialPort::SoftwareControl)等。返回值表示操作是否成功。

示例:

if (serialPort.setFlowControl(QSerialPort::NoFlowControl)) {

qDebug() << "No flow control set.";

} else {

qDebug() << "Failed to set flow control:" << serialPort.errorString();

}

QSerialPort::FlowControl flowControl() const:返回当前流控制。

QSerialPort::FlowControl flowControl() const

返回当前设置的流控制方式。

示例:

QSerialPort::FlowControl currentFlowControl = serialPort.flowControl();

qDebug() << "Current flow control:" << currentFlowControl;

qint64 write(const char *data, qint64 maxSize):写入数据到串口。

qint64 write(const char *data, qint64 maxSize)

将指定的数据写入串口,返回写入的字节数。如果返回值为-1,则表示写入失败。

示例:

const char *data = "Hello";

qint64 bytesWritten = serialPort.write(data, strlen(data));

qDebug() << "Bytes written:" << bytesWritten;

qint64 write(const QByteArray &byteArray):写入数据到串口。

qint64 write(const QByteArray &byteArray)

将 QByteArray 类型的数据写入串口,返回写入的字节数。如果返回值为-1,则表示写入失败。

示例:

QByteArray data = "Hello";

qint64 bytesWritten = serialPort.write(data);

qDebug() << "Bytes written:" << bytesWritten;

QByteArray readAll():读取所有可用数据。

QByteArray readAll()

读取串口中所有可用的数据,并将其作为 QByteArray 返回。

示例:

QByteArray data = serialPort.readAll();

qDebug() << "Data received:" << data;

qint64 read(char *data, qint64 maxSize):读取数据。

qint64 read(char *data, qint64 maxSize)

从串口读取最多 maxSize 字节的数据,存储到 data 缓冲区中,返回读取的字节数。如果返回值为-1,则表示读取失败。

示例:

char buffer[100];

qint64 bytesRead = serialPort.read(buffer, sizeof(buffer));

qDebug() << "Bytes read:" << bytesRead;

qint64 bytesAvailable() const:返回可读的字节数。

qint64 bytesAvailable() const

该方法返回单个读缓冲区中当前要读取的字节数。它可以用于在读取数据之前确定有多少数据可用。

示例:

qint64 availableBytes = serialPort->bytesAvailable();

qDebug() << "Bytes available to read:" << availableBytes;

bool waitForReadyRead(int msecs):等待数据可读。

bool waitForReadyRead(int msecs)

该方法在指定的毫秒数内等待数据变得可读,如果在超时时间内有数据可读,则返回 true;否则返回 false。它通常与无事件驱动的嵌入式系统中的阻塞 I/O 一起使用。

示例:

if (serialPort->waitForReadyRead(5000)) {

QByteArray data = serialPort->readAll();

qDebug() << "Data received:" << data;

} else {

qDebug() << "Read timed out.";

}

bool setBreakEnabled(bool set):设置或清除串口的断点信号。

bool setBreakEnabled(bool set)

该方法设置或清除串口的断点信号。如果成功设置或清除断点信号,返回 true;否则,返回 false

示例:

if (!serialPort->setBreakEnabled(true)) {

qDebug() << "Failed to set break:" << serialPort->errorString();

}

bool flush():刷新串口缓冲区。

bool flush()

该方法刷新串口的输入和输出缓冲区。如果成功,则返回 true;否则,返回 false

示例:

if (serialPort->flush()) {

qDebug() << "Serial port buffer flushed.";

} else {

qDebug() << "Failed to flush buffer:" << serialPort->errorString();

}

高级应用技巧

1. 实现串口数据完整性校验

在串口通信中,使用校验和(checksum)或 CRC(循环冗余校验)来确保数据的完整性是常见做法。以下是一个简单的校验和计算示例:

uint8_t calculateChecksum(const QByteArray &data)

{

uint8_t checksum = 0;

for (char byte : data) {

checksum += static_cast<uint8_t>(byte);

}

return checksum;

}

在发送和接收数据时,可以附加校验和,并在接收时进行验证:

void MainWindow::sendDataWithChecksum(const QByteArray &data)

{

QByteArray packet = data;

uint8_t checksum = calculateChecksum(data);

packet.append(checksum);

serialPort->write(packet);

}

void MainWindow::readData()

{

QByteArray data = serialPort->readAll();

if (!data.isEmpty()) {

uint8_t receivedChecksum = data.at(data.size() - 1);

QByteArray payload = data.left(data.size() - 1);

if (calculateChecksum(payload) == receivedChecksum) {

outputTextEdit->append("Data received (valid): " + payload);

} else {

outputTextEdit->append("Data received (invalid checksum).");

}

}

}

2. 使用线程处理串口通信

为了避免在主线程中处理串口通信而导致界面卡顿,可以将串口通信放到单独的线程中。使用工作者/线程模式实现:

class SerialWorker : public QObject

{

Q_OBJECT

public:

SerialWorker(const QString &portName, QObject *parent = nullptr)

: QObject(parent), serialPort(new QSerialPort(portName, this)) { }

public slots:

void start()

{

if (serialPort->open(QIODevice::ReadWrite)) {

connect(serialPort, &QSerialPort::readyRead, this, &SerialWorker::readData);

qDebug() << "Serial port opened.";

} else {

qDebug() << "Failed to open serial port:" << serialPort->errorString();

}

}

void stop()

{

if (serialPort->isOpen()) {

serialPort->close();

}

qDebug() << "Serial port closed.";

}

void readData()

{

QByteArray data = serialPort->readAll();

emit dataReceived(data);

}

void writeData(const QByteArray &data)

{

if (serialPort->isOpen()) {

serialPort->write(data);

}

}

signals:

void dataReceived(const QByteArray &data);

private:

QSerialPort *serialPort;

};

在主程序中启动串口通信线程:

SerialWorker *worker = new SerialWorker("COM1");

QThread *thread = new QThread;

worker->moveToThread(thread);

connect(thread, &QThread::started, worker, &SerialWorker::start);

connect(thread, &QThread::finished, worker, &SerialWorker::stop);

connect(worker, &SerialWorker::dataReceived, [](const QByteArray &data) {

qDebug() << "Data received in main thread:" << data;

});

thread->start();

// 在需要时停止和清理线程

thread->quit();

thread->wait();

delete worker;

delete thread;

通过将串口通信移到单独的线程中,可以避免主线程的卡顿,确保界面响应流畅。

3. 使用信号槽机制处理串口事件

充分利用 QSerialPort 的信号槽机制,可以处理串口的各种事件(如数据可读、数据写入完成、错误发生等),从而实现异步通信。

// 主窗口类中的信号和槽连接

connect(serialPort, &QSerialPort::readyRead, this, &MainWindow::readData);

connect(serialPort, &QSerialPort::bytesWritten, this, &MainWindow::bytesWrittenHandler);

connect(serialPort, &QSerialPort::errorOccurred, this, &MainWindow::handleError);

// 槽函数

void MainWindow::bytesWrittenHandler(qint64 bytes)

{

qDebug() << bytes << "bytes written.";

}

void MainWindow::handleError(QSerialPort::SerialPortError error)

{

if (error == QSerialPort::ResourceError) {

qDebug() << "Critical Error:" << serialPort->errorString();

closeSerialPort();

}

}

4. 动态调整串口参数

在有些应用场景中,需要根据外部因素动态调整串口参数(如波特率、数据位等)。可以使用 QSerialPort 提供的相关方法来实现。

void MainWindow::adjustSerialPortParameters(qint32 baudRate, QSerialPort::DataBits dataBits)

{

if (serialPort->isOpen()) {

serialPort->setBaudRate(baudRate);

serialPort->setDataBits(dataBits);

qDebug() << "Serial port parameters adjusted:" <<

"BaudRate:" << baudRate <<

"DataBits:" << dataBits;

}

}

通过提供一个接口,允许用户或程序动态调整串口参数,以满足不同的通信需求。

🚩 常见问题及解决方法

1. 串口无法打开

在使用 QSerialPort 打开串口时,可能会遇到各种错误,其中一些常见原因包括:

串口被占用:检查串口是否被其他程序占用。权限问题:在 Linux 系统上,确保当前用户有权访问串口设备(通常需要属于 dialout 组)。

解决方法:

if (!serialPort->open(QIODevice::ReadWrite)) {

qDebug() << "Failed to open serial port:" << serialPort->errorString();

}

2. 数据丢失或乱码

数据丢失或乱码是串口通信中的常见问题,通常是由于串口参数(波特率、数据位、校验位、停止位)设置不匹配导致的。

解决方法:

确保通信双方的串口参数一致。检查串口缓冲区是否溢出,尝试增大缓冲区大小或更频繁地读取数据。使用适当的校验和/CRC 校验确保数据完整性。

3. 串口通信延迟

在某些情况下,串口通信可能会出现延迟,导致数据传输不及时。这可能是由多种因素引起的,包括硬件性能限制、串口配置、线程调度等。

解决方法:

尽量使用更高的波特率,以提高数据传输速度。将串口通信移到单独的线程中,避免主线程卡顿影响串口通信。优化数据传输和处理逻辑,减少不必要的延迟。

📌 总结

QSerialPort 是 Qt 提供的一个功能强大、简单易用的串口通信类。通过本文的学习,您应该对 QSerialPort 的基本使用、高级应用技巧及相关注意事项有了全面的理解。在实际项目中,QSerialPort 可以帮助实现与外部设备的串口通信,确保数据的可靠传输和接收。希望本文能帮助您更好地理解和使用 QSerialPort,在各种应用场景中实现高效稳定的串口通信。



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。