1

I am experiencing problems when I put parts of my code into custom functions and then have Arduino Mega 2560 run it. The code works fine when I put it all in the void loop() function, but when I create new functions then call those functions in the loop() function, it doesn't do what I want it to.

Here is the code where I put everything in the loop function

/*
Location.txt: Date/Time , Latitude (deg decimal), Longitude, Altitude (m)
Speed.txt: Date/Time, Speed (m/s), Heading (deg)
*/

#include<TinyGPS.h>
#include<SD.h>
#include<SPI.h>

int CS = 53;

long lat,lon;
unsigned long time, date;
int year,tinseconds;
byte month, day, hour, minute, second, hundredths;
unsigned long age;
char dataString[20];
TinyGPS GPS;

struct GPSstruct {
  String dateTime;
  int timeseconds;
  float C_lat;
  float C_lon;
  float C_alt;
  float heading;
  float speedmps;
};

void setup()
{
  Serial.begin(115200);
  Serial1.begin(38400);
  pinMode(CS, OUTPUT);
  if(!SD.begin(CS))
  {
    Serial.println(F("Card Failure"));
  }
}

void loop()
{
if(Serial1.available()){ // check for gps data
   if(GPS.encode(Serial1.read())){ // encode gps data
    GPS.crack_datetime(&year, &month, &day, &hour, &minute, &second, &hundredths, &age);
    GPS.get_position(&lat,&lon); // get latitude and longitude in degree decimals multiplied by 10^5
    sprintf(dataString, "%02d/%02d/%02d %02d:%02d:%02d",month,day,year,hour,minute,second);
    tinseconds = second + minute*60 + hour*3600;
    float C_lat = ((float)lat)/1000000; //to get degree decimals
    float C_lon = ((float)lon)/1000000;
    float C_alt = GPS.f_altitude();
    float heading = GPS.f_course();
    float speedmps = GPS.f_speed_mps();
    GPSstruct A = {dataString,tinseconds,C_lat,C_lon,C_alt,heading,speedmps};

//DEBUG
    Serial.println();
    Serial.print(F("Date/Time: "));Serial.println(dataString);
    Serial.print(F("Time (sec): "));Serial.println(tinseconds);
    Serial.print(F("Lat: "));Serial.println(C_lat,5);
    Serial.print(F("Lon: "));Serial.println(C_lon,5);
    Serial.print(F("Alt: "));Serial.println(C_alt);
    Serial.print(F("Heading: "));Serial.println(heading);
    Serial.print(F("Speed: "));Serial.println(speedmps);
//END of DEBUG

//add the code below makes alt = 1000000 for a long time then it fixes at some ?wierd? number
//------//
  File dataFile = SD.open("Location.txt", FILE_WRITE); //Records date/time, lat, lon, alt
    if (dataFile)
    {
      dataFile.print(A.dateTime);dataFile.print(" , ");dataFile.print(A.C_lat,5);dataFile.print(" , ");dataFile.print(A.C_lon,5);dataFile.print(" , ");dataFile.println(A.C_alt);
      dataFile.close();
    }
    else
    {
       Serial.println(F("Location.txt cannot be opened!")); 
    }


   File dataFile2 = SD.open("Speed.txt",FILE_WRITE); //Records date/time, speed, heading
   if (dataFile2)
   {
     dataFile2.print(A.dateTime);dataFile2.print(" , ");dataFile2.print(A.speedmps);dataFile2.print(" , ");dataFile2.println(A.heading);
     dataFile2.close();
   }
   else
   {
     Serial.println(F("Speed.txt cannot be opened!"));
   }
//------//
   }
}
}

Here is the code where I put them into two custom functions and call them in loop()

#include<TinyGPS.h>
#include<SD.h>
#include<SPI.h>

int CS = 53;
long lat,lon;
unsigned long time, date;
int year,tinseconds;
byte month, day, hour, minute, second, hundredths;
unsigned long age;
char dataString[20];
TinyGPS GPS;

struct GPSstruct {
  char dateTime[20];
  int timeseconds;
  float C_lat;
  float C_lon;
  float C_alt;
  float heading;
  float speedmps;
};

//Function Prototypes
struct GPSstruct GPSdata(void);
void SDlogger(struct GPSstruct);

void setup()
{
  Serial.begin(115200);
  Serial1.begin(38400);
  pinMode(CS, OUTPUT);
  SD.begin(CS);
}

//GPS data function:
struct GPSstruct GPSdata(void) {
static GPSstruct A;

