0

I am getting multiple messages from a GPS device at different frequencies. After getting strings I have to save this data on the SD card. It works well when we have the same frequencies messages but if the frequencies are not same the saved data gets some blank spaces. I am using the split strings method.

    CR1A = String1.indexOf(13);  //finds location of first
    String1A = String1.substring(0, CR1A + 2 );   //captures first data String
    CR1B = String1.indexOf(13, CR1A + 2 ); //finds location of second ,
    String1B = String1.substring(CR1A , CR1B + 2 ); //captures second data String
    CR1C = String1.indexOf(13, CR1B + 2 );
    String1C = String1.substring(CR1B , CR1C + 2 );
    CR1D = String1.indexOf(13, CR1C + 2 );
    String1D = String1.substring(CR1C , CR1D + 2 );
    CR1E = String1.indexOf(13, CR1D + 2 );
    String1E = String1.substring(CR1D , CR1E + 2 );
    CR1F = String1.indexOf(13, CR1E + 2 );
    String1F = String1.substring(CR1E , CR1F + 2 );

    strID = (String1A.substring(0, 2));
    if (strID == "$G") {
      File dataFile = SD.open("GPS1.txt", FILE_WRITE);
      // if the file is available, write to it:

      strID = (String1A.substring(0, 5));
      if (strID == "$GPGG") {
        dataFile.print(dt);
        dataFile.print(" ");
        dataFile.print(tm);
        dataFile.print(msec);
        dataFile.print(",");
        dataFile.print(String1A);
        String1A = "";
      }

      strID = (String1D.substring(4, 6));
      if (strID == "TG" || "DA" || "LL" || "NS" || "RS") {
        dataFile.print(String1B);
        String1B = "";
      }
      strID = (String1C.substring(4, 6));
      if (strID == "TG" || "DA" || "LL" || "NS" || "RS") {
        dataFile.print(String1C);
        String1C = "";
      }
      strID = (String1D.substring(4, 6));
      if (strID == "TG" || "DA" || "LL" || "NS" || "RS") {
        dataFile.print(String1D);
        String1D = "";
      }
      strID = (String1E.substring(4, 6));
      if (strID == "TG" || "DA" || "LL" || "NS" || "RS") {
        dataFile.print(String1E);
        String1E = "";
      }
      strID = (String1F.substring(4, 6));
      if (strID == "TG" || "DA" || "LL" || "NS" || "RS") {
        dataFile.print(String1F);
        String1F = "";
      }
      dataFile.close();
    }

EDIT:

This is the code now I am using. I have turned off all the commands which extract strings from my available data received at the serial port. I am just using an interrupt timer for it.. and it is working perfectly. But I didn't like this simple method and I don't know it's a good way to get strings like this or not as I am not a good programmer.

#include <TimerOne.h>
#define RxTimeOut 5

/*
  ** MEGA MINI **
  ** MOSI - pin 51
  ** MISO - pin 50
  ** CLK - pin 52
  ** CS - pin 53 (for MKRZero SD: SDCARD_SS_PIN)
  ** SDA - pin 20
  ** SCL - pin 21
*/
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <EEPROM.h>
#include "math.h"
#include <SPI.h>
#include <SD.h>
#include "RTClib.h"
#define DS1307_CTRL_ID 0x68
unsigned long int ticks = 0;
RTC_DS1307 rtc;
bool flag = false;
String GPSmessage = "";
const int chipSelect = 53;
String dataString = "";
//String dataString1 = "";
//String dataString2 = "";
//String dataString3 = "";
bool stringComplete = false;
bool string1Complete = false;
bool string2Complete = false;
bool string3Complete = false;
String strID = "";

unsigned long msec;
const long interval = 500;



#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32


Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

unsigned long CurrentBaudRate = 9600;

unsigned long x = 0;

int Up = 3;
int Dn = 4;
int Mnu = 5;


