基于Qt实现高性能串口通讯应用程序,要求多线程,数据分包,高性能,高稳固 ...

打印 上一主题 下一主题

主题 1835|帖子 1835|积分 5505

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
2. 核心模块实现

2.1 线程安全的串口管理类
  1. class SerialPortWorker : public QObject {
  2.     Q_OBJECT
  3. public:
  4.     explicit SerialPortWorker(QObject *parent = nullptr)
  5.         : m_serial(new QSerialPort), m_buffer(1024*1024) // 1MB环形缓冲区
  6.     {
  7.         connect(m_serial, &QSerialPort::readyRead,
  8.             this, &SerialPortWorker::onDataReceived, Qt::DirectConnection);
  9.     }
  10. signals:
  11.     void packetReady(QByteArray packet);
  12.     void errorOccurred(QString err);
  13. public slots:
  14.     void startPort(const SerialSettings &settings) {
  15.         QMutexLocker lock(&m_mutex);
  16.         m_serial->setPortName(settings.portName);
  17.         m_serial->setBaudRate(settings.baudRate);
  18.         m_serial->setFlowControl(QSerialPort::HardwareControl);
  19.         if(!m_serial->open(QIODevice::ReadWrite)) {
  20.             emit errorOccurred(m_serial->errorString());
  21.         }
  22.         m_lastActiveTime = QDateTime::currentMSecsSinceEpoch();
  23.     }
  24. private slots:
  25.     void onDataReceived() {
  26.         const qint64 now = QDateTime::currentMSecsSinceEpoch();
  27.         const QByteArray data = m_serial->readAll();
  28.       
  29.         // 写入环形缓冲区
  30.         if(!m_buffer.write(data)) {
  31.             emit errorOccurred("Buffer overflow");
  32.             return;
  33.         }
  34.         // 分包处理(示例:固定头尾协议)
  35.         while(m_buffer.size() >= 4) {
  36.             if(m_buffer.peek(0) == 0xAA && m_buffer.peek(1) == 0x55) {
  37.                 const int length = m_buffer.peek(2);
  38.                 if(m_buffer.size() >= length + 4) {
  39.                     QByteArray packet;
  40.                     m_buffer.read(packet, length + 4);
  41.                     if(packet.back() == 0x0D) { // 校验尾字节
  42.                         emit packetReady(packet);
  43.                     }
  44.                 }
  45.             } else {
  46.                 m_buffer.skip(1); // 滑动窗口寻找包头
  47.             }
  48.         }
  49.         m_lastActiveTime = now;
  50.     }
  51. private:
  52.     QScopedPointer<QSerialPort> m_serial;
  53.     RingBuffer m_buffer;
  54.     QMutex m_mutex;
  55.     qint64 m_lastActiveTime = 0;
  56. };
复制代码
2.2 高性能环形缓冲区实现
  1. class RingBuffer {
  2. public:
  3.     explicit RingBuffer(size_t capacity)
  4.         : m_capacity(capacity),
  5.           m_buffer(new char[capacity]) {}
  6.   
  7.     bool write(const QByteArray &data) {
  8.         if(data.size() > freeSpace()) return false;
  9.       
  10.         std::lock_guard<std::mutex> lock(m_mutex);
  11.         const size_t tailSpace = m_capacity - m_tail;
  12.         if(data.size() <= tailSpace) {
  13.             memcpy(m_buffer.data() + m_tail, data.data(), data.size());
  14.         } else {
  15.             memcpy(m_buffer.data() + m_tail, data.data(), tailSpace);
  16.             memcpy(m_buffer.data(), data.data() + tailSpace, data.size() - tailSpace);
  17.         }
  18.         m_tail = (m_tail + data.size()) % m_capacity;
  19.         return true;
  20.     }
  21.     void read(QByteArray &out, size_t len) {
  22.         std::lock_guard<std::mutex> lock(m_mutex);
  23.         out.resize(len);
  24.         if(m_head + len <= m_capacity) {
  25.             memcpy(out.data(), m_buffer.data() + m_head, len);
  26.         } else {
  27.             const size_t firstPart = m_capacity - m_head;
  28.             memcpy(out.data(), m_buffer.data() + m_head, firstPart);
  29.             memcpy(out.data() + firstPart, m_buffer.data(), len - firstPart);
  30.         }
  31.         m_head = (m_head + len) % m_capacity;
  32.     }
  33.     size_t size() const {
  34.         return (m_tail >= m_head) ?
  35.             (m_tail - m_head) :
  36.             (m_capacity - m_head + m_tail);
  37.     }
  38. private:
  39.     std::mutex m_mutex;
  40.     std::unique_ptr<char[]> m_buffer;
  41.     size_t m_capacity = 0;
  42.     size_t m_head = 0;
  43.     size_t m_tail = 0;
  44. };
