QSerialPort读取错误的数据计数

QSerialPort reads wrong count of data

本文关键字:数据 读取 取错误 QSerialPort      更新时间:2023-10-16

我想这样做:

我有一个测量压力的测量装置。它通过COM1连接。通过发送"ASCII字母9"数据,分别从该设备中检索测量值。这些测量应该显示在GUI中的qtableview子类中。我不希望GUI在读取测量设备时冻结,所以我想这被称为非阻塞。

在我的代码和测试中,我想在for循环中检索10个测量值。但我总是得到6,有时是7。

我还子类化了QSerialPort。

代码如下。提示我做错了什么,甚至可能是我的代码更正将非常感激。也可以随意评论代码的设计。

void MainWindow::startInspection()
{
    SauterFH_S *sauterFH_S;
    try
    {
        sauterFH_S = new SauterFH_S(new SerialPort(serialPort, 
        baudRate));
    }
    catch(QSerialPort::SerialPortError& e)
    {
        qDebug() << e;
    }
    connect(sauterFH_S, SIGNAL(measurandAvalaible(char*)),
        measurandTableWidget, SLOT(insertMeasurand(char*)));
    // Retrieve 10 measurements
    for(int i=0; i<10; ++i)
        sauterFH_S->getMeasurand();
    delete sauterFH_S;
}

子类QSerialPort的构造函数如下:

TASte::IO::SerialPort::SerialPort(const QString &portName, qint32 
    baudRate, DataBits dataBits, Parity parity, StopBits stopBits,
    QIODevice::OpenMode openMode, QObject *parent)
:QSerialPort(parent)
{
    setPort(QSerialPortInfo(portName));
    setBaudRate(baudRate);
    setDataBits(dataBits);
    setParity(parity);
    setStopBits(stopBits);
    if( !open(openMode) ) throw error();
}

下面是重要的内容:

TASte::Gauge::SauterFH_S::SauterFH_S(IO::SerialPort *port)
    :_port(port)
{
    connect(_port, SIGNAL(readyRead()),this, SLOT(onReadyRead()));
}
TASte::Gauge::SauterFH_S::~SauterFH_S()
{
    // delete _port;
}
void TASte::Gauge::SauterFH_S::getMeasurand()
{
    // typedef QByteArray SerialCommand
    IO::SerialCommand command("9");
    _port->write(command);
}

void TASte::Gauge::SauterFH_S::onReadyRead()
{
    // static const int DATA_LENGTH=8;
    char data[DATA_LENGTH];
    _port->read(data, DATA_LENGTH);
    emit measurandAvalaible(data);
}

提前感谢!

Object QSerialPort工作良好,如果你发送和接收数据在其他线程。在这种情况下,数据可能会丢失,程序有时会冻结。我也遇到过同样的问题。我给你看样东西。我写的代码每个使用UDP传输,但在串行端口是相同的概念。因此,首先必须为串行端口创建线程。在我的情况下,我创建了路由,但为UDP。你必须定义你的all connections,每个线程主窗口和串行端口之间的一些接口。

    thForUdp = new QThread();
    udp->moveToThread(thForUdp);
    thForUdp->start();
    connect(this , SIGNAL(SIGNAL_RefreshStatus()) , udp , SLOT(SLOT_refreshStatus()) , Qt::QueuedConnection);
    connect(udp , SIGNAL(SIGNAL_TransmitionFailed()) , this , SLOT(SLOT_TrasmitionFailed()) , Qt::QueuedConnection); //od
    connect(udp , SIGNAL(SIGNAL_ActualStatus(QByteArray)) , schema , SLOT(SLOT_ActualStatus(QByteArray)) , Qt::QueuedConnection);
    connect(udp , SIGNAL(SIGNAL_RefreshTimer()) , this , SLOT(SLOT_StartRefreshTimer()) , Qt::QueuedConnection ); //do
    connect(this , SIGNAL(SIGNAL_GetAllName()) , udp , SLOT(SLOT_GetAllName()) , Qt::QueuedConnection );
    connect(udp , SIGNAL(SIGNAL_AllName(QVector<QString>)) , schema , SLOT(SLOT_AllName(QVector<QString>)), Qt::QueuedConnection);
    connect(udp , SIGNAL(SIGNAL_setEnableRefresh(bool)) , this , SLOT(SLOT_setEnableRefresh(bool)) , Qt::QueuedConnection);

现在您必须创建从QSerialPort继承的对象。在我的例子中,我继承了QUdpSocket

class Udp : public QUdpSocket , public Object
{
    Q_OBJECT
public:
    Udp(Mediator *medium);
private slots:
    void SLOT_ReadyToReadStatus();
signals:
    void SIGNAL_TransmitionFailed();
    void SIGNAL_RefreshTimer();
    void SIGNAL_ActualStatus(QByteArray stat);
    void SIGNAL_AllName(QVector<QString> vec);
    void SIGNAL_setEnableRefresh(bool state);
};

正如你所看到的,Udp类有所有的信号,然后你在第一个块代码中看到。然后在串行端口类中创建正确的信号和插槽来发送和接收数据

在我的情况下,这是在构造器Udp

QObject::connect(this , SIGNAL(readyRead()) , this  , SLOT(SLOT_ReadyToReadStatus()));`

现在你的程序将在这个规则下工作。MainWindow窗体进程A发送信号(获取数据)->>在对象serialport在线程B中发送数据,在线程B中接收数据,然后serialport发送信号到线程A(发送接收到的数据到线程A) ->> MainWindow接收数据

非常重要的是在MainWindow和SerialPort 之间通过机制SIGNAL &SLOT,因为它们是两个不同的线程。这是QT规则。

这个解决方案将使你的程序不会冻结,数据被完整地接收,因为另一个线程负责这个。

通常我建议在发送数据后使用waitForReadyRead()功能,并通过waitForReadtRead接收

{
    if(!this->waitForReadyRead(3000))
    {
     // here is wait for data maximum 3 second 
    // if recived your data find in slot SLOT_ReadyToReadStatus()
    }
// if data is correct receive from this block you send to Thread A via SIGNAL!!
QByteArray array
SIGNAL_Here_Data_To_To_Thread_A(array)

}

Try this