Go Down

Topic: correlating times on SD card to RTC (Read 717 times) previous topic - next topic

grif0210

Been working on this for 3 days now and I am stumped.

I expect my program to read the date from a DS3231 RTC module them compare that to a table in a txt file on an SD card (using this reader)  and then find the corresponding sunrise and sunset times in order to trigger a camera controlled by some relays to take a picture at the appropriate time.

Everything has been going fine but when I added in the code that would control the camera and also log some data to the SD card strange things started happening.  For example my Serial.println statements stopped working? 

Is it possible that this program has simply gotten too big for my uno and I need to get a different board?

I attached the txt file with the dates and times in it.

Here is my code, although I feel like it is way to long for anyone to read, I am open to any suggestions:
Code: [Select]

//MUST RESET RTC WHEN THIS SKETCH IS LOADED TO ENSURE DST STATE IS KNOWN

//DS3231:  SDA pin   -> Arduino Analog 4 or the dedicated SDA pin
//          SCL pin   -> Arduino Analog 5 or the dedicated SCL pin

//SD card attached to SPI bus as follows:
//  MOSI - pin 11
//  MISO - pin 12
//  CLK - pin 13
//  CS - pin 4 (for MKRZero SD: SDCARD_SS_PIN)

#include <Wire.h>
#include <TimeLib.h>
#include <DS1307RTC.h>
#include <SPI.h>
#include <SD.h>

File myFile;
tmElements_t tm;
String today = "";
String currentTime;
int currentMins;
String amPic;
String pmPic;
String amGoldPic;
String pmGoldPic;
char data;
String output = "";
String dataLog = "DATALOG.txt";
int currentDay  = -1;  //date vars start at -1 to ensure newDay gets true
boolean newDay = true;
boolean DST;
const int pResistor = A3;
const int power = 8;
const int shutter = 9;
int picNumber = 1;





void setup() {
  pinMode(pResistor, INPUT);
  pinMode(power, OUTPUT);
  pinMode(shutter, OUTPUT);

  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial
  }


  Serial.print("Initializing SD card...");

  if (!SD.begin(4)) {
    Serial.println("initialization failed!");
    while (1);
  }
  Serial.println("initialization done.");
  RTC.read(tm);
  DST = isItDST();
}


void loop() {

  //set today to the current date mm/dd/20
  initializeDate();
  if (newDay) {
    newDay = false;
    setPicTimes();


    //compare time to am pic until it matches
    //take the picture
    //repeat for the all four pics
    while (!compareTime(amGoldPic)) {
      delay(30000);
    }
    while (!compareTime(amPic)) {
      delay(30000);
    }
    while (!compareTime(pmPic)) {
      delay(30000);
    }
    while (!compareTime(pmGoldPic)) {
      delay(30000);
    }
  }
} //end of main loop


// if a new day has come today is set to the new date
// pics taken and times found are reset to false
void initializeDate() {
  RTC.read(tm);
  int d = tm.Day;
  if (d != currentDay) {
    int m = tm.Month;
    currentDay = d;
    today = String(m) + '/' + currentDay + "/20";
    Serial.println(String("Date: ") + today);
    newDay = true;
  }
}
// end of initializeDate



// read from the file until the current date is found
// initialize am and pm pic times for todays date in times file
void setPicTimes() {
  boolean timesFound = false;
  // re-open the file for reading:
  myFile = SD.open("times2.txt");
  if (myFile) {
    Serial.println("times2.txt opened");
    // read from the file until there's nothing else in it:
    while (myFile.available() && !timesFound) {
      data = myFile.read();
      do {
        output += data;
        data = myFile.read();
      } while (data != '\n' && data != '\r');
      Serial.println("out " + output);
      timesFound = checkDate();
      output = "";
      data = myFile.read();
    }
    // close the file:
    myFile.close();
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }

}