String String1;
String inputString1 = "";         // a String to hold incoming data
boolean NewDataFlag1 = 0;
unsigned int Serial1TimeOut = 0;

String String2;
String inputString2 = "";         // a String to hold incoming data
boolean NewDataFlag2 = 0;
unsigned int Serial2TimeOut = 0;

String String3;
String inputString3 = "";         // a String to hold incoming data
boolean NewDataFlag3 = 0;
unsigned int Serial3TimeOut = 0;

void timerIsr()
{
  serial1Event();
  serial2Event();
  serial3Event();


  if (Serial1TimeOut > 0)Serial1TimeOut--;
  if (Serial1TimeOut == 0 && NewDataFlag1 == 1)
  {
    String1 = inputString1;
    inputString1 = "";
    NewDataFlag1 = 0;
  }

  if (Serial2TimeOut > 0)Serial2TimeOut--;
  if (Serial2TimeOut == 0 && NewDataFlag2 == 1)
  {
    String2 = inputString2;
    inputString2 = "";
    NewDataFlag2 = 0;
  }

  if (Serial3TimeOut > 0)Serial3TimeOut--;
  if (Serial3TimeOut == 0 && NewDataFlag3 == 1)
  {
    String3 = inputString3;
    inputString3 = "";
    NewDataFlag3 = 0;
  }

}


void setup() {

  Timer1.initialize(5000); // Timer event time
  Timer1.attachInterrupt( timerIsr );

  Serial.println("Sonay di nathli");


  //========================================= SD Card =======================================================//
  //  Serial.println("Initializing SD card...");

  // see if the card is not present:
  if (!SD.begin(chipSelect)) {
    //    Serial.println("Card failed, or not present");
    //     don't do anything more:
    return;
  }
  //  Serial.println("SD card Ready");

  //====================================================== RTC =============================================//
  if (!rtc.begin())
  {
    //    Serial.println("Couldn't find RTC");
    Serial.flush();
    abort();
  }

  if (!rtc.isrunning()) {
    //    Serial.println("RTC is NOT running, let's set the time!");
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }

  //================================================ OLED Baudrate selection ====================================================//
  pinMode(Up, INPUT_PULLUP);
  pinMode(Dn, INPUT_PULLUP);
  pinMode(Mnu, INPUT_PULLUP);

  unsigned char bdindx = EEPROM.read(0);
  if (bdindx > 3) bdindx = 0;
  if (bdindx == 0) CurrentBaudRate = 4800;
  if (bdindx == 1) CurrentBaudRate = 9600;
  if (bdindx == 2) CurrentBaudRate = 19200;
  if (bdindx == 3) CurrentBaudRate = 115200;
  delay (500);

  while (!Serial) { }// wait for serial port to connect
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(CurrentBaudRate);
  Serial1.begin(CurrentBaudRate);
  Serial2.begin(CurrentBaudRate);
  Serial3.begin(CurrentBaudRate);
  Serial.println(CurrentBaudRate);
  delay (1000);

  display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS);
  display.clearDisplay();
  display.setTextSize(1);             // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE);        // Draw white text
  display.display();

}

String String1A, String1B, String1C, String1D, String1E, String1F;
String String2A, String2B, String2C, String2D, String2E, String2F;
String String3A, String3B, String3C, String3D, String3E, String3F;
int CR1A, CR1B, CR1C, CR1D, CR1E, CR1F;
int CR2A, CR2B, CR2C, CR2D, CR2E, CR2F;
int CR3A, CR3B, CR3C, CR3D, CR3E, CR3F;


// ============================================ Showing baud rate on screen (position) ===========================================//

