0

I am on a project,in which I need to store the output of GPS from SKG 13BL to a database using Arduino UNO and GSM module.I wrote the following code

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

SoftwareSerial 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];

enum _parseState {
  PS_DETECT_MSG_TYPE,

  PS_IGNORING_COMMAND_ECHO,

  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;

byte parseState = PS_DETECT_MSG_TYPE;
char buffer[80],url[80];
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("GPS LOADING....."));
  Serial.println(F("Testing by : "));
  Serial.println(F("Billa"));
  Serial.println();

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

void loop()
{ 
  unsigned long now = millis();

  while (gps.available( gpsPort )) {
    fix = gps.read();

    // Once every 5 seconds...    
    if (++fixCount >= 5) {
      displayInfo();
      fixCount = 0;
    }
  }

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

  if ( actionState == AS_IDLE ) {
    if ( now > lastActionTime + 5000 ) {
      sprintf(url, "AT+HTTPPARA=\"URL\",\"http://*****.000webhostapp.com/hinderset.php?date=%s\"", dt); // passing date only now as part of testing
      sendGSM(url);
      sendGSM("AT+HTTPACTION=0");
      lastActionTime = now;
      actionState = AS_WAITING_FOR_RESPONSE;
    }
  }

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

void displayInfo()
{
  Serial.print(F("Location: ")); 
  if (fix.valid.location) {
    Serial.print( fix.latitude(), 5 );
    Serial.print( ',' );
    Serial.print( fix.longitude(), 5 );
  } else {
    Serial.print(F("INVALID"));
  }

  Serial.print(F("  Speed: ")); 
  if (fix.valid.speed) {
    Serial.print(fix.speed_kph());
    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);
  } 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_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;
  }
}

When I tested them in separate modules they worked and obtained result But now When I wrote the above code it is showing me "NO GPS DETECTED".Can you please help me in resolving the problem.The objective is I need to obtain the output from GPS at every 5 secs (5 secs interval between each output) and store them into database using GSM module

1

There are three problems:

1) You are using delay.

2) You are still using SoftwareSerial. It blocks interrupts for long periods of time, interfering with other parts of your sketch. I told you this in your previous post.

3) Starting the HTTP action is not synchronized with the GPS clock. The Arduino millis() clock is not synchronized with the GPS atomic clock. They will drift in and out of sync over time. I also told you this in the same previous post.

The solution:

1) Don't use delay. The GPS device continues to send characters, and they get dropped when the Arduino is blocked at the delay.

Instead, just send the command and let your nice parseATTText handle the response as it comes in, without waiting. If there are multiple commands to send, add an extra state for each command. When a response for the first command arrives, send the second command and step to the next state.

You can use delay in setup if you don't care about the responses to those initial commands. Or you could add one SETUP_xxx state for each command to your FSM and let them happen in loop. parseATTText will advance through those STARTUP states, sending each of those commands.

2) Use NeoSWSerial.

3) Move the HTTPPARA command into the GPS loop with displayInfo:

  while (gps.available( gpsPort )) {
    fix = gps.read();

    // Once every 5 seconds...    
    if (++fixCount >= 5) {
      displayInfo();

      // Send the next report if the previous one is finished
      if ( actionState == AS_IDLE ) {
        sprintf(url, "AT+HTTPPARA=\"URL\",\"http://*****.000webhostapp.com/hinderset.php?date=%s\"", dt); // passing date only now as part of testing
        sendGSM(url);
        parseState = PS_HTTPPARA_RESPONSE; // a new state
        actionState = AS_WAITING_FOR_RESPONSE;
      }

      fixCount = 0;
    }
  }

You should move sendGSM("AT+HTTPACTION=0") into parseATTText as a case PS_HTTPPARA_RESPONSE, and step to the next state (PS_DETECT_MSG_TYPE?)

If you reset fixCount inside the if (actionState == IDLE) block, it will send a new location when the previous one finally completes, perhaps after 6 new fixes.

Resetting fixCount outside the block (as above) means it may send the 5th location, skip the 10th because it's NOT IDLE, and then send the 15th location. If you want it to send the 5th, then the 11th if it's not busy, reset fixCount inside the if block.

  • it works fine.ty – Billa Apr 15 '17 at 17:33
  • I want to store the value of latitude and longitude onto a variable how can i do that.( here it just prints Serial.print( fix.latitude(), 5 ); Serial.print( ',' ); Serial.print( fix.longitude(), 5 ); ) . I also want to store the speed to a variable how can i do that. when i used sprintf() it failed. – Billa Apr 15 '17 at 17:35
  • lat, lon and speed are inside the fix structure -- they are already variables. A structure is just a "group" of variables. In this case, fix.latitude() is a very simple function that returns the fix.location._lat variable as a float value. Same with speed: fix.speed_kph() is a simple function that returns the fix.spd... variable's value, converted from knots to kph. You can use fix (and its member variables) wherever you want, because it is a global, and it is always up-to-date. – slash-dev Apr 16 '17 at 2:01
  • If you really want a separate copy of the pieces inside fix, you can declare a second structure: gps_fix oldFix; and copy the current fix into it at some point: oldFix = fix; // save a snapshot. – slash-dev Apr 16 '17 at 2:03
  • I use latitude and longitude for reverse geo and in this i require a precise value i.e about 4 decimal numbers ( like 9.7451 ) .when i use Serial.print(fix.latitude); it shows 9.74 .how can i get precise value. – Billa Apr 16 '17 at 3:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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