// Checks if a date read from the times file matches the current days date
// if it does then the times for the AM and PM pics will be set from that
// accounts for DST
// output will be one row from the times file eg mm/dd/20 \t hh:mm \t hh:mm \n\r
boolean checkDate() {
  if (output.substring(0, output.indexOf('\t')).equals(today)) {
    int amHours = output.substring(output.indexOf('\t') + 1, output.indexOf(':')).toInt();
    int pmHours = output.substring(output.lastIndexOf('\t') + 1, output.lastIndexOf(':')).toInt();
    if (DST) {
      amGoldPic = (amHours) + output.substring(output.indexOf(':'), output.lastIndexOf('\t'));
      amPic = (amHours + 2) + output.substring(output.indexOf(':'), output.lastIndexOf('\t'));
      pmPic = (pmHours - 4) + output.substring(output.lastIndexOf(':'));
      pmGoldPic = (pmHours - 2) + output.substring(output.lastIndexOf(':'));
    } else {
      amGoldPic = (amHours + 1) + output.substring(output.indexOf(':'), output.lastIndexOf('\t'));
      amPic = (amHours + 3) + output.substring(output.indexOf(':'), output.lastIndexOf('\t'));
      pmPic = (pmHours - 3) + output.substring(output.lastIndexOf(':'));
      pmGoldPic = (pmHours - 1) + output.substring(output.lastIndexOf(':'));
    }
    Serial.println("am, pm: " + amPic + ", " + pmPic);
    return true; //stops the loop reading through the file
  }
  return false;
}


//compares the cuurent time to the time a picture is supposed to be taken
boolean compareTime(String picTime) {
  RTC.read(tm);
  currentTime = String(tm.Hour) + ":" + print2digits(tm.Minute);
  Serial.println(currentTime);
  delay(2000);
  if (currentTime.equals(picTime)) {
    Serial.println(picTime + " picture taken");
    takePic(picTime);
    return true;
  }
  else if (tm.Hour > picTime.substring(0, picTime.indexOf(':')).toInt()) {
    Serial.println(picTime + "picture missed");
    return true;
  }
  else return false;
} // end of compareTime


//puts a zero in front of single digit minutes
String print2digits(int number) {
  String digits = "";
  if (number >= 0 && number < 10) {
    digits += "0";
  }
  digits += String(number);
  return digits;
}


boolean isItDST() {

  // ********************* Calculate offset for Sunday *********************
  int y = tmYearToCalendar(tm.Year) - 2000;                          // DS3231 uses two digit year (required here)
  int x = (y + y / 4 + 2) % 7;    // remainder will identify which day of month
  // is Sunday by subtracting x from the one
  // or two week window.  First two weeks for March
  // and first week for November
  // *********** Test DST: BEGINS on 2nd Sunday of March @ 2:00 AM *********
  if (tm.Month == 3 && tm.Day >= (14 - x))
  {
    return true;                           // Daylight Savings Time is TRUE (add one hour)
  }
  if (tm.Month > 4 && tm.Month < 11)
  {
    return true;
  }
  // ************* Test DST: ENDS on 1st Sunday of Nov @ 2:00 AM ************
  if (tm.Month == 11 && tm.Day <= (7 - x))
  {
    return true;                            // daylight savings time is TRUE
  }
  return false;  //it is not DST

}//end of isItDST

// take the pic and log it in the DATALOG file
void takePic (String picTime) {
  //take the pic
  digitalWrite(power, HIGH);
  delay(10000);
  digitalWrite(shutter, HIGH);
  delay(500);
  digitalWrite(shutter, LOW);
  delay(10000);
  digitalWrite(power, LOW);

  //log the pic
  myFile = SD.open(dataLog);
  if (myFile) {
    Serial.print(String("Photo ") + picNumber + ": Writing to " + dataLog + "...");
    myFile.println(String("Pic: ") + picNumber);
    picNumber++;
    myFile.println(today + " - " + picTime);
    myFile.println("Photo Resistor Value: " + analogRead(pResistor));
    // close the file:
    myFile.close();
    Serial.println("done.");
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening" + dataLog);
  }
}// end of takePhoto



Thanks!

ieee488

step by step

add part just for controlling the camera
does it work?

if it does, then add part for logging to the SD card
does it work?

if not, debug.


.

grif0210

Thanks for the reply :)

I have gone through the program step by step.  I am having very strange thing happen.  For example, I comment out most of the code and get down to one part that works on int's own... reading and serial.printing the data from the SD card. 

Then I add an inert chunk of code.  Like ...

if(day == true){
      day = false;
}

... this breaks my code and printing the data from the SD card no longer works.

I am so confused about how that could happen.

grif0210

I have been building and rebuilding this program to try to figure out what is wrong.  It seems like it might have something to do with interacting with the RTC. 