void DrawBaudRate(unsigned long BdRt)
{
  unsigned char Xoffset = 0;
  if (BdRt >= 0 && BdRt < 10000) Xoffset = 37;
  if (BdRt >= 10000 && BdRt < 100000) Xoffset = 30;
  if (BdRt >= 100000 ) Xoffset = 25;
  //  display.drawRect(0,0,128,64,SSD1306_WHITE);
  //  display.setTextSize(2);
  //  display.setCursor(15,10);
  //  display.println("Baudrate");
  //  display.setTextSize(2);
  //  display.setCursor(15,10);
  //  display.println(tm);
  //  display.setCursor(Xoffset,37);// 6 digit
  //  display.println(BdRt);
  //  display.display();
  //  delay(10);
}

// ================================================== Selection of Baud Rate ========================================================//
unsigned long SelectBaudRate(unsigned long BdRt)
{
  unsigned char BdRtIndx = 0;
  unsigned int FlashCnt = 0;

  if (BdRt == 4800) BdRtIndx = 0;
  if (BdRt == 9600) BdRtIndx = 1;
  if (BdRt == 19200) BdRtIndx = 2;
  if (BdRt == 115200) BdRtIndx = 3;

  unsigned char Xoffset = 0;
  if (BdRt >= 0 && BdRt < 10000) Xoffset = 37;
  if (BdRt >= 10000 && BdRt < 100000) Xoffset = 30;
  if (BdRt >= 100000 ) Xoffset = 25;
  display.drawRect(0, 0, 128, 64, SSD1306_WHITE);
  display.setTextSize(1);
  display.setCursor(15, 10); display.println("Select Baudrate");
  display.setCursor(15, 20); display.println("by Up/Dn Buttons");
  display.setTextSize(2);
  display.setCursor(Xoffset, 37); // 6 digit
  display.println(BdRt);
  display.display();
  delay(10);

  while (digitalRead(Mnu) == 0) delay(10);
  delay(100);


  while (digitalRead(Mnu) == 1)
  {
    delay(10);
    FlashCnt++;

    if (digitalRead(Up) == 0)
    {
      if (BdRtIndx < 3) BdRtIndx++;
    }


    if (digitalRead(Dn) == 0)
    {
      if (BdRtIndx > 0) BdRtIndx--;
    }

    if (BdRtIndx == 0) BdRt = 4800;
    if (BdRtIndx == 1) BdRt = 9600;
    if (BdRtIndx == 2) BdRt = 19200;
    if (BdRtIndx == 3) BdRt = 115200;

    if (BdRt >= 0 && BdRt < 10000) Xoffset = 37;
    if (BdRt >= 10000 && BdRt < 100000) Xoffset = 30;
    if (BdRt >= 100000 ) Xoffset = 25;
    display.clearDisplay();
    display.drawRect(0, 0, 128, 64, SSD1306_WHITE);
    display.setTextSize(1);
    display.setCursor(15, 10); display.println("Select Baudrate");
    display.setCursor(15, 20); display.println("by Up/Dn Buttons");
    display.setTextSize(2);
    display.setCursor(Xoffset, 37); // 6 digit
    if (FlashCnt > 1) display.println(BdRt);
    if (FlashCnt > 2) FlashCnt = 0;
    display.display();
    delay(250);

    //while(digitalRead(Up)==0 || digitalRead(Dn)==0) delay(10);
  }
  while (digitalRead(Mnu) == 0) delay(10);

  display.clearDisplay();
  display.drawRect(0, 0, 128, 64, SSD1306_WHITE);
  display.setTextSize(2);
  display.setCursor(20, 10); display.println("Saving");
  display.setCursor(20, 35); display.println("Changes");
  display.display();
  delay(2000);

  EEPROM.write(0, BdRtIndx);


  return (BdRt);


}

//=================================================== OLED showing time ===============================================//
char Time[]     = "  :  :  ";
byte i, second, minute, hour;

void DS3231_display() {
  // Convert BCD to decimal
  second = (second >> 4) * 10 + (second & 0x0F);
  minute = (minute >> 4) * 10 + (minute & 0x0F);
  hour   = (hour >> 4)   * 10 + (hour & 0x0F);
  // End conversion

  Time[7]     = second % 10 + 48;
  Time[6]     = second / 10 + 48;
  Time[4]     = minute % 10 + 48;
  Time[3]     = minute / 10 + 48;
  Time[1]     = hour   % 10 + 48;
  Time[0]     = hour   / 10 + 48;
  display.drawRect(0, 0, 128, 64, SSD1306_WHITE);
  draw_text(16, 25, Time, 2);                         // Display the time
}

