1
#include <NeoSWSerial.h>

//#include <SoftwareSerial.h>
#include <AltSoftSerial.h>
#include <NMEAGPS.h>

NeoSWSerial GSM(2, 3); // RX, TX: Connect TXD to RX & RXD to TX

static const int RXPin = 8, TXPin = 9;
AltSoftSerial gpsPort(RXPin, TXPin);
static const uint32_t GPSBaud = 9600;

NMEAGPS gps;
gps_fix fix;
uint8_t fixCount = 0;
char dt[15],tm[15];
float lati,longi;
//int block = 0;

enum _parseState {
  PS_DETECT_MSG_TYPE,

  PS_IGNORING_COMMAND_ECHO,

  PS_HTTPPARA_RESPONSE,

  PS_HTTPACTION_TYPE,
  PS_HTTPACTION_RESULT,
  PS_HTTPACTION_LENGTH,

  PS_HTTPREAD_LENGTH,
  PS_HTTPREAD_CONTENT
};

enum _actionState {
  AS_IDLE,
  AS_WAITING_FOR_RESPONSE
};

byte actionState = AS_IDLE;
unsigned long lastActionTime = 0;

float s;

byte parseState = PS_DETECT_MSG_TYPE;
char buffer[160],url[160];
byte pos = 0;

int contentLength = 0;

void resetBuffer() {
  memset(buffer, 0, sizeof(buffer));
  pos = 0;
}

void sendGSM(const char* msg, int waitMs = 500) {
  GSM.println(msg);
  while(GSM.available()) {
    parseATText(GSM.read());
  }
  //delay(waitMs);
}

void setup()
{
  GSM.begin(9600);
  Serial.begin(9600);
  gpsPort.begin(GPSBaud);

  Serial.println(F("Hinder LOADING....."));
  Serial.println(F("obtain gps and store data to database"));
  Serial.println(F("Testing by : "));
  Serial.println(F("Nikhil,Muthumani and Mathews"));
  Serial.println();

  sendGSM("AT+SAPBR=3,1,\"APN\",\"vodafone\"");  
  delay(500);
  sendGSM("AT+SAPBR=1,1",3000);
  delay(500);
  sendGSM("AT+HTTPINIT"); 
  delay(500); 
  sendGSM("AT+HTTPPARA=\"CID\",1");
  delay(500);
}

void loop()
{ 
  unsigned long now = millis();
  while (gps.available( gpsPort )) {
    fix = gps.read();
     //Serial.println(F("b"));
    // Once every 5 seconds...    
    if (++fixCount >= 5) {
       //Serial.println(F("a"));
      displayInfo();

      //send the next report if previous one is finished
      if ( actionState == AS_IDLE ) {
      sprintf(url, "AT+HTTPPARA=\"URL\",\"http://**************/***.php?lat=%d&lng=%d&speed=%d&date=%s&time=%s\"",lati,longi,s,dt,tm );
      sendGSM(url);
     // lastActionTime = now;
      parseState = PS_HTTPPARA_RESPONSE; // a new state
      actionState = AS_WAITING_FOR_RESPONSE;
      fixCount = 0;
    }

    }
  }

/*  if ((gps.statistics.chars < 10) && (millis() > 5000)) {
     Serial.println( F("No GPS detected: check wiring.") );
     while(true);
     block=1;
    }*/

  while(GSM.available()) {
    //lastActionTime = now;
    parseATText(GSM.read());
  }
 }


void displayInfo()
{
  Serial.print(F("Location: ")); 
  if (fix.valid.location) {
    lati=( fix.latitude());
    //sprintf(lati,"%d",fix.latitude(),5);
    Serial.print(lati);
    Serial.print( ',' );
    longi= ( fix.longitude());
    //sprintf(longi,"%d",fix.longitude(),5);
    Serial.print(longi);
  } else {
    Serial.print(F("INVALID"));
  }

  Serial.print(F("  Speed: ")); 
  if (fix.valid.speed) {
    s=fix.speed_kph();
    Serial.print(s);
    Serial.print(F(" KMPH "));
  } else {
    Serial.print(F("INVALID"));
  }

  // Shift the date/time to local time
  NeoGPS::clock_t localSeconds;
  NeoGPS::time_t  localTime;
  if (fix.valid.date && fix.valid.time) {
    using namespace NeoGPS; // save a little typing below...

    localSeconds = (clock_t) fix.dateTime; // convert structure to a second count
    localSeconds += 5 * SECONDS_PER_HOUR + 30 * SECONDS_PER_MINUTE; // shift timezone
    localTime = localSeconds;              // convert back to a structure
  }

  Serial.print(F("  Date : "));
  if (fix.valid.date) {
    sprintf(dt,"%02d/%02d/20%d",fix.dateTime.date,fix.dateTime.month,fix.dateTime.year);
    Serial.print(dt);
  } else {
    Serial.print(F("INVALID"));
  }

  Serial.print(F("  Time : "));
  if (fix.valid.time) {
    if (localTime.hours>12)localTime.hours-=12;//To convert 24 hr format to 12 hr format
    sprintf(tm,"%02d:%02d:%02d",localTime.hours,localTime.minutes,localTime.seconds);
    Serial.print(tm);
    //block=1;
  } else {
    Serial.print(F("INVALID"));
  }

  Serial.println();
}

