是什么导致我的程序延迟?读取串行数据并解析 ESP32:Arduino IDE

问题描述

在我的测试程序中,出现意外延迟(大约 100 毫秒)。 我正在尝试从 GPS 读取数据(作为 NMEA 语句)并解析它。 目前,程序读取数据,如果是 NMEA 语句,它会尝试解析它。问题是,我在某些消息之间延迟了大约 100 毫秒。

GPS 的波特率为 9600,这会导致问题吗?

我的方法是解析 GGA 语句,并尽快将修改后的自定义语句重新发送到不同的串行端口 (USB),其中添加了传感器数据(应该看起来像最初来自 GPS - 如此同步)

我的输出如下所示: Output from program

13:38:31.306 -> $GPGSV,3,1,10,02,25,125,06,28,083,12,79,312,15,05,189,0*6E
13:38:31.306 -> $GPGSV,0*6E
13:38:31.306 -> 5
13:38:31.306 -> $GPGSV,2,17,11,042,19,32,049,24,59,149,36,270,0*60
13:38:31.410 -> $GPGSV,0*60
13:38:31.410 -> 112
13:38:31.410 -> $GPGSV,29,04,210,303,0*62
13:38:31.410 -> $GPGSV,0*62
13:38:31.410 -> 3
13:38:31.410 -> $GLGSV,69,00,219,70,23,71,21,324,73,293,0*75
13:38:31.544 -> $GLGSV,0*75
13:38:31.544 -> 113
13:38:31.544 -> $GLGSV,78,101,57,075,80,51,314,81,56,0*72
13:38:31.544 -> $GLGSV,0*72
13:38:31.544 -> 7

接收到字节后直接打印第一句。收到完整的句子后,第二个句子会打印为字符串。

这是我的代码:

#define RXD2 13
#define TXD2 12
#define SERIAL_SIZE_RX  1024    // used in Serial.setRxBufferSize()

bool bNMEAstarted = false;
String NMEAsent;

unsigned long currentTime,lastTime;

void setup() {
  Serial.begin(115200);
  delay(15);

  //GPS serial
  Serial2.begin(9600,SERIAL_8N1,RXD2,TXD2);
  delay(150);
  //Serial2.setRxBufferSize(SERIAL_SIZE_RX);  //increase buffer size to 1024 bytes
  currentTime = millis();
  lastTime = currentTime;
}

void loop() {
  receiveFromGPS();
}


void receiveFromGPS(){
  byte incomByte1 = 0;
  if (Serial2.available()>0){
    incomByte1 = Serial2.read();
    Serial.write(incomByte1);
    
    // Parsing NMEA sentence
    if (incomByte1 == '$') {        //means it is NMEA sentece
      bNMEAstarted = true;
      NMEAsent = "";                //empty the string
    }

    if (bNMEAstarted) {
      NMEAsent += (char)incomByte1;       //add every character to NMEA sentence
      if (incomByte1 == 10) {             //ASCII(10) <LF> (Linefeed) ends the message
        bNMEAstarted = false;
        //do parsing after the end on sentence
        parseNMEA(NMEAsent);
      }
    }
  }
}


void parseNMEA(String sNMEA) {
  //if (sNMEA.substring(3,6) == "GGA") {      // GGA Message found

    //only print every NMEA sentence and time between each measurements
    Serial.print(sNMEA);
    currentTime = millis();
    Serial.println(currentTime-lastTime);
  //} 
  lastTime = currentTime;
}

解决方法

较长的 GGA 语句是 64 字节长。在 9600 波特时,一个字节的传输时间大约为 1 毫秒。如果您的 GPS 在它们之间没有任何延迟地吐出 GGA 句子,那么它应该每 64 毫秒接收一个句子 - 这是您的平均水平。

这里令人困惑的部分可能是这样的事实:有时读取似乎发生得非常快( 100 毫秒)。这是由 UART 的缓冲区引起的。 ESP32 中的 UART 在接收端有一个 128 B 的 FIFO 缓冲区,它接收传入的字节并且在 one of two conditions 发生之前不会将它们给你:

  1. 缓冲区已满(未记录确切数量)或
  2. 缓冲区未满(但保存了一些数据)并且发生了 RX 超时(未记录确切的超时值)。

这会造成您最终会获得数据的情况,但它有点……断断续续。很抱歉,我不知道如何解决这个问题,因为 UART 缓冲区不能轻易绕过(或者,至少,没有关于如何做到这一点的官方文档)。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...