如何检查串行数据之间的差距

时间:2014-05-14 21:19:56

标签: arduino

我正在研究从汽车上的单线总线读取串行数据的接口(BMW IBUS)。我使用Microchip MCP2025 LIN总线收发器芯片将单线总线转换为常规Rx / Tx,以馈入Arduino(Nano V3)的硬件串行引脚(0& 1)。

宝马的IBUS协议使用9600波特的串行8E1。消息是可变长度(在5到37个字节之间)总线消息由大约11毫秒的暂停分开(比接收时的总线高电平时间长得多)并且我需要使用此间隙来检测一条消息的结束和开始下一个。

第一个字节是源ID,  第二个字节是数据包的长度,不包括前两个字节(源和长度),  第3个字节是目标ID,  第4个字节以后是实际数据,  最后一个字节是校验和

校验和是由整个数据包的XOR生成的,不包括校验和本身。

我的问题是我不知道如何测量消息之间的总线空闲时间。我想我可以使用bitRead(PIND,0)来判断总线何时空闲(高),但我不知道如何计算时间并在适当的时间过后继续处理消息。

我目前正在使用以下代码来阅读来自IBUS的消息。它大部分都有效,但在连接到汽车时却不同步。它不知道消息何时完成,但依赖于每条消息的第二个字节(长度字节)来知道要读入多少字节。只要它正确读取长度字节,它很好,但是如果它不同步,并且长度字节错误,它会读取错误的字节数并最终超出数组并且Arduino重置。如果我能检测到消息之间的空闲时间,我将确定我有一个完整的消息。

    void ReadIBUS()
{ 
  boolean inSTATE = 0;
  byte IBUSbyte[40];

  while(Serial.available() > 0 && inSTATE == 0 )
  { 
    IBUSbyte[0] = Serial.read();  //read source byte
    while (inSTATE == 0)
    {
      if(Serial.available() > 0)
      {
        IBUSbyte[1] = Serial.read();  //read length byte
        inSTATE = 1;       
      }

      delay(10);
    }

    inSTATE == 0;
    LENGTH = IBUSbyte[1];
    int i = 2;
    while(i <= LENGTH + 1)
    {
      if(Serial.available() > 0)
      {
        IBUSbyte[i] = Serial.read(); 
        i++;
        delay(10);
      }
    }

    checksumBYTE = 0;
    byteSTATE = 0;
    for (int i = 0; i < LENGTH + 1; i++){
      checksumBYTE ^= IBUSbyte[i];
    } 
    if (IBUSbyte[LENGTH + 1] == checksumBYTE){
      for(int i = 0; i <= LENGTH + 1; i++)
      {
        mySerial.print(IBUSbyte[i], HEX);
        mySerial.print(" ");
      }
      mySerial.println();

    }
    else {
      debug();
      inSTATE = 0;
      byteSTATE = 0;
    }
  } 

}

1 个答案:

答案 0 :(得分:0)

首先,delay很少使用。在这种情况下,您可以使用millis来衡量字符之间的长度,但前提是您丢失了delay

void ReadIBUS()
{ 
  byte IBUSbyte[40];

  do {
    // First, make sure we're between frames, in the quiet interval

    uint32_t last_rx = millis();
    while (millis() - last_rx < 5) {
      // Hasn't been long enough, see if more chars are coming
      if (Serial.available()) {
        Serial.read(); // throw away partial frame chars
        last_rx = millis();
      }
    }

    // Haven't received any chars for a while, we must be
    //   between frames.  Now wait for a frame.

    while (!Serial.available())
      ; // waiting...
    IBUSbyte[0] = Serial.read();  //read source byte

    while (!Serial.available())
      ; // waiting...
    IBUSbyte[1] = Serial.read();  //read length byte

    LENGTH = IBUSbyte[1];

    // Check the LENGTH to make sure it's not bogus.  If it is, try again.
  } while (LENGTH > sizeof(IBUSbyte)-1);

  // LENGTH is reasonable, wait for the payload

  uint8_t bytes_received = 2;
  while (bytes_received <= LENGTH + 1) {
    if (Serial.available()) {
      IBUSbyte[ bytes_received++ ] = Serial.read(); // read frame payload byte
    }
  }

  // All here, verify the checksum

  checksumBYTE = 0;
  for (int i = 0; i < LENGTH + 1; i++) {
    checksumBYTE ^= IBUSbyte[i];
  }

  if (IBUSbyte[LENGTH + 1] == checksumBYTE) {
    for(int i = 0; i <= LENGTH + 1; i++) {
      mySerial.print(IBUSbyte[i], HEX);
      mySerial.print(" ");
    }
    mySerial.println();
  } else {
    debug();
  }
}

不再需要状态变量。

顺便说一句,这个例程“阻止”程序的其余部分做任何事情,直到收到完整的帧。它应该被重写,以便经常调用它(例如来自loop),并且在调用中记住last_rxbytes_received。收到完整的帧后,它可以返回true。这可行,它只是次优,因为它阻止了其他任何事情发生,除了中断。