qt - 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
}
}
解决方案
首先,您使用的是什么操作系统?标准 PC 操作系统的处理时间很差。这意味着当您收到数据可用的通知时,您可能已经损失了 10 毫秒。此外,如果您的串口通过 USB 2,由于 USB 默认轮询率为 125Hz,您可能会额外损失 8 毫秒。这使您只有 12 毫秒的时间将数据发回。
然后查看您的代码,您在发送回复之前做了很多事情,其中一些可能很耗时。
例如,您使用 执行大量 IO qDebug()
,每次调用都会刷新输出。您还有一个呼叫InitializeStructs();
,其名称听起来像是需要花费大量时间的事情。
首先要做的是衡量您在代码中损失了多少时间并优化耗时的操作。为此,您可以使用外部工具,如 callgrind 或仅使用QElapsedTimer::nsecsElapsed()
.
如果还不够,可以尝试提高 USB 轮询率。
如果您希望在必须发送回复之前接收多个字节的数据,则可以增加缓冲区大小。
如果还不够,您可以为您的线程保留一个 CPU 内核来进行串行通信。在 Linux 上寻找 ISOLCPUS。我不知道 Windows 上是否存在类似的东西。但我怀疑,你应该需要这个,因为 30 毫秒并不是那么关键。
推荐阅读
- spring - 将版本从 2.3.8 更新到 2.5.6 时 Spring boot applicationcontext null
- python - 打印几个 CSV 文件以安装到 Postgres - 将 Float 转换为 Integer 时出错
- go - Golang ethclient.Client - 如何进行 RPC 调用?
- java - 使用java向具有国际字符的收件人发送电子邮件
- javascript - 我如何阻止 Parent Div 因为它的孩子而扩展?
- java - 如何在 VSCode 中将本机库链接到 Java 项目?
- tensorflow - 我如何使用 SpanBert 预测某些特定上下文中的令牌范围?
- java - 我如何 JUnit 测试来自 org.apache.springFramework.kafka.listener.adapter 的 RecordFilterStrategy
- java - cvc-complex-type.2.4.c:匹配通配符是严格的,但找不到元素“mongo:mongo”的声明。[11]
- json - 用于将数据保存在缓存中的 CSV 或 JSON