1

所以几天来,我一直在用头撞键盘,因为我不知道如何让我的新 GPS 盾牌与我的 Teensy 3.1(与 Arduino 兼容)微控制器很好地配合使用。

有问题的 GPS 防护罩是基于 iteaduino 的,可以在这里看到。

我使用 TinyGPS Arduino 库解析来自 Teensy UART 引脚上的 NEO 6 gps 模块的传入数据,并将纬度和经度输出到我在 Arduino IDE 中的串行监视器上没有问题。

当我尝试向 NEO 6 发出 NMEA 命令或 UBX 命令时,就会出现问题。这是实际控制模块的唯一方法,而不是让它每秒发出相同的 6 条 NMEA 消息。(例如,您不能在不发出 UBX RXM-PMREQ 命令的情况下将模块设置为省电模式)。

我首先将我的代码基于ukhas 提供的示例,但无法使其正常工作。所以,我做了一个简单的小程序,基本上做了以下事情:

  1. 以 9600 波特与 NEO 6 模块建立串行通信
  2. 向 GPS 模块发送遵循 UBX 协议的 11 字节数据包,告诉它停止发送 NMEA lat/lon 消息
  3. 解析来自 GPS 模块的传入数据包以搜索 ACK(确认)消息

没有确认消息出现!我究竟做错了什么?!

这是我的代码:

#include <HardwareSerial.h>
#include <string.h>
#include <TinyGPS.h>

void gpsdump(TinyGPS &gps);
void printFloat(double f, int digits = 2);

HardwareSerial2 GPS= HardwareSerial2();  //Initialize harware serial object for the GPS unit
TinyGPS gps;
byte gps_set_sucess = 0 ;

//Pin Definitions
int GPS_RxPin= 9;
int GPS_TxPin=10;

//I/O variables
int GPSbaud = 9600;
int Serialbaud=19200;

int byteCount;


//----------------------------------GPS unit functions------------------------------------------------

// Send a byte array of UBX protocol to the GPS
void sendUBX(uint8_t *MSG, uint32_t len, long timeout=3000) {

  uint32_t CK_A = 0, CK_B = 0;
  uint8_t sum1=0x00, sum2=0x00;
  uint8_t fullPacket[len+4];

  for(int i=0; i<len; i++) {
    fullPacket[i+2]=MSG[i];
  }

  Serial.println();
  fullPacket[0]=0xB5;
  fullPacket[1]= 0x62;

  //Calculate checksum
  for(int i=0; i<len; i++){
    CK_A = CK_A + MSG[i];
    CK_B = CK_B + CK_A;
    Serial.println("CK_A= " + String(CK_A));
    Serial.println("CK_B= " + String(CK_B));
  }

  sum1 = CK_A &0xff;//Mask the checksums to be one byte
  sum2= CK_B &0xff;

  fullPacket[len+2]=sum1; //Add the checksums to the end of the UBX packet
  fullPacket[len+3]=sum2;

  Serial.print("Checksum 1 premask= ");
  Serial.println(CK_A,HEX);
  Serial.print("Checksum 1 postmask= ");
  Serial.println(sum1, HEX);

  Serial.print("Checksum 2 premask= ");
  Serial.println(CK_B,HEX);
  Serial.print("Checksum 2 postmask= ");
  Serial.println(sum2, HEX);

  Serial.println("fullPacket is:");

  for(int i=0; i<(len+4); i++) { 
    Serial.print(fullPacket[i],HEX);//Print out a byt of the UBX data packet to the serial monitor
    Serial.print(", ");
    GPS.write(fullPacket[i]);//Send a byte of the UBX data packet to the GPS unit
  }
  GPS.clear(); 
  Serial.println();
}//end function


