GPS modul Ublox Neo-6m a Arduino

K mému Arduinu jsem si sehnal GPS modul Ublox Neo-6M. Bohužel, s knihovnou TinyGPS ani TinyGPSPlus si nerozumí (knihovna nedokáže dekódovat data z modulu). Proto jsem si napsal vlastní obslužný kód, který zobrazuje všechny dostupné informace.

Zeměpisná šířka a délka přicházejí ve formátu „DDMM.MMMMM“. Parsování provádím tak, že načtu část před desetinnou tečkou. Stupně získám celočíselným dělením DDMM / 100. Minuty jsou zbytek po celočíselném dělení DDMM % 100. K celým minutám přičtu část za desetinnou tečkou převedenou na „0.MMMMM“ (MMMMM / 100000).

Pro převod stupňového formátu do decimálního slouží vzorec DEC = DEGREE + MINUTES / 60 + SECONDS / 3600. Minuty máme v desetinném tvaru, takže je stačí vydělit 60 a přičíst ke stupňům.

Protože funkce Serial.print() zobrazuje pouze 2 desetinná místa, rozhodl jsem se výsledek vynásobit 1000. Pokud se zobrazí číslo 49163.69, víme, že se ve skutečnosti jedná o 49.16369.

#include "SoftwareSerial.h"

#define GPS_RX_PIN 7
#define GPS_TX_PIN 6

#define BUFFSIZ 90

char buffer[BUFFSIZ];
char buffidx;
char *parseptr;
uint32_t latitude, longitude;

SoftwareSerial gpsSerial(GPS_RX_PIN, GPS_TX_PIN);

void setup()  {
  Serial.begin(9600);
  gpsSerial.begin(9600);
}

void loop() {
  uint32_t tmp;
  
  if (gpsSerial.available() > 0) {
    readline();
    if (strncmp(buffer, "$GPRMC", 6) == 0) {
  
      // Time
      parseptr = buffer + 7;
      tmp = parsedecimal(parseptr);
      Serial.print(tmp / 10000);
      Serial.print(":");
      Serial.print((tmp / 100) % 100);
      Serial.print(":");
      Serial.print(tmp % 100);

      // Status
      parseptr = strchr(parseptr, ',') + 1;
      Serial.print(" ");
      Serial.print(parseptr[0]);
      Serial.print(" ");
      
      // Latitude
      parseptr += 2;
      latitude = parsedecimal(parseptr);
      if (latitude != 0) {
        parseptr = strchr(parseptr, '.') + 1;
        Serial.print(((latitude / 100) + (((latitude % 100) + (parsedecimal(parseptr) / 100000.0)) / 60.0)) * 1000);
      }
      parseptr = strchr(parseptr, ',') + 1;
      if (parseptr[0] != ',') {
        // Serial.print(parseptr[0]);
      }
      Serial.print("x10^3 ");
      
      // Longitude
      parseptr = strchr(parseptr, ',') + 1;
      longitude = parsedecimal(parseptr);
      if (longitude != 0) {
        parseptr = strchr(parseptr, '.') + 1;
        Serial.print(((longitude / 100) + (((longitude % 100) + (parsedecimal(parseptr) / 100000.0)) / 60.0)) * 1000);
      }
      parseptr = strchr(parseptr, ',') + 1;
      if (parseptr[0] != ',') {
        // Serial.print(parseptr[0]);
      }
      Serial.print("x10^3 ");
      
      // Groundspeed
      parseptr = strchr(parseptr, ',') + 1;
      Serial.print(parsedecimal(parseptr));
      Serial.print(" ");
  
      // Track angle
      parseptr = strchr(parseptr, ',') + 1;
      Serial.print(parsedecimal(parseptr));
      Serial.print(" ");
      
      // Date
      parseptr = strchr(parseptr, ',') + 1;
      tmp = parsedecimal(parseptr); 
      Serial.print(tmp / 10000);
      Serial.print("/");
      Serial.print((tmp / 100) % 100);
      Serial.print("/");
      Serial.print(tmp % 100);
      
      Serial.println();
    } else {
      // Serial.println("waiting...");
    }
  } else {
    Serial.println("unavaliable");
  }
}

uint32_t parsedecimal(char *str) {
  uint32_t d = 0;
  
  while (str[0] != 0) {
   if ((str[0] > '9') || (str[0] < '0')) {
     return d;
   }

   d *= 10;
   d += str[0] - '0';
   str++;
  }

  return d;
}

void readline(void) {
  char c;
  buffidx = 0;

  while (1) {
      c = gpsSerial.read();
      if (c == -1) {
        continue;
      }

      if (c == '\n') {
        continue;
      }

      if ((buffidx == BUFFSIZ-1) || (c == '\r')) {
        buffer[buffidx] = 0;
        return;
      }

      buffer[buffidx++]= c;
  }
}

Inspirace na webu http://forum.arduino.cc/.