当前位置: 首页 > news >正文

Qt串口通信设计指南:通信层架构与实践

一、串口通信在架构中的位置

在软件架构中,串口通信确实属于通信层(Communication Layer),负责设备与应用程序之间的数据传输。它位于硬件接口层之上,业务逻辑层之下,起到承上启下的作用。

典型的分层架构:

二、Qt串口通信设计原则

1. 模块化设计

  • 将串口功能封装为独立类

  • 对外提供简洁的接口

  • 隐藏底层实现细节

2. 分层架构

三、核心类设计(基于QSerialPort)

1. 基础串口类设计

// serialportmanager.h
#include <QObject>
#include <QSerialPort>
#include <QSerialPortInfo>class SerialPortManager : public QObject
{Q_OBJECT
public:explicit SerialPortManager(QObject *parent = nullptr);~SerialPortManager();bool openPort(const QString &portName, qint32 baudRate = QSerialPort::Baud9600,QSerialPort::DataBits dataBits = QSerialPort::Data8,QSerialPort::Parity parity = QSerialPort::NoParity,QSerialPort::StopBits stopBits = QSerialPort::OneStop);void closePort();bool isOpen() const;qint64 writeData(const QByteArray &data);signals:void dataReceived(const QByteArray &data);void errorOccurred(const QString &errorString);private slots:void handleReadyRead();void handleError(QSerialPort::SerialPortError error);private:QSerialPort *m_serialPort;
};

2. 实现文件

// serialportmanager.cpp
SerialPortManager::SerialPortManager(QObject *parent) : QObject(parent), m_serialPort(new QSerialPort(this))
{connect(m_serialPort, &QSerialPort::readyRead, this, &SerialPortManager::handleReadyRead);connect(m_serialPort, &QSerialPort::errorOccurred,this, &SerialPortManager::handleError);
}bool SerialPortManager::openPort(const QString &portName, qint32 baudRate,QSerialPort::DataBits dataBits,QSerialPort::Parity parity,QSerialPort::StopBits stopBits)
{m_serialPort->setPortName(portName);m_serialPort->setBaudRate(baudRate);m_serialPort->setDataBits(dataBits);m_serialPort->setParity(parity);m_serialPort->setStopBits(stopBits);return m_serialPort->open(QIODevice::ReadWrite);
}void SerialPortManager::handleReadyRead()
{QByteArray data = m_serialPort->readAll();while (m_serialPort->waitForReadyRead(50))data += m_serialPort->readAll();emit dataReceived(data);
}qint64 SerialPortManager::writeData(const QByteArray &data)
{if (!m_serialPort->isOpen()) {emit errorOccurred(tr("Port is not open"));return -1;}return m_serialPort->write(data);
}

四、高级设计模式

1. 协议解析层设计

// protocolhandler.h
class ProtocolHandler : public QObject
{Q_OBJECT
public:explicit ProtocolHandler(QObject *parent = nullptr);public slots:void processRawData(const QByteArray &data);signals:void packetReceived(const QVariantMap &parsedData);void checksumError(const QByteArray &invalidData);private:QByteArray m_buffer;bool verifyChecksum(const QByteArray &data);QVariantMap parseProtocol(const QByteArray &validData);
};

2. 使用示例

// 在应用层组合使用
SerialPortManager *serial = new SerialPortManager;
ProtocolHandler *protocol = new ProtocolHandler;// 连接信号槽
connect(serial, &SerialPortManager::dataReceived,protocol, &ProtocolHandler::processRawData);
connect(protocol, &ProtocolHandler::packetReceived,this, &MainWindow::handleParsedData);// 发送数据示例
QByteArray command = buildCommand("RELAY_ON", 1);
serial->writeData(command);

五、线程安全设计

1. 跨线程通信方案