// Calculate expected UBX ACK packet and parse UBX response from GPS--------------------------
boolean getUBX_ACK(uint8_t *MSG, uint32_t len) {
  uint8_t b;
  uint8_t ackByteID = 0;
  uint8_t ackPacket[10];
  unsigned long startTime = millis();
  uint32_t CK_A=0, CK_B=0;
  boolean notAcknowledged=false;

 Serial.print(" * Reading ACK response: ");
  // Construct the expected ACK packet    
  ackPacket[0] = 0xB5;  // header
  ackPacket[1] = 0x62;  // header
  ackPacket[2] = 0x05;  // class
  ackPacket[3] = 0x01;  // id
  ackPacket[4] = 0x02;  // length
  ackPacket[5] = 0x00;
  ackPacket[6] = MSG[0];    // MGS class
  ackPacket[7] = MSG[1];    // MSG id
  ackPacket[8] = 0;     // CK_A
  ackPacket[9] = 0;     // CK_B

  // Calculate the checksums
  for (uint8_t i=2; i<8; i++) {
    CK_A = CK_A + ackPacket[i];
    CK_B= CK_B + CK_A;
  }

  ackPacket[8]= CK_A &0xff;//Mask the checksums to be one byte
  ackPacket[9]= CK_B &0xff;

  Serial.println("Searching for UBX ACK response:");
  Serial.print("Target data packet: ");

  for(int i =0; i<10; i++) {
    Serial.print(ackPacket[i], HEX);
    Serial.print(", ");
    }

  Serial.println();
  Serial.print("Candidate   packet: ");

  while (1) {

    // Test for success
    if (ackByteID > 9) {
      // All packets in order!
      Serial.println(" (Response received from GPS unit:)");
      if(notAcknowledged){
        Serial.println("ACK-NAK!");
      }
      else{
        Serial.println("ACK-ACK!");
        return true;
      }
    }

    // Timeout if no valid response in 5 seconds
    if (millis() - startTime > 5000) { 
      Serial.println("<<<Response timed out!>>>");
      return false;
    }

    // Make sure data is available to read
    if (GPS.available()) {
      b = GPS.read();

      // Check that bytes arrive in sequence as per expected ACK packet
      if (b == ackPacket[ackByteID]) { 
        ackByteID++;
        Serial.print(b, HEX);
        Serial.print(", ");
        // Check if message was not acknowledged
        if (ackByteID==3){
          b=GPS.read();
          if (b==0x00){
            notAcknowledged=true;
            ackByteID++;
          }
        }
      } 
      else if(ackByteID>0){
        ackByteID = 0;  // Reset and look again, invalid order
        Serial.print(b,HEX);
        Serial.println(" -->NOPE!");
        Serial.print("Candidate   packet: ");    
      }

    }
  }//end while
}//end function

//--------SETUP------------------

void setup()
{
  boolean gps_get_success=false;

  delay(5000);//Give yourself time to open up the serial monitor  

  pinMode(GPS_TxPin,OUTPUT); //Define the UART transmission pin for ommunication with the GPS unit
  pinMode(GPS_RxPin,INPUT); // Define the UART read pin for communication with the GPS unit

 Serial.begin(Serialbaud);  //Begin serial ommunication with Serial Monitor
 Serial.println("Serial monitor operational");
 GPS.begin(GPSbaud);  //Begin serial communication with GPS unit

 //Compile a UBX data packet to send to GPS - turn off GLL reporting
 uint8_t disableGLL[] = {0x06, 0x01, 0x03, 0x00, 0xF0, 0x01, 0x00};
 uint32_t len= sizeof(disableGLL)/sizeof(uint8_t); 

 Serial.println("Attempting to send UBX command to turn of GLL reporting");
 Serial.println("Original message is " + String(len) + " bytes:");

  for(int i=0; i<len; i++) {
    Serial.print(disableGLL[i]);
    Serial.print(", ");
  }
  Serial.println();

   //Clear the communication buffer
   while ( GPS.available())
    {
      char c = GPS.read();
    }

 sendUBX(disableGLL, len);
 getUBX_ACK(disableGLL, len);


}

//--------MAIN LOOP-------MAIN LOOP-------MAIN LOOP-------MAIN LOOP-------MAIN LOOP-------MAIN LOOP--
void loop()
{
  while ( GPS.available())
    {
      char c = GPS.read();
      if(c==0xb5){Serial.println();}
      Serial.print(c, HEX); // uncomment this line if you want to see the GPS data flowing
      Serial.print(", ");
    }

}//END LOOP-------------------

我不太确定为什么 GPS 模块没有响应我的命令。它开始显得无礼了。这是串行监视器输出:

Serial monitor operational
Attempting to send UBX command to turn of GLL reporting
Original message is 7 bytes:
6, 1, 3, 0, 240, 1, 0, 

CK_A= 6
CK_B= 6
CK_A= 7
CK_B= 13
CK_A= 10
CK_B= 23
CK_A= 10
CK_B= 33
CK_A= 250
CK_B= 283
CK_A= 251
CK_B= 534
CK_A= 251
CK_B= 785
Checksum 1 premask= FB
Checksum 1 postmask= FB
Checksum 2 premask= 311
Checksum 2 postmask= 11
fullPacket is:
B5, 62, 6, 1, 3, 0, F0, 1, 0, FB, 11, 
 * Reading ACK response: Searching for UBX ACK response:
Target data packet: B5, 62, 5, 1, 2, 0, 6, 1, F, 38, 
Candidate   packet: B5, 38 -->NOPE!
Candidate   packet: B5, CC -->NOPE!
Candidate   packet: B5, 38 -->NOPE!
Candidate   packet: <<<Response timed out!>>>

这是通过 UART 传入的原始字节的示例(这些被发送到 arduino 串行监视器)

