串行丢包 - QTSerialPort

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了串行丢包 - QTSerialPort相关的知识,希望对你有一定的参考价值。

我正在制作一个程序,以每秒250个样本(115200波特)读取来自串行RN42蓝牙连接的数据流。在运行代码时,我注意到有些数据没有被删除和读取,因此不同步。

SerialMonitor::SerialMonitor(QObject *parent) :
    QObject(parent)
{

    // Initialization here

     DAQ = new QSerialPort(this);
     DAQ->setPortName("/dev/tty.BIOEXG-SPP");
     DAQ->setBaudRate(QSerialPort::Baud115200);
     DAQ->setDataBits(QSerialPort::Data8);
     DAQ->setParity(QSerialPort::NoParity);
     DAQ->setStopBits(QSerialPort::OneStop);
     DAQ->setFlowControl(QSerialPort::NoFlowControl);

     if (DAQ->open(QIODevice::ReadOnly)) printf("Success!
");
     else printf("FAILED...
");

     connect(DAQ, SIGNAL(readyRead()), this, SLOT(WriteToText()));
}

void SerialMonitor::WriteToText()
{
    while (DAQ->canReadLine()) {
        QString IncomingData = DAQ->readLine();

        // More processing here

    }
}

}

我的代码有问题吗?如果没有,有没有办法解决这个问题?这是一个EEG设备,因此每个数据点都至关重要。

提前致谢!

答案

您已禁用所有错误检查和同步机制:

  • 奇偶校验位已禁用。
  • 流量控制已禁用。

如果您可以控制设备上的微控制器,那么一个很好的选择就是实现一个用于恢复丢失数据的chk机制。如果您的设备是黑盒子,则必须使用HW机制来提高稳定性。当使用无线通信时,存在丢失一些数据的可能性并且在项目中被考虑。

注意:您应该在打开之后设置串行参数,而不是之前。

另一答案
  1. 您可以尝试使用bytesAvailable/readAll()而不是(can)readLine()进行检查。
  2. 驱动程序有可能无法及时从FIFO读取数据,从而导致数据丢失(可能是驱动程序问题)。
另一答案

我有同样的问题。 QSerialPort有时会丢失一些字节块。我修改了我在网上找到的一段旧代码,这不会丢失任何东西。

#include "QVSerialPort.hpp"
#include <QtDebug>

//////////////////////////////////////////
// Set header file for documentation    /
////////////////////////////////////////

//////////////////////////////////////////////////////
// Windows Version of the serial port driver Code
/////////////////////////////////////////////////////

#ifdef Q_OS_WIN32

#include <windows.h>

QVSerialPort::QVSerialPort(QObject *parent) :
    QThread(parent)
{
    // make everything in this thread, run in this thread. (Including signals/slots)
    QObject::moveToThread(this);
    // make our data buffer
    dataBuffer = new QByteArray();
    hSerial = INVALID_HANDLE_VALUE;
    running = true;
    deviceName=NULL;
    bufferSem = new QSemaphore(1); // control access to buffer
}

QVSerialPort::~QVSerialPort() {
    running = false;
    CloseHandle(hSerial);
}

//write data to serial port
int QVSerialPort::writeBuffer(QByteArray *buffer) {
        int dwBytesRead = 0;
    if (hSerial != INVALID_HANDLE_VALUE) {
        // have a valid file discriptor
        WriteFile(hSerial, buffer->constData(), buffer->size(), (DWORD *)&dwBytesRead, NULL);
        return dwBytesRead;
    } else {
        return -1;
    }
}

// setup what device we should use
void QVSerialPort::usePort(QString *device_Name, int _buad, int _byteSize, int _stopBits, int _parity) {
    deviceName = new QString(device_Name->toLatin1());
    // serial port settings
    Buad = _buad;
    ByteSize = _byteSize;
    StopBits = _stopBits;
    Parity = _parity;
}

// data fetcher, get next byte from buffer
uint8_t QVSerialPort::getNextByte() {
    // mutex needed to make thread safe
    bufferSem->acquire(1); // lock access to resource, or wait untill lock is avaliable
    uint8_t byte = (uint8_t)dataBuffer->at(0); // get the top most byte
    dataBuffer->remove(0, 1); // remove top most byte
    bufferSem->release(1);
    return byte; // return top most byte
}

// return number of bytes in receive buffer
uint32_t QVSerialPort::bytesAvailable() {
    // this is thread safe, read only operation
    bufferSem->acquire(1); // lock access to resource, or wait untill lock is avaliable
    uint32_t res = (uint32_t)dataBuffer->size();
    bufferSem->release(1);
    return res;
}

// our main code thread
void QVSerialPort::run() {
//    bufferSem->release(1);      // not in a locked state

    // thread procedure
    if (_SERIALTHREAD_DEBUG) {
        qDebug() << "QVSerialPort: QVSerialPort Started..";
        qDebug() << "QVSerialPort: Openning serial port " << deviceName->toLatin1();
    }

    // open selected device
    hSerial = CreateFile( (WCHAR *) deviceName->constData() , GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    if ( hSerial == INVALID_HANDLE_VALUE ) {
        qDebug() << "QVSerialPort: Failed to open serial port " << deviceName->toLatin1();
        emit openPortFailed();
        return;  // exit thread
    }

    // Yay we are able to open device as read/write
    qDebug() << "QVSerialPort: Opened serial port " << deviceName->toLatin1() << " Sucessfully!";

    // now save current device/terminal settings
    dcbSerialParams.DCBlength=sizeof(dcbSerialParams);

    if (!GetCommState(hSerial, &dcbSerialParams)) {
                qDebug() << "QVSerialPort: Failed to get com port paramters";
                emit openPortFailed();
                return;
        }

    if (_SERIALTHREAD_DEBUG) {
        qDebug() << "QVSerialPort: Serial port setup and ready for use";
        qDebug() << "QVSerialPort: Starting QVSerialPort main loop";
    }
    dcbSerialParams.BaudRate=Buad;
    dcbSerialParams.ByteSize=ByteSize;
    dcbSerialParams.Parity=Parity;
    dcbSerialParams.StopBits=StopBits;

    if(!SetCommState(hSerial, &dcbSerialParams)) {
                qDebug() << "QVSerialPort: Failed to set new com port paramters";
                emit openPortFailed();
                return;
    }
    COMMTIMEOUTS timeouts;

    timeouts.ReadIntervalTimeout = 0;
    timeouts.ReadTotalTimeoutMultiplier = 0;
    timeouts.ReadTotalTimeoutConstant = 0;
    timeouts.WriteTotalTimeoutMultiplier = 1;
    timeouts.WriteTotalTimeoutConstant = 1;
    if (!SetCommTimeouts(hSerial, &timeouts)){
        qDebug()<<" error setcommtimeout";
    }
    // signal we are opened and running
    emit openPortSuccess();

    static uint8_t byte123[1023]; // temp storage byte
    int dwBytesRead;
    int state=0;    // state machine state

    // start polling loop
    while(running) {
        int ret = ReadFile(hSerial, (void *)byte123, 128, (DWORD *)&dwBytesRead, NULL); // reading 1 byte at a time..  only 2400 baud.
        // print what we received
        if (ret != 0 && dwBytesRead > 0){
            if (_SERIALTHREAD_DEBUG) {
                qDebug() << "QVSerialPort: Received byte with value: " << byte123[0];
            }
            if (dataBuffer->size() > 1023*1024) {
                if ( state == 0 ) {
                    qDebug() << "Local buffer overflow, dropping input serial port data";
                    state = 1;  // over-flowed state
                    emit bufferOverflow();
                }
            } else {
                if ( state == 1 ) {
                    qDebug() << "Local buffer no-longer overflowing, back to normal";
                    state = 0;;
                }
                // stick byte read from device into buffer
                // Mutex needed to make thread safe from buffer read operation
                bufferSem->acquire(1);
                for (int i=0;i<dwBytesRead;i++)
                    dataBuffer->append(byte123[i]);
                bufferSem->release(1);
                emit hasData(); // signal our user that there is data to receive
            }
        }
    }
    CloseHandle(hSerial);
}

#else

//////////////////////////////////////////////////////////
// Linux/Mac/BSD Version of the serial port driver Code
////////////////////////////////////////////////////////

// POSIX C stuff for accessing the serial port
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>

// Constructor
QVSerialPort::QVSerialPort(QObject *parent) :
    QThread(parent)
{
    // make everything in this thread, run in this thread. (Including signals/slots)
    QObject::moveToThread(this);
    // make our data buffer
    dataBuffer = new QByteArray();
    running = true;
    deviceName=NULL;
    bufferMutex = new QMutex(); // control access to buffer
    bufferMutex->unlock();  // not in a locked state
}

QVSerialPort::~QVSerialPort() {
                running = false;
                close(sfd);
}

//write data to serial port
int QVSerialPort::writeBuffer(QByteArray *buffer) {
    if (sfd != 0) {
        // have a valid file discriptor
        return write(sfd, buffer->constData(), buffer->size());
    } else {
        return -1;
    }
}

// setup what device we should use
void QVSerialPort::usePort(QString *device_Name) {
    deviceName = new QString(device_Name->toLatin1());
    if (_SERIALTHREAD_DEBUG) {
        qDebug() << "QVSerialPort: Using device: " << deviceName->toLatin1();
    }
}

// data fetcher, get next byte from buffer
uint8_t QVSerialPort::g

以上是关于串行丢包 - QTSerialPort的主要内容,如果未能解决你的问题,请参考以下文章

在串行端口(QtSerialPort)读取传入字节的连续流

如何让 qtserialport 为 Native QT 的 NVIDIA TX1 工作?

Qt 串行端口错误 - 未读取数据

使用 pyside 进行异步串行通信

为啥 QtSerialPort 在运行超过一次或两次后不会读取?

Arduino 和 QtSerialPort 始终打开错误