void parseATText(byte b) {

  buffer[pos++] = b;

  if ( pos >= sizeof(buffer) )
    resetBuffer(); // just to be safe

  /*
   // Detailed debugging
   Serial.println();
   Serial.print("state = ");
   Serial.println(state);
   Serial.print("b = ");
   Serial.println(b);
   Serial.print("pos = ");
   Serial.println(pos);
   Serial.print("buffer = ");
   Serial.println(buffer);*/

  switch (parseState) {

  case PS_HTTPPARA_RESPONSE:
    {
      parseState = PS_DETECT_MSG_TYPE;
      sendGSM("AT+HTTPACTION=0");
     /*  while(GSM.available()) {
    //lastActionTime = now;
    parseATText(GSM.read());
  }*/

    }
    break;

  case PS_DETECT_MSG_TYPE: 
    {
      if ( b == '\n' )
        resetBuffer();
      else {        
        if ( pos == 3 && strcmp(buffer, "AT+") == 0 ) {
          parseState = PS_IGNORING_COMMAND_ECHO;
        }
        else if ( b == ':' ) {
          //Serial.print("Checking message type: ");
          //Serial.println(buffer);

          if ( strcmp(buffer, "+HTTPACTION:") == 0 ) {
            Serial.println("Received HTTPACTION");
            parseState = PS_HTTPACTION_TYPE;
          }
          else if ( strcmp(buffer, "+HTTPREAD:") == 0 ) {
            Serial.println("Received HTTPREAD");            
            parseState = PS_HTTPREAD_LENGTH;
          }
          resetBuffer();
        }
      }
    }
    break;

  case PS_IGNORING_COMMAND_ECHO:
    {
      if ( b == '\n' ) {
        Serial.print("Ignoring echo: ");
        Serial.println(buffer);
        parseState = PS_DETECT_MSG_TYPE;
        resetBuffer();
      }
    }
    break;

  case PS_HTTPACTION_TYPE:
    {
      if ( b == ',' ) {
        Serial.print("HTTPACTION type is ");
        Serial.println(buffer);
        parseState = PS_HTTPACTION_RESULT;
        resetBuffer();
      }
    }
    break;

  case PS_HTTPACTION_RESULT:
    {
      if ( b == ',' ) {
        Serial.print("HTTPACTION result is ");
        Serial.println(buffer);
        parseState = PS_HTTPACTION_LENGTH;
        resetBuffer();
      }
    }
    break;

  case PS_HTTPACTION_LENGTH:
    {
      if ( b == '\n' ) {
        Serial.print("HTTPACTION length is ");
        Serial.println(buffer);

        // now request content
        GSM.print("AT+HTTPREAD=0,");
        GSM.println(buffer);

        parseState = PS_DETECT_MSG_TYPE;
        resetBuffer();
      }
    }
    break;

  case PS_HTTPREAD_LENGTH:
    {
      if ( b == '\n' ) {
        contentLength = atoi(buffer);
        Serial.print("HTTPREAD length is ");
        Serial.println(contentLength);

        Serial.print("HTTPREAD content: ");

        parseState = PS_HTTPREAD_CONTENT;
        resetBuffer();
      }
    }
    break;

  case PS_HTTPREAD_CONTENT:
    {
      // for this demo I'm just showing the content bytes in the serial monitor
      Serial.write(b);

      contentLength--;

      if ( contentLength <= 0 ) {

        // all content bytes have now been read

        parseState = PS_DETECT_MSG_TYPE;
        resetBuffer();

        Serial.print("\n\n\n");

        actionState = AS_IDLE;
      }
    }
    break;
  }
}