B5, 38, 35, FC, 10, 40, A1, 59, 3C, 10, 1D, 3C, 30, 11, BD, 19, 90, 18, 10, 48, BD, 51, 39, 1C, 3C, 10, 39, 5D, BC, 91, 91, 59, 3D, B9, B1, B1, 10, D5, 3C, B0, 59, 3D, 3C, 10, 91, 3D, B8, BC, 90, 19, 38, BC, 10, 48, BD, 11, 1D, 1C, 38, 50, 39, 11, 1D, 18, 3C, 11, B9, 1D, 3D, 1, 17, 11, 59, BC, 3C, 10, 5D, 18, B8, 50, 9D, 31, AC, 42, 1D, 5C, 71, 98, B1, 3C, B, 99, 59, 8A, 39, 1, CD, 19, 59, A, BC, 18, 31, 9D, 9D, BC, 31, A5, 86, 94, 32, B1, 0, 85, 25, B1, A5, 1C, 8A, 30, 1, 10, 19, 59, 99, 1D, 38, 31, 63, 84, B, B8, 19, BD, 
4

4 回答 4

1

您的校验和计算有问题。校验和变量被声明为 uint32_t,它们应该被声明为 uint8_t。或者,它们应该在每次添加后被屏蔽,如下所示:

  //Calculate checksum
  for(int i=0; i<len; i++){
    CK_A = CK_A + MSG[i];
    CK_A &= 0xFF;
    CK_B = CK_B + CK_A;
    CK_B &= 0xFF;
    Serial.println("CK_A= " + String(CK_A));
    Serial.println("CK_B= " + String(CK_B));
  }
于 2015-07-23T10:27:19.660 回答
0

我可以告诉你 disableGLL 数据包格式正确。我正在发送那个确切的数据包,并且我收到了您预期的 ACK 数据包。

因为您可以正常接收 NMEA 消息,我们可以排除 RS232 设置问题(波特率等)。

我建议不要Serial.print将语句与GPS.print和语句交织在一起GPS.read。如果大量字符已排队等待输出,则调用Serial.print将阻塞,直到有更多字符空间。在Serial.print等待期间,字符仍然从 GPS 模块进来。最终,您的输入缓冲区将溢出。到时间Serial.print回来时,您可能已经丢失了一些要阅读的字符。

从来自 Arduino 串行监视器的字节来看,似乎已经删除了 8 个字节。请注意,预期的 0x38 在初始 0xB5 之后是 8 个字节。

试试这个: 在sendUBX中,将最后一个for循环分成两个循环:

Serial.println("fullPacket is:");

for(int i=0; i<(len+4); i++) { 
  Serial.print(fullPacket[i],HEX);//Print out a byt of the UBX data packet to the serial monitor
  Serial.print(", ");
}
Serial.println();
Serial.flush();  // and wait until all debug messages have been sent

for(int i=0; i<(len+4); i++) { 
  GPS.write(fullPacket[i]);//Send a byte of the UBX data packet to the GPS unit
}
GPS.flush(); // wait until the packet has been sent

然后注释掉Serial.print. getUBX_ACK您可能可以在以下位置留下一个Serial.print

  // Check that bytes arrive in sequence as per expected ACK packet
  if (b == ackPacket[ackByteID]) { 
    ackByteID++;
    Serial.print(b);  //  just output the bad byte
//    Serial.print(b, HEX);
//    Serial.print(", ");
    // Check if message was not acknowledged

然后你就会知道你是否真的在 0xB5 之后得到了 0x38。当然,逻辑分析仪、串行嗅探器甚至示波器都可以告诉您线路上的实际情况。

调试语句改变程序的时间并不少见,也许足以以意想不到的方式破坏它。在这种情况下,输入缓冲区溢出并丢弃字符。

于 2014-10-02T02:23:26.063 回答
0

我对该代码有同样的问题。我使用了 Habduino 代码,它与 MAX8 GPS 模块有点相同。必须检查 Ublox NEO-6M 的所有命令,似乎是一样的。但是和你一样的问题。

我通过打开uCenter解决了它。与消息视图 (F9) 相比,禁用所有 NMEA 和 UBX(子)消息。我的默认启用了 UBX-POSLLH 消息。通过选择 UBX-CFG-CFG 而不是“发送”,将设置保存在 UBX-CFG-CFG 下。

我不知道“HardwareSerial”库;我将我的 GPS 连接到 Arduino(引脚 0 和 1)的硬件 UART 上。这意味着没有要监控的序列号,但因此我使用了这个非常有用的技巧: http ://ava.upuaut.net/?p=757

如果有人知道如何禁用来自 NEO-6M 的 UBX 消息,请告诉我。文档对我来说并不清楚。谢谢!

于 2015-04-28T10:06:33.500 回答
0

@Justin,CS计算没有问题。请检查他提供的数据包,因为它们格式正确。

使用 32 位 CS 变量可能很浪费,但它不会生成不正确的校验和。在两种情况下(发送和接收),他都会在计算结束时屏蔽它们。

我已经用相同的 ublox Neo-6M 设备验证了这一点。我是(当前)最快和最小的 NMEA+UBX 解析器NeoGPS的作者。

于 2015-09-20T19:23:02.827 回答