QT 串口接收数据不完整解决思路

一、问题描述

在串口通信时,会经常遇到,在接收一帧数据时,QSerialPort::readyRead()会触发多次,即接收一包数据需要多次接收才能完整得到数据帧。

二、解决思路

延迟接收: QSerialPort::readyRead()触发时不要立刻去接收数据,而是等待readyRead的最后一次触发时读数据。
如何等待最后一次readyRead: 用一个单触发定时器,readyRead触发时启动定时器,当定时器timeout(),可以认为是最后一次readyRead()

三、贴代码思路

    //!
    m_serial = new QSerialPort;
    connect(m_serial,&QSerialPort::readyRead,this,&MainWindow::slot_serialport_readyRead);

    //! 轮询定时器-周期性发送数据
    pTimerSend = new QTimer(this);
    pTimerSend->setTimerType(Qt::PreciseTimer);
    connect(pTimerSend, &QTimer::timeout, this, &MainWindow::slot_com_timeout_send);
    // pTimerSend->start(200); //串口连接成功后启动,此处仅为体现轮询周期为200ms

    //! 串口模式-数据延迟接收-保证数据完整
    pTimerRecv = new QTimer(this);
    pTimerRecv->setTimerType(Qt::PreciseTimer);
    pTimerRecv->setSingleShot(true); //只触发一次
    connect(pTimerRecv, &QTimer::timeout, this, &MainWindow::slot_serialport_delay_recv_timeout);
//! 串口接收信号
void MainWindow::slot_serialport_readyRead()
{
	//! 定时器重新启动,直到该函数不再触发(超过50ms),定时器触发
    pTimerRecv->start(50);	//4K数据,50ms的延迟接收完全没问题
}
//! 串口延迟接收
void MainWindow::slot_serialport_delay_recv_timeout()
{
    QByteArray Recv = m_serial->readAll();
    //! qDebug()<<"=="<
    //! qDebug()<<"###"<
    //! 处理接收的数据
    com_recv_data_process(Recv);
}

四、注意事项

  1. 延迟接收时长问题: 延迟时长应小于轮询周期
  2. 通信状况复杂不适用:若通信的串口中会打印调试信息或其他信息时,延迟接收可能出现问题,例如:由于串口中有打印的调试信息,readyRead()信号不断发生,导致pTimerRecv不断重启而无法触发延迟接收函数,从而导致收不到或收到远超应收字节数的数据。

五、总结

以上描述方式仅适合干净的通信环境,若想一劳永逸的适配各种环境,这里提供一个思路。如下:开辟一个缓存,实时接收串口数据(仅存),开一个子线程,识别缓存中的数据,去掉无法识别的数据,取出已识别数据。

你可能感兴趣的:(qt)