in this I try obtain the GPS latitude and longitude at every 5 secs and and use that values to find the name of the location.I need to pass the value of latitude and longitude over the URL to the php code and there it is converted to the location name.I also need to pass the speed,date and time (speed and date works fine). When i try to sent them the command displayed on the window is Ignoring echo: AT+HTTPPARA="URL","http://[link]/hinder.p‌​hp?lat=?&lng=?&speed‌​=?&date=&time=1‌​6/04/2017" here you can see instead of value of latitude,speed and longitude a question mark appears.So i tried

sprintf(url, "AT+HTTPPARA=\"URL\",\"http://masp203.000webhostapp.com/hind‌​er.php?lat=%f&lng=%f‌​&speed=%d&date=%s&ti‌​me=%s\"",fix.latitud‌​e(),fix.longitude(),‌​fix.speed_kph(),dt,t‌​m ); sendGSM(url);

but that too didnt worked.I need a presice value of latitude and longitude (about 5 decimal points) since it is used to find the location.Can any one tell me hoe can i do that .

4 Answers 4

1

Floating point values aren't precise.

However you problem has nothing to do with precision, but purely how you are representing the value as text. You are asking for the format %f which, by default on Arduino, is not supported by sprintf.

Instead you have to use the function dtostrf() (a non-standard libavr specific function).

char floatval[10]; // Room for 9 characters + NULL
float myVal = 48.53927853;

dtostrf(myVal, 9, 5, floatval);

Selection of the right numbers is critical. The first is the total space you have available in the target character array (not including the required NULL, so one less than the size of the array). The second is the number of decimal places to render. So you have to make sure you have enough room for the integer portion, any sign (if it's negative) and the decimal point, plus the number of decimal places you want to render - in this case:

  • 1 - Sign
  • 2 - Integer
  • 1 - Decimal point
  • 5 - Decimal portion

Total: 1+2+1+5 = 9.

The first value, width, can also be given as a negative value, in which case left alignment of the content will be performed.

3
  • how can i make use of dtostrf() function in my url (sprintf(url, "AT+HTTPPARA=\"URL\",\"http://masp203.000webhostapp.com/hind‌​er.php?lat=%f&lng=%f‌​&speed=%d&date=%s&ti‌​me=%s\"",fix.latitud‌​e(),fix.longitude(),‌​fix.speed_kph(),dt,t‌​m ); sendGSM(url);.Can u explain it with my example Commented Apr 16, 2017 at 16:14
  • You could use format %s to insert the string, or you could not use sprintf() at all and build it up piecemeal using strcat(), etc.
    – Majenko
    Commented Apr 16, 2017 at 16:16
  • it works fine!! Commented Apr 16, 2017 at 17:28
1

If you aren't going to be computing with the GPS coordinates, I'd suggest keeping the character strings just as they were delivered by the device. You'll keep all of the precision available without introducing any quantization or roundoff errors.

0

how to get precise value from float variable?

possible solutions:

1) don't use float where precise values are needed - by far the best solution;

2) use fixed point types;

3) use integer types;

...

0

I need a precise value of latitude and longitude (about 5 decimal points) since it is used to find the location. Can any one tell me how can I do that.

If you only need 5 decimal points, you can continue to use float values. If you would like more precision, you can use the 32-bit integer forms of lat/lon provided by NeoGPS.

For float values, you can do as Majenko suggested. Just like the date and time arrays, you format that floating-point lat and lon values into their own character arrays. Then put them in the url array with sprintf and "%s", just like the dt and tm arrays.

To get the extra digits of precision, you have to use the fix.latitudeL() and fix.longitudeL() functions. They return integers that have 10 significant digits. They are scaled by 10000000, so you have to insert the decimal point at the right place. The example program NMEAloc.ino shows how to print those integers as if they were floating-point values.

Since you are using sprintf, you could format latitude like this:

char lat[16];
int deg = fix.latitudeL() / 10000000L; // possibly negative
int decimals = abs( fix.latitude() - deg * 10000000L );
sprintf( lat, "%d.%07d", deg, decimals );

Then format this into the url array with %s:

sprintf( url, " ... &lat=%s&...", ... , lat, ... );

That gives you 7 decimals, like 9.7451145

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.