void blink_parameter() {
  byte j = 1;
  while (j < 10 && digitalRead(Up) && digitalRead(Dn)) {
    j++;
    delay(25);
  }
}

byte edit(byte x_pos, byte y_pos, byte parameter) {
  char text[3];
  sprintf(text, "%02u", parameter);
  while (!digitalRead(Up));                     // Wait until button B1 released
  while (true) {
    while (!digitalRead(Dn)) {                  // If button B2 is pressed
      display.clearDisplay();
      parameter++;
      if (i == 0 && parameter > 23)                  // If hours > 23 ==> hours = 0
        parameter = 0;
      if (i == 1 && parameter > 59)                  // If minutes > 59 ==> minutes = 0
        parameter = 0;
      sprintf(text, "%02u", parameter);
      draw_text(x_pos, y_pos, text, 2);
      delay(200);                                    // Wait 200ms
    }
    display.drawRect(0, 0, 128, 64, SSD1306_WHITE);
    draw_text(x_pos, y_pos, "  ", 2);
    blink_parameter();
    draw_text(x_pos, y_pos, text, 2);
    blink_parameter();
    if (!digitalRead(Up)) {                     // If button B1 is pressed
      i++;                                           // Increament 'i' for the next parameter
      //      display.clearDisplay();

      return parameter;                              // Return parameter value and exit
    }
  }
}

void draw_text(byte x_pos, byte y_pos, char *text, byte text_size) {
  display.setCursor(x_pos, y_pos);
  display.setTextSize(text_size);
  display.print(text);
  display.display();
}