// 在工作线程中创建串口对象
class SerialWorker : public QObject
{Q_OBJECT
public slots:void initPort() {m_serial = new QSerialPort;// 初始化配置...}void writeData(const QByteArray &data) {m_serial->write(data);}private:QSerialPort *m_serial;
};// 在主线程中使用
QThread *serialThread = new QThread;
SerialWorker *worker = new SerialWorker;
worker->moveToThread(serialThread);connect(this, &MainWindow::sendData, worker, &SerialWorker::writeData);
connect(serialThread, &QThread::started,worker, &SerialWorker::initPort);serialThread->start();

2. 数据缓冲区设计

// 线程安全的环形缓冲区
class CircularBuffer
{
public:CircularBuffer(int size = 4096);bool push(const QByteArray &data);QByteArray pop(int maxSize);bool isEmpty() const;private:QMutex m_mutex;QByteArray m_buffer;int m_head = 0;int m_tail = 0;const int m_capacity;
};

六、错误处理与调试

1. 完善的错误处理

void SerialPortManager::handleError(QSerialPort::SerialPortError error)
{if (error == QSerialPort::NoError)return;QString errorStr;switch (error) {case QSerialPort::DeviceNotFoundError:errorStr = "Device not found";break;case QSerialPort::PermissionError:errorStr = "Permission denied";break;// 其他错误处理...default:errorStr = m_serialPort->errorString();}emit errorOccurred(errorStr);// 自动重连逻辑if (error == QSerialPort::ResourceError) {QTimer::singleShot(1000, this, [this]() {if (!m_serialPort->isOpen())openPort(m_serialPort->portName());});}
}

2. 调试技巧

// 十六进制数据打印
qDebug() << "Received:" << data.toHex(' ');// 流量统计
static qint64 totalBytesReceived = 0;
totalBytesReceived += data.size();
qDebug() << "Total received:" << totalBytesReceived << "bytes";// 时间戳记录
QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss.zzz");
qDebug() << timestamp << "Data sent:" << command.toHex();

七、性能优化技巧

  1. 批量写入:合并小数据包

// 不好的做法
for (int i = 0; i < 100; i++) {serial.write(smallData[i]);
}// 好的做法
QByteArray batchData;
for (int i = 0; i < 100; i++) {batchData.append(smallData[i]);
}
serial.write(batchData);

2. 合理设置缓冲区大小

m_serialPort->setReadBufferSize(1024 * 64); // 64KB

3. 使用异步读写

// 使用readyRead信号而非轮询
connect(m_serialPort, &QSerialPort::readyRead, this, &SerialPortManager::handleReadyRead);

八、完整架构示例

九、设计模式应用

1. 状态模式处理不同协议

class ProtocolState {
public:virtual void handleData(ProtocolContext *context, const QByteArray &data) = 0;
};class ModbusState : public ProtocolState {
public:void handleData(ProtocolContext *context, const QByteArray &data) override {// Modbus协议处理逻辑}
};class CustomState : public ProtocolState {// 自定义协议处理
};

2. 观察者模式实现多订阅

class SerialSubject : public QObject {Q_OBJECT
public:void attach(SerialObserver *observer);void detach(SerialObserver *observer);signals:void dataUpdated(const QByteArray &data);private:QList<SerialObserver*> m_observers;
};

十、总结与最佳实践

  1. 分层设计:严格区分物理传输层、协议解析层和应用层

  2. 异步处理:使用信号槽机制实现非阻塞IO

  3. 线程安全:跨线程访问时使用QMutex保护或moveToThread

  4. 错误恢复:实现自动重连和错误恢复机制

  5. 协议无关:设计通用的接口,支持多种协议

  6. 资源管理:及时关闭串口和释放资源

通过以上设计,可以构建出健壮、可维护的Qt串口通信模块,满足工业控制、嵌入式设备通信等各种场景的需求。

http://www.dtcms.com/a/326191.html

相关文章:

  • K8S学习----应用部署架构:传统、虚拟化与容器的演进与对比
  • 虚拟财产刑事辩护:跨地域性与匿名性带来的挑战
  • 记录一些sonic自动化运行中的问题
  • 常见通信协议详解:TCP、UDP、HTTP/HTTPS、WebSocket 与 GRPC
  • 基于 Axios 的 HTTP 请求封装文件解析
  • Rust:专业级错误处理工具 thiserror 详解
  • Nginx 从入门到实战:安装、配置、升级与高级应用全解析
  • Web 开发前端与后端 API 的交互
  • golang 基础案例_01
  • 【MYSQL】MySQL中On duplicate key update
  • 台式机内存条安装方法
  • Docker中安装MySQL 5的详细过程
  • 算法讲解--水果成篮
  • GitHub的简单使用方法----(2)
  • Android中Activity销毁底层原理
  • AVS Video Converter视频转换与编辑工具深度评测
  • 基于OpenCV的实时美颜技术:从传统算法到深度学习融合实现
  • 光功率dBm为何是负数?一文详解
  • Effective C++ 条款35:考虑 virtual函数以外的其他选择
  • Spring源码解析 - SpringApplication run流程-prepareContext源码分析
  • MD5:理解MD5 / MD5核心特性 / MD5 在前端开发中的常见用途 / 在线生成MD5 / js-md5
  • Linux Docker 运行SQL Server
  • loading效果实现原理
  • Elasticsearch Node.js 客户端的安装
  • 第六十一章:AI 模型的“视频加速术”:Wan视频扩散模型优化
  • 简单清晰的讲解一下RNN神经网络
  • HarmonyOS 开发入门 第一章
  • 力扣面试150题--阶乘后的零,Pow(x,n)直线上最多的点
  • Win10电脑密码忘记如何进入操作系统
  • 基于AS32S601芯片的商业卫星光纤放大器(EDFA)抗单粒子效应解决方案研究