【问题标题】:Qt reading serial data - working code but needs to be more reliableQt 读取串行数据 - 工作代码,但需要更可靠
【发布时间】:2018-03-29 21:01:59
【问题描述】:

我正在从 Arduino 微控制器向运行 Qt 的 PC 发送几 kB 的数据。

Arduino 根据来自 PC 的命令测量数据,然后像这样将数据发回:

void loop(){

// I wait for trigger signal from PC, then begin data acquisition
// Data are acquired from a sensor, typically few thousand 16-bit values
// 1 kHz sampling rate, store data on SRAM chip

// Code below transfers data to PC
   for(unsigned int i=0;i<datalength;i++){

     // Get data from SRAM
     msb=SPI.transfer(0x00);
     lsb=SPI.transfer(0x00);        

     // Serial write
     Serial.write(msb);
     Serial.write(lsb);
     }
Serial.flush();

} // Loop over

Qt 正在接收这样的数据:

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)  
{
ui->setupUi(this);

if(microcontroller_is_available){
   // open and configure serialport
    microcontroller->setPortName(microcontroller_port_name);
    microcontroller->open(QSerialPort::ReadWrite);
    microcontroller->setBaudRate(QSerialPort::Baud115200);
    microcontroller->setDataBits(QSerialPort::Data8);
    microcontroller->setParity(QSerialPort::NoParity);
    microcontroller->setStopBits(QSerialPort::OneStop);
    microcontroller->setFlowControl(QSerialPort::NoFlowControl);
    }

connect(microcontroller, &QSerialPort::readyRead, this, &MainWindow::readData);
}

void MainWindow::readData()  // Read in serial data bytes
{
    serialData += microcontroller->readAll();

    if(serialData.length()==2*datalength){ 
// Once all serial data received
// Do something, like save data to file, plot or process
}
}

现在上面的代码工作得很好,但是偶尔(假设每几百次采集一次,所以不到 1% 的时间)并不是所有的数据都会被 Qt 和我的 @987654323 接收上面的@函数悬而未决。我必须重置程序。所以我的问题是:我怎样才能使数据传输更可靠并避免丢失字节?

仅供参考:我知道存在 Arduino stackexchange。我没有在那里发帖,因为这似乎是一个与 Qt 相关的问题,而不是 Arduino。

【问题讨论】:

  • 我从来都不喜欢这样的为最好的协议祈祷。您是否最好在定义明确的块中传输数据,每个块都有一个标头、校验和/CRC、尾部、timoeout 和 ACK/NACK,以便始终可以重新发送并从通信失败中恢复?
  • 如果您可以忽略该消息,请尝试合并超时系统?
  • 可能是的。你知道我可以遵循的任何既定协议的名称,而不是自己破解一些东西吗?
  • 嗯,它是相同的东西,但你传输一些额外的数据,你可以将它们放入一些逻辑来管理传输。然而,它会增加复杂性和数据开销,但大多数时候这不是问题。您的数据包似乎是恒定大小的,因此可以稍微简化一下。
  • 什么是datalength?是常数吗?

标签: c++ qt arduino serial-port


【解决方案1】:

我没有仔细研究它,但似乎问题可能与这一行有关:

if(serialData.length()==2*datalength)

所以,如果你得到一些额外的数据,你就会放弃整个事情吗?毕竟,不能保证数据会到达整齐离散的块。

如果长度大于或等于,你应该读入数据,读入指定的长度并留下剩余的数据,因为它是下一个块的一部分。

它还可以解释为什么你的函数会挂起 - 如果你碰巧超过 2*datalength 条件永远不会成立。

但即使你解决了这个问题,实现还是有点幼稚,不能被认为是完全证明的。还有其他可能出错的地方,您将需要更多描述性的块数据,这样您就可以找出出错的地方以及如何修复它或跳过错误,而无需在齿轮上扔扳手。

【讨论】:

  • 我同意这很幼稚。我从没想过分块发送数据,这似乎是个好主意。假设我从微控制器发送 1 kB 数据,然后发送几个预定字节来表示该块的结束。如果 Qt 读取了这些权限,它会请求传输下一个 1kB 块,否则再次传输前一个 1kB 块。明白了,或者你会做一些更详细的事情?
  • 理论上你仍然以datalength*2长度的块发送它,但实际上你无法判断一个块的开始或结束位置,无法解释丢失或损坏的数据包或停顿.您的代码“大部分工作”的原因非常幸运,再次无法保证传输时间和粒度,充其量您可以假设您将获得一些数据,并将其累积到希望结束的数据中一个有效的数据块。您的使用场景不清楚,您宁愿跳过什么 - 数据传输或可能是您在 mcu 端进行的数据采集。
  • 我的场景是说我一次将获取的数据发送到 PC 1 kB,假设我获取的数据超过 1 kB(通常是 16 kB)。如果我没有正确读取块的标头/签名,那么我会要求再次发送该块。
  • 好吧,试试看效果如何。请记住,本网站的范围是关于特定的编程问题,因此如果出现另一个问题,您应该创建一个新问题。过于宽泛的问题通常是封闭的。 Martin James 已经列出了制作完整解决方案所需的所有内容。
  • 到目前为止的答案很有帮助。我将在原始问题中发回调查结果。谢谢。
【解决方案2】:

我建议的一些事情是将您的数据包装在一个信封中。每次您想发送数据时,添加一个标题字符(例如“H”)和签名(可能是“S”?)。在接收部分检查您的消息的第一个和最后一个字符并确保它是应该的。这将几乎消除噪音和不完整的数据。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-01-10
    • 2016-03-04
    • 1970-01-01
    • 1970-01-01
    • 2019-01-20
    • 1970-01-01
    • 1970-01-01
    • 2013-02-12
    相关资源
    最近更新 更多