//---------------------------------------------
void loop() {

  // ========================================= Editing time and displaying on OLED ============================================//
  if (!digitalRead(Up)) {                       // If button B1 is pressed
    i = 0;
    while (!digitalRead(Up));                   // Wait for button B1 release

    hour   = edit(16, 25, hour);                     // Edit hours
    minute = edit(52, 25, minute);                   // Edit minutes

    // Convert decimal to BCD
    minute = ((minute / 10) << 4) + (minute % 10);
    hour = ((hour / 10) << 4) + (hour % 10);
    // End conversion

    // Write data to DS3231 RTC
    Wire.beginTransmission(0x68);               // Start I2C protocol with DS3231 address
    Wire.write(0);                              // Send register address
    Wire.write(0);                              // Reset sesonds and start oscillator
    Wire.write(minute);                         // Write minute
    Wire.write(hour);                           // Write hour
    Wire.endTransmission();                     // Stop transmission and release the I2C bus
    delay(200);                                 // Wait 200ms
  }

  Wire.beginTransmission(0x68);                 // Start I2C protocol with DS3231 address
  Wire.write(0);                                // Send register address
  Wire.endTransmission(false);                  // I2C restart
  Wire.requestFrom(0x68, 7);                    // Request 7 bytes from DS3231 and release I2C bus at end of reading
  second = Wire.read();                         // Read seconds from register 0
  minute = Wire.read();                         // Read minutes from register 1
  hour   = Wire.read();                         // Read hour from register 2
  Wire.beginTransmission(0x68);                 // Start I2C protocol with DS3231 address
  Wire.write(0x11);                             // Send register address
  Wire.endTransmission(false);                  // I2C restart
  Wire.requestFrom(0x68, 2);                    // Request 2 bytes from DS3231 and release I2C bus at end of reading
  DS3231_display();                             // Diaplay time & calendar

  delay(50);                                    // Wait 50ms

  { display.clearDisplay();
    if (digitalRead(Mnu) == 0) CurrentBaudRate = SelectBaudRate(CurrentBaudRate);
    //  DrawBaudRate(CurrentBaudRate);
    delay(10);

    x++;
    if (x > 123456) x = 0;
  }

  // ======================================= Reading Date and Time from RTC =============================================//
  DateTime now = rtc.now();
  char dt[16];
  char tm[16];
  char buffer [16];
  uint8_t thisSec, thisMin, thisHour;
  thisSec = now.second();
  thisMin = now.minute();
  thisHour = now.hour();
  sprintf(dt, "%02d-%02d-%02d", now.year(), now.month(), now.day());
  sprintf(tm, "%02d%02d%02d", now.hour(), now.minute(), now.second());
  sprintf (buffer, "%02d:%02d:%02d", thisHour, thisMin, thisSec);
  msec = millis() % 1000; //TO USE LAST 3 DIGITS OF MILLIS OF ARDUINO

  //SERIAL_PORT_1

//  if (string1Complete)
  { Serial.print (String1);
//    CR1A = String1.indexOf(13);  //finds location of first
//    String1A = String1.substring(0, CR1A + 2 );   //captures first data String
//    CR1B = String1.indexOf(13, CR1A + 2 ); //finds location of second ,
//    String1B = String1.substring(CR1A , CR1B + 2 ); //captures second data String
//    CR1C = String1.indexOf(13, CR1B + 2 );
//    String1C = String1.substring(CR1B , CR1C + 2 );
//    CR1D = String1.indexOf(13, CR1C + 2 );
//    String1D = String1.substring(CR1C , CR1D + 2 );
//    CR1E = String1.indexOf(13, CR1D + 2 );
//    String1E = String1.substring(CR1D , CR1E + 2 );
//    CR1F = String1.indexOf(13, CR1E + 2 );
//    String1F = String1.substring(CR1E , CR1F + 2 );
//
//    strID = (String1A.substring(0, 5));
//    if (strID == "$GPGG") {
//      Serial.println(String1);
//    }
//    strID = (String1B.substring(0, 5));
//    if (strID == "$GPVT") {
//      Serial.println(String1B);
//    }
//    strID = (String1C.substring(0, 5));
//    if (strID == "$GPZD") {
//      Serial.println(String1C);
//    }
//    strID = (String1D.substring(0, 5));
//    if (strID == "$GPGL") {
//      Serial.println(String1D);
//    }
//    strID = (String1E.substring(0, 5));
//    if (strID == "$GPGN") {
//      Serial.println(String1E);
//    }
//    strID = (String1F.substring(0, 5));
//    if (strID == "$GPGR") {
//      Serial.println(String1F);
//    }
//    strID = (String1.substring(0, 2));
//    if (strID == "$") {
      File dataFile = SD.open("GPS1.txt", FILE_WRITE);
      // if the file is available, write to it:

      strID = (String1A.substring(0, 5));
      if (strID == "$GPGG") {
        dataFile.print(dt);
        dataFile.print(" ");
        dataFile.print(tm);
        dataFile.print(msec);
        dataFile.print(",");
        dataFile.print(String1);
        Serial.print (String1);
        String1 = "";
        Serial.print (String1);
        dataFile.close();
      }
//    }
//      strID = (String1D.substring(4, 6));
//      if (strID == "TG" || "DA" || "LL" || "NS" || "RS") {
//        dataFile.print(String1B);
//        String1B = "";
//      }
//      strID = (String1C.substring(4, 6));
//      if (strID == "TG" || "DA" || "LL" || "NS" || "RS") {
//        dataFile.print(String1C);
//        String1C = "";
//      }
//      strID = (String1D.substring(4, 6));
//      if (strID == "TG" || "DA" || "LL" || "NS" || "RS") {
//        dataFile.print(String1D);
//        String1D = "";
//      }
//      strID = (String1E.substring(4, 6));
//      if (strID == "TG" || "DA" || "LL" || "NS" || "RS") {
//        dataFile.print(String1E);
//        String1E = "";
//      }
//      strID = (String1F.substring(4, 6));
//      if (strID == "TG" || "DA" || "LL" || "NS" || "RS") {
//        dataFile.print(String1F);
//        String1F = "";
//      }
      
//    }
    else {
      File dataFile = SD.open("ES2.txt", FILE_WRITE);

      if (dataFile) {
        dataFile.print(dt);
        dataFile.print(" ");
        dataFile.print(tm);
        dataFile.print(msec);
        dataFile.print(",");
        dataFile.println(String1);
        Serial.print (String1);
//        dataFile.println(String1B);
        String1A = "";
        String1B = "";
        dataFile.close();
      }
    }
//  }
  string1Complete = false;
  }
  
}