 if(Serial1.available()){ // check for gps data
   if(GPS.encode(Serial1.read())){ // encode gps data
    GPS.crack_datetime(&year, &month, &day, &hour, &minute, &second, &hundredths, &age);
    GPS.get_position(&lat,&lon); // get latitude and longitude in degree decimals multiplied by 10^5
    sprintf(dataString, "%02d/%02d/%02d %02d:%02d:%02d",month,day,year,hour,minute,second);
    tinseconds = second;
    float C_lat = ((float)lat)/1000000; //to get degree decimals
    float C_lon = ((float)lon)/1000000;
    float C_alt = GPS.f_altitude();
    float heading = GPS.f_course();
    float speedmps = GPS.f_speed_mps();
    strcpy(A.dateTime, dataString);
    A.C_lat = C_lat;
    A.C_lon = C_lon;
    A.C_alt = C_alt;
    A.heading = heading;
    A.speedmps = speedmps;

//DEBUG
    Serial.print(F("Date/Time: "));Serial.println(dataString);
    Serial.print(F("Time (sec): "));Serial.println(tinseconds);
    Serial.print(F("Lat: "));Serial.println(C_lat);
    Serial.print(F("Lon: "));Serial.println(C_lon);
    Serial.print(F("Alt: "));Serial.println(C_alt);
    Serial.print(F("Heading: "));Serial.println(heading);
    Serial.print(F("Speed: "));Serial.println(speedmps);
    Serial.println();
//END of DEBUG
  }
 }
 return A;
}

//SD data logging funct:
void SDlogger(struct GPSstruct A)
{
   File dataFile = SD.open("Location.txt", FILE_WRITE); //Records date/time, lat, lon, alt
    if (dataFile)
    {
      dataFile.print(A.dateTime);dataFile.print(" , ");dataFile.print(A.C_lat);dataFile.print(" , ");dataFile.print(A.C_lon);dataFile.print(" , ");dataFile.println(A.C_alt);
      dataFile.close();
    }
    else
    {
       Serial.println(F("Location.txt cannot be opened!")); 
    }
   File dataFile2 = SD.open("Speed.txt",FILE_WRITE); //Records date/time, speed, heading
   if (dataFile2)
   {
     dataFile2.print(A.dateTime);dataFile2.print(" , ");dataFile2.print(A.speedmps);dataFile2.print(" , ");dataFile2.println(A.heading);
     dataFile2.close();
   }
   else
   {
     Serial.println(F("Speed.txt cannot be opened!"));
   } 
} 
void loop()
{
  struct GPSstruct Gdata = GPSdata();
  SDlogger(Gdata);
}

The one with all the code in the loop function prints all the serial.println commands and writes data into the micro SD card, but the one with custom functions DOESN'T print serial.println commands in GPSdata function and only prints that "Location.txt/Speed.txt cannot be opened!" and have writes 0 into the mirco SD card.

Why is this happening? Is it memory problems? (But the other one works fine)

The code here is meant to be a part of a bigger main code that uses these GPS data, so I would prefer it if I can keep the main script clean using custom functions.

Thank you.

  • The code in both appears to be perfectly satisfactory - stock - normal - stream file writing. Do you have an "errno" global variable available? If you do, that might shed some light on the errors you're getting. There's nothing inherent to custom functions that would make your code not work. You're absolutely sure that the SD card was plugged in & functional when you used the custom function and it failed? – TDHofstetter Aug 18 '14 at 20:40
2

Admittedly, your code is somewhat hard to read without an actual editor (not your fault), but I think the issue is that in the first code (everything in one loop), the matching bracket from the initial if-statement (if(Serial1.available()) {) is located after the SD logging functions.

In the second code (decomposing the code), you have the SD logging done outside the if-statement. My guess is that Serial1.available() = false initially, so in the first piece of code, it skips everything else and loop until Serial1.available() == true. That probably doesn't take long, so you just see everything working. In the second code, you return static GPSstruct A (I'm not sure you want this to be static, but I could be wrong) which has been initialized but contains no useful data (it's uninitialized). The void loop() then takes that empty struct and passes it over to SDlogger(struct GPSstruct). That function doesn't do any error-checking to make sure that A has useful information.

An easy workaround would be to add a field to the GPSstruct for whether or not it contains data. It's a simple boolean value. The code might look something like this:

struct GPSstruct {
  boolean containsData;
  String dateTime;
  int timeseconds;
  float C_lat;
  float C_lon;
  float C_alt;
  float heading;
  float speedmps;
};

...

if(Serial1.available()){
  A.containsData = true;
  ...
} else {
  A.containsData = false;
}

...

void SDlogger(struct GPSstruct A) {
  if(A.containsData) {
    ...
  } else {
    return;
  }

Also, as I was typing this, it got migrated...

  • Personally, I'd put the check for available data in loop(), and if available, call the GPSdata and SDlogger functions based on that check. – Harper Shelby Aug 18 '14 at 22:32
  • That would work too. You can do it however you like; I just tried to come up with a quick example. Putting it in the loop would definitely be simpler. – Hari Ganti Aug 18 '14 at 23:45
  • Was that the problem? I don't actually see a way to mark the answer, but if you can mark a post as answering your question, you should to close it. Glad we could help! – Hari Ganti Aug 21 '14 at 0:20

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.