当前位置:首页 » 《关于电脑》 » 正文

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

12 人参与  2024年09月08日 12:42  分类 : 《关于电脑》  评论

点击全文阅读


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


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

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

在这里插入图片描述
在这里插入图片描述

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

? 概述? QSerialPort 类介绍常用方法信号和槽机制常用枚举类型 ? 示例代码示例:基本串口通信操作头文件:mainwindow.h源文件:mainwindow.cpp 代码解释方法分析高级应用技巧1. 实现串口数据完整性校验2. 使用线程处理串口通信3. 使用信号槽机制处理串口事件4. 动态调整串口参数 ? 常见问题及解决方法1. 串口无法打开2. 数据丢失或乱码3. 串口通信延迟 ? 总结

? 概述

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

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

? QSerialPort 类介绍

在 Qt 官方文档中,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_OBJECTpublic:    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_OBJECTpublic:    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,在各种应用场景中实现高效稳定的串口通信。


点击全文阅读


本文链接:http://zhangshiyu.com/post/157013.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1