//-----------------------------------------------------------------------------------------------------------------

void serial1Event() {
  while (Serial1.available()) {
    char inChar1 = (char)Serial1.read();
    inputString1 += inChar1;
    Serial1TimeOut = RxTimeOut;
    NewDataFlag1 = 1;

    if (NewDataFlag1 == 1) {
      string1Complete = true;
    }

  }
}
6
  • 2
    You never check that indexOf() does find the '\r'. Why do you try to process five messages at a time instead of processing them one by one? Commented Oct 9, 2021 at 12:50
  • 1
    Please provide a more detailed description of what message data you have in that string, what errornous output you get and where in the code that happens.
    – chrisl
    Commented Oct 9, 2021 at 14:51
  • 4
    If (strID == "TG" || "DA" || "LL" || "NS" ... that is nonsense
    – SBF
    Commented Oct 9, 2021 at 15:41
  • I will provide you my complete program. Actually there is no delay between sentences so when the processor writes one sentence to sd card 2nd message arrives and most of the time it saves glitch in sd card.
    – Omar Rai
    Commented Oct 10, 2021 at 13:06
  • 1
    If you're curious, "DA", "LL", and "NS" are all truthy in C++. So, the above mentioned nonsense is functionally equivalent to if (true).
    – timemage
    Commented Oct 10, 2021 at 13:25

1 Answer 1

1

I do not know what the “frequencies” have to do with your problem, but I would bet that you would get more reliable results if you handle one NMEA sentence at a time, instead of trying to handle six of them at once, and hoping to get the right ones.

Below is a function that processes one complete sentence at a time. It records the sentence to the SD file if its type belongs to a list of “interesting” types you want to monitor:

// Sentence types that are to be recorded.
const char monitoredTypes[6][4] = {
    "GGA", "VTG", "ZDA", "GLL", "GNS", "GRS"
};

// Process a complete, CRLF-terminated NMEA sentence.
void processSentence(String &sentence) {

    // Sanity check.
    if (sentence.substring(0, 3) != "$GP") {
        Serial.print("WARNING: invalid sentence: ");
        Serial.print(sentence);
        return;
    }

    // Record the sentence if it has an interesting type.
    String type = sentence.substring(3, 6);
    for (int i = 0; i < 6; i++) {
        if (type == monitoredTypes[i]) {
            File dataFile = SD.open("GPS1.txt", FILE_WRITE);
            if (type == "GGA") {  // this type seems to be special
                dataFile.print(dt);
                dataFile.print(" ");
                dataFile.print(tm);
                dataFile.print(msec);
                dataFile.print(",");
            }
            dataFile.print(sentence);
            dataFile.close();
        }
    }
}

The way to use it is to buffer the incoming characters until you get a complete sentence (identified by the final LF), then submit that buffer to this function:

String buffer;

void loop() {
    while (Serial.available() > 0) {
        char c = Serial.read();
        buffer += c;

        // On end of sentence, process and clear the buffer.
        if (c == '\n') {
            processSentence(buffer);
            buffer = "";
        }
    }
}

Note that it wouldn't take too much work to get rid of the String class and use plain C strings instead. Plain strings are way more memory friendly.

0

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.