Here is a simplified version of the code:
Code: [Select]
/*
  SD card read/write

  This example shows how to read and write data to and from an SD card file
  The circuit:
   SD card attached to SPI bus as follows:
 ** MOSI - pin 11
 ** MISO - pin 12
 ** CLK - pin 13
 ** CS - pin 4 (for MKRZero SD: SDCARD_SS_PIN)

  created   Nov 2010
  by David A. Mellis
  modified 9 Apr 2012
  by Tom Igoe

  This example code is in the public domain.

*/

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

File myFile;
String output = "";
char data;
String today = "2/29/20";
String amPic;
String pmPic;
boolean timesFound = false;
int currentDay  = -1;
boolean newDay = true;
int d;
int m;

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {} // wait for serial port to connect. Needed for native USB port only
 

  setSyncProvider(RTC.get);   // the function to get the time from the RTC
  if (timeStatus() != timeSet)
    Serial.println("Unable to sync with the RTC");
  else
    Serial.println("RTC has set the system time");

  Serial.print("Initializing SD card...");

  if (!SD.begin(4)) {
    Serial.println("initialization failed!");
    while (1);
  }
  Serial.println("initialization done.");


  initializeDate();
  readStuff();
}

void loop() {
  // nothing happens after setup
}

// if a new day has come today is set to the new date
// pics taken and times found are reset to false
void initializeDate() {
  d = day();
  if (d != currentDay) {
    m = month();
    currentDay = d;
    today = String(m) + '/' + currentDay + "/20";
    Serial.println(String("Date: ") + today);
    newDay = true;
  }
}
// end of initializeDate

void readStuff() {
  // re-open the file for reading:
  myFile = SD.open("times2.txt");
  if (myFile) {
    Serial.println("times2.txt opened");

    // read from the file until there's nothing else in it:
    while (myFile.available() && !timesFound) {
      data = myFile.read();
      do {
        output += data;
        data = myFile.read();
      } while (data != '\n' && data != '\r');
      Serial.println("out " + output);
      checkDate();
      output = "";
      data = myFile.read();
    }
    // close the file:
    myFile.close();
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }

}//end of read stuff

void checkDate() {
  if (output.substring(0, output.indexOf('\t')).equals(today)) {
    int amHours = output.substring(output.indexOf('\t') + 1, output.indexOf(':')).toInt();
    int pmHours = output.substring(output.lastIndexOf('\t') + 1, output.lastIndexOf(':')).toInt();
    if (false) {
      amPic = (amHours + 2) + output.substring(output.indexOf(':'), output.lastIndexOf('\t'));
      pmPic = (pmHours - 4) + output.substring(output.lastIndexOf(':'));
    } else {
      amPic = (amHours + 3) + output.substring(output.indexOf(':'), output.lastIndexOf('\t'));
      pmPic = (pmHours - 3) + output.substring(output.lastIndexOf(':'));
    }
    Serial.println("am, pm: " + amPic + ", " + pmPic);
    timesFound = true; //stops the loop reading through the file
  }
}


It works when the RTC is not involved but then when I add the snippet below it no longer prints anything from the SD card.  It does correctly read the date and set the string variable today to be the date exactly as intended.

Code: [Select]
setSyncProvider(RTC.get);   // the function to get the time from the RTC
  if (timeStatus() != timeSet)
    Serial.println("Unable to sync with the RTC");
  else
    Serial.println("RTC has set the system time");



Why would reading from the RTC have an effect on reading from the SD card?



grif0210

I am pretty confident that the problems in my program are being caused by running out of memory.  The SD library takes like 400k when it opens a File.  I determined this by using Serial.println(FreeRam()).

That RAM doesn't free up when the file is closed and opening another file then runs me out of memory.

I am trying a variety of things to limit memory usage such as using the F() macro where possible using fewer string variables and switching to the Sdfat library instead of SD. 

If I can't get the program to run with these changes I will just get a mega2560 board... 4 times the RAM ... and it should run easily.

grif0210

The combination of using the F()macro where possible and the Sdfat library solved my problem.  Man that was tough to debug. 

One lingering question I have is why does this work:

Serial.println(F("some string")); 

but I got an error when usnig F() on a file name  like this:

myFile = SD.open(F("times2.txt"));

Clearly I don't know everything there is to know... yet ¯\_(ツ)_/¯



Go Up