复制代码
4. 性能优化要点


  • 零拷贝设计

    • 利用memcpy直接操纵环形缓冲区内存
    • 制止QByteArray的多次构造和析构

  • 硬件加速
    1. // 主线程配置
    2. SerialSettings settings {
    3.     "/dev/ttyUSB0",
    4.     QSerialPort::Baud115200,
    5.     QSerialPort::Data8,
    6.     QSerialPort::NoParity,
    7.     QSerialPort::OneStop
    8. };
    9. QThread serialThread;
    10. SerialPortWorker worker;
    11. worker.moveToThread(&serialThread);
    12. // 错误处理和UI更新连接
    13. connect(&worker, &SerialPortWorker::packetReady,
    14.         this, &MainWindow::processPacket,
    15.         Qt::QueuedConnection);
    16. connect(&worker, &SerialPortWorker::errorOccurred,
    17.         this, &MainWindow::showError);
    18. QTimer::singleShot(0, &worker, [=](){
    19.     worker.startPort(settings);
    20. });
    21. serialThread.start();
    复制代码
  • 实时性保障
    1. class WriteHandler : public QObject {
    2.     Q_OBJECT
    3. public slots:
    4.     void enqueueWrite(const QByteArray &data) {
    5.         QMutexLocker lock(&m_queueMutex);
    6.         m_writeQueue.enqueue(data);
    7.         if(!m_isWriting) {
    8.             QTimer::singleShot(1, this, &WriteHandler::processQueue);
    9.         }
    10.     }
    11. private slots:
    12.     void processQueue() {
    13.         QByteArray packet;
    14.         {
    15.             QMutexLocker lock(&m_queueMutex);
    16.             if(m_writeQueue.isEmpty()) {
    17.                 m_isWriting = false;
    18.                 return;
    19.             }
    20.             packet = m_writeQueue.dequeue();
    21.         }
    22.         qint64 bytesWritten = 0;
    23.         while(bytesWritten < packet.size()) {
    24.             const qint64 ret = m_port->write(packet.constData() + bytesWritten,
    25.                                            packet.size() - bytesWritten);
    26.             if(ret == -1) {
    27.                 emit writeFailed(m_port->errorString());
    28.                 return;
    29.             }
    30.             bytesWritten += ret;
    31.             if(!m_port->waitForBytesWritten(100)) {
    32.                 emit timeout("Write operation timeout");
    33.                 return;
    34.             }
    35.         }
    36.         QTimer::singleShot(1, this, &WriteHandler::processQueue);
    37.     }
    38. private:
    39.     QSerialPort* m_port;
    40.     QQueue<QByteArray> m_writeQueue;
    41.     QMutex m_queueMutex;
    42.     bool m_isWriting = false;
    43. };
    复制代码
5. 稳固性保障措施

<ol>心跳检测机制
  1. // 在Linux平台启用DMA加速
  2. m_serial->setReadBufferSize(1024*1024); // 1MB硬件缓冲区
  3. m_serial->setDevicePolicy(QSerialPort::FlushOnAccess);
复制代码
错误规复流程
  1. // 设置线程优先级
  2. QThread::currentThread()->setPriority(QThread::TimeCriticalPriority);
  3. // 禁用系统缓冲
  4. m_serial->setDataTerminalReady(true);
  5. m_serial->setRequestToSend(true);
复制代码
数据完备性校验
[code]bool verifyChecksum(const QByteArray &packet) {    quint8 sum = 0;    for(int i=2; i
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

乌市泽哥

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表