首页 > 解决方案 > QSerial 使用同步回复

问题描述

我正在尝试从串口输入数据并仅在 30 毫秒内回复。我需要使用同步方法来写出数据。我将缓冲区设置为 1 个字节,是否正确?但是当我收到数据并将其写出时,它似乎不在给定的时间范围内。

QSerial 中是否有特殊设置?我的应用程序基于终端应用程序..

const QByteArray data = m_serial->readAll();
m_console->putData(data);


qDebug () << QTime::currentTime() << "data to lin " << data.toHex();
for (const char y: data)
{
    uint8_t dataint = static_cast<uint8_t>(y);
    LIN_Input(dataint,m_serial);
}





/*  LIN_Input: gets the serial data as uint8_t
 *
 */
#ifndef UseQt
void LIN_Input(uint8_t ipbyte, nrf_serial_t const * p_serial)
#else
void LIN_Input(uint8_t ipbyte, QSerialPort *m_serial)
#endif
{
#ifndef UseQt
    Lin_serialcommunicatin = (nrf_serial_t *)  p_serial; //copy the pointer of the serial port
#else
     Lin_serialcommunicatin = m_serial;
#endif
    InitializeStructs();   // Initialize Arrays
#ifndef nodebug
//    qDebug() << ipbyte;
#endif

    if (DataLen>0)  // split data into coressonding bytes
    {
        if (ByteCounter<=DataLen) //while still receiving data as expected by its length
        {
            if (ByteCounter<DataLen) //not last packet
            {
                ByteCounter++;
#ifndef nodebug
//                qDebug() << "Packet #" << ByteCounter << " id =" << id << " data=" << ipbyte;
//                qDebug() << "Parsing";
#endif
                InputSerialData[ByteCounter-1]=ipbyte;

            }
            else                     // last packet ** CheckSum
            {
                CheckSum = ipbyte;
                uint8_t returnedchecksum =0;
                bool checksum = CheckCheckSum(ByteCounter, InputSerialData, CheckSum, &returnedchecksum); //check checksum
                if (checksum)     //checksum is correct, parse data otherwise ignore it
                {
                    for (uint8_t i=1; i<=ByteCounter; i++)
                    {
                        LIN_Parse(id,i,ipbyte); //lin_parser uses Bytenumber starting from 1 to 8
                    }

                }
                ByteCounter=0;
                id=0;
                DataLen=0;

            }
#ifndef nodebug
//            ByteCounter==0? qDebug() << "CheckSum " << ipbyte :
//            qDebug() << "ID=" << id << " Byte " << ByteCounter << " is " << ipbyte;
#endif
        }
    }


    if (Sync)       //was Sync the previous Byte? Yes-> Current Byte is ID
    {
        DataLen=LIN_Determine_ID(ipbyte,&id);
#ifndef nodebug
        DataLen>0 ? qDebug() << "ID=" <<ipbyte << " expect data with " << DataLen << "bytes" : qDebug() << "received id=" << id;
#endif
        Sync=false;
        if (id==0x47)
        {
            QTime q;
            qDebug() << ".............................";
            qDebug() << q.currentTime() <<  "ID 47 received";
#ifndef nodebug
            qDebug() << "ID 47 request, now reply";
#endif
            Lin_serialcommunicatin->waitForBytesWritten(10);
            LIN_Reply_ID47();
        }
        if (id==0x92)
        {
            qDebug() << ".............................";
            qDebug() << QTime::currentTime() <<  "ID 92 received";

#ifndef nodebug
            qDebug() << "ID 92 request, now reply";
#endif
            Lin_serialcommunicatin->waitForBytesWritten(10);
            LIN_SendSerialData(8);
        }
    }
    //Recheck the sync statemachine independent on previous byte: There was a bug here because it was made with else if there was no Sync in Previous Byte
    //consequence was not detecting sucessive syncs. Bug fixed.
    Sync = LIN_determine_sync(ipbyte,&State);

    if (Sync)
    {
        ByteCounter=0;
        id=0;
#ifndef nodebug
        qDebug() << "sync";
#endif
    }


}







void LIN_SendSerialData(uint8_t nofbytes)
{
#ifdef emulator
    qDebug() << "lin Send";
#endif
   //nofbytes = 2 or 8. Using <= because i send the checksum also
   for (uint8_t i=0; i<=nofbytes; i++)
   {
#ifdef UseQt
       //qDebug() << "byte " << i << " = " << SerializedData[i];
       QByteArray array(reinterpret_cast<const char*>(&SerializedData[i]), sizeof(SerializedData[i]));
#endif

       //send_serial_data(SerializedData[i]);

#ifdef emulator
    qDebug() << "sending data to serial port =" << array << " hex=" << array.toHex();
#endif
#ifdef UseQt
         Lin_serialcommunicatin->write(array);
         QTime q;
         qDebug() << q.currentTime() <<  "Reply sent";
         qDebug() << " ............................. ";
#else
        char c;
        nrf_serial_t const * serialaddress = Lin_serialcommunicatin;

        c=(char) SerializedData[i];
        (void)nrf_serial_write(serialaddress, &c, sizeof(c), NULL, 0);
        (void)nrf_serial_flush(serialaddress, 0);
#endif
   }

}

标签: qtarduinoserial-port

解决方案


首先,您使用的是什么操作系统?标准 PC 操作系统的处理时间很差。这意味着当您收到数据可用的通知时,您可能已经损失了 10 毫秒。此外,如果您的串口通过 USB 2,由于 USB 默认轮询率为 125Hz,您可能会额外损失 8 毫秒。这使您只有 12 毫秒的时间将数据发回。

然后查看您的代码,您在发送回复之前做了很多事情,其中​​一些可能很耗时。

例如,您使用 执行大量 IO qDebug(),每次调用都会刷新输出。您还有一个呼叫InitializeStructs();,其名称听起来像是需要花费大量时间的事情。

首先要做的是衡量您在代码中损失了多少时间并优化耗时的操作。为此,您可以使用外部工具,如 callgrind 或仅使用QElapsedTimer::nsecsElapsed().

如果还不够,可以尝试提高 USB 轮询率。

如果您希望在必须发送回复之前接收多个字节的数据,则可以增加缓冲区大小。

如果还不够,您可以为您的线程保留一个 CPU 内核来进行串行通信。在 Linux 上寻找 ISOLCPUS。我不知道 Windows 上是否存在类似的东西。但我怀疑,你应该需要这个,因为 30 毫秒并不是那么关键。


推荐阅读