Incorrect date and time printed to SD card Arduino Yun

Hi Everyone,

I have a system with a arduino yun that is using rtc ds1307 clock and a ds18b20 temperature probe and heat lamp to ramp a tank to different daily max temp at the same time each day over the span of 3 weeks. Every minute it prints the date, time, and temperature specifcs to an SD card. I've ran this system (and associated code) a few times before and didn't run into any SD card issues. The last time I used the system was 6 months ago for 3 months and printed everything correctly for that time period.

I need to run the system again and the issue I am having is that when I check the data on the SD card, the date and time are completely wrong (but temperature stats are correct). I've run the example ds1307 sketch to check the RTC is set correctly and it displays the the correct time and date on the serial monitor. I am not sure why this is not communicated to the SD card. I've tried formatting the SD card and re-calibrating the RTC clock but to no avail. Does anyone have any suggestions for what could be causing the issue or how to go about troubleshooting it? I am very much a novice with arduino so very likely I am missing something obvious. Thanks!

Here is the code i'm using (which has worked fine before):

#include <Wire.h>    //library allows communication with I2C/TWI devices
  #include <Bridge.h>             //necessary library connecting Arduino chip to Linux chip
  #include <Process.h>            //library that can calculate and process data (from server)
  #include <FileIO.h>             //library for read/write to SD card on YUN (different from UNO)
  
  //#include <LiquidCrystal.h> //From https://github.com/adafruit/LiquidCrystal//make sure to use the LiquidCrystal library from
                            //adafruit if you are using the i2C LCD backpack
  #include <SPI.h>  // Required for RTClib to compile properly
  #include <RTClib.h> // From https://github.com/mizraith/RTClib
  //#include <RTC_DS1307.h>  // From https://github.com/mizraith/RTClib   (note: not the Chronodot)
  //#include <PID_v1.h> //From https://github.com/br3ttb/Arduino-PID-Library
  #include <Timer.h> // From https://github.com/JChristensen/Timer
  #include <OneWire.h> // From  http://www.pjrc.com/teensy/td_libs_OneWire.html
  #include <DallasTemperature.h> //From  http://milesburton.com/Main_Page?title=Dallas_Temperature_Control_Library
  
  
  #define Heater_LED 5          //pin connected to LED showing heater is on
  #define lowTide_LED 4         //pin connected to LED showing valve is open
  #define Heater_Relay 9        //pin connected to heater relay
  #define lowTideRelay 10       //pin connected to valve relay
  #define temperature_sensor_bus 6  // pin the temeperature sensors is connected to
  
  #define TempProgSize 13        //defined size of the unpredictable temp array
  //---------------------------------------------------------
  // Real Time Clock setup
  RTC_DS1307 RTC;                 //allow reference to clock with "RTC" (note: not the Chronodot)
  //---------------------------------------------------------
  
  //---------------------------------------------------------
  //Specify 1-Wire connections
  //---------------------------------------------------------
  OneWire oneWire(temperature_sensor_bus);
  DallasTemperature sensors(&oneWire);
  DeviceAddress Temp01 = {0x28, 0xBD, 0xC9, 0xB4, 0x0A, 0x00, 0x00, 0x77}; //address for specific sensor

  //DeviceAddress deviceAddress
  //---------------------------------------------------------
  
  //---------------------------------------------------------
  //Specify timer
  //---------------------------------------------------------
  Timer t;                  //make the variable "t" represent a timer
  
  //---------------------------------------------------------
  
  unsigned long datetime;    //variable to hold date and time data
  
  int startDay;              //variable to specify numerical day exp. started
  int today;                 //variable to hold today's numerical day
  int previous_month_index;  //variable to hold the index (starting at Jan = 0, Feb = 1) of the previous month
  int elapsedDays;           //variable to hold the total elapsed days in experiment
  
  boolean tideValveState;    //variable to (0,1) to hold state of the valve (1 = open, 0 = closed)
  
  //---------------------------------------------------------
  // Tide Time/Temperature Variables
  //---------------------------------------------------------
  int lowTideHR_1 = 9; //first low tide starts at this hour
  int lowTideMIN_1 = 00; // ...and this minute
  
  int lowTideHR_2 = 21; //second low tide starts at this hour
  int lowTideMIN_2 = 00; // ...and this minute
  
  int duration_HR = 6;  // low tide duration length (hrs)
  int duration_MIN = 00; //...and minutes. (ex. low tide is 6hrs and 25min long)
  
  int duration = (duration_HR * 60) + (duration_MIN % 60); //tide duration in minutes
  
  int Start_1 = (lowTideHR_1 * 60) + (lowTideMIN_1 % 60);  //start time of tide 1 in min. since midnight
  
  int endTime_1 = (Start_1 + duration) % (24 * 60);        //end time of tide 1 in min. since midnight
  
  int Start_2 = (lowTideHR_2 * 60) + (lowTideMIN_2 % 60);  //start time of tide 2 in min. since midnight
  
  int endTime_2 = (Start_2 + duration) % (24 * 60);        //end time of tide 2 in min. since midnight
  
  
  byte TempProg[] = {22, 29, 33, 21, 31, 17, 30, 22, 29, 33, 30, 14, 26, 34, 30, 23, 28, 19, 24}; //max temps for unpredictable tide
  float temp = 13;       //initiate temp variable
  float Tset = 13;       //initial set temperature
  float Tmin = 13;       //base temperature during high tide
  float Tmax = TempProg[0];       //maximum ramp temperature
  float rate = 0;        //initiate rate variable
  float timeDelay = 60000; // time between increases in heat ramp temperature in ms.
  const long tembooDelay = 5000; //time between updates to Google Spreadsheet (in ms)
  unsigned long previousMillis = 0; 
  
  boolean newDay;          //variable for keeping track if tide 2 into the following day
  
  float PulseWM;
  float deltaT;
  //---------------------------------------------------------
  
  //*********************************************************
  //SETUP LOOP
  //*********************************************************
  void setup()
  {
    Wire.begin();                         //required for communication
    RTC.begin();                         //Start clock
    Bridge.begin();                      //Start Bridge/Linux connection
    FileSystem.begin();                  //Start SD card saving functions
  
    DateTime now = RTC.now();            //specify "now" as the current datetime
    startDay = now.day();                //specify that the numerical day when sketch starts in the start day
    Serial.begin(115200);              //Start serial monitor
    //lcd.begin(16, 2);                    //Start LCD (dimensions 16 x 2)
    sensors.begin();                     //Initialize 1-Wire sensors
     sensors.setResolution(Temp01, 12);   //set temperature sensor resolution (12bit = 0.0625 deg.C)

    
  
    pinMode(lowTideRelay, OUTPUT);       //set LED and Relays to output
    pinMode(lowTide_LED, OUTPUT);
    pinMode(Heater_LED, OUTPUT);
    pinMode(Heater_Relay, OUTPUT);
  
    digitalWrite(lowTideRelay, LOW);     //have the tide valve start closed
    digitalWrite(lowTide_LED, LOW);      //have the tide LED start off
  
  
    //---------------------------------------------------------
    //Setup Timer loops
    //---------------------------------------------------------
   // t.every(200, PIDloop);                  //update PID every 200ms
    t.every(timeDelay, tempRamp);           //increase Tset every "timeDelay"
    //t.every(1000, lcdPrint);                 //update the lcd (running the lcdPrint function (below) every 1000 ms
    t.every(200, heater);                 //run heater function every 200ms
    t.every(60000, sd_card);               //run the sd_card function every 60000 ms, 60 s.
    //---------------------------------------------------------
  
  } //end of setup
  
  
  //*********************************************************
  //MAIN LOOP
  //*********************************************************
  
  void loop()
  {
    Serial.print(temp);    //print to Serial Monitor every 3000ms
   delay(3000);
    unsigned long currentMillis = millis();                        //initiate a timer counting ms from start of sketch
   
          getTempFunc();                                        //get temperatures
          tideValve();                                          //specify if tide valve is open of closed
                                                   //check  
            
      if (currentMillis - previousMillis > tembooDelay) {                      //every tembooDelay
        previousMillis = currentMillis;                                  //reset timer...
 //       runAppendValues(datetime, temp, Tset, deltaT, PulseWM, Tmax);     //and send data to GoogleSpreadheet
      }
      
      t.update();                                               //update timer                                                  
     
  }//end Main
  
  
  
  
  
  //---------------------------------------------------------
  //getTempFunc function. This function takes a digital reading
  //and returns a temperature value.
  //---------------------------------------------------------
  float getTempFunc()
  {
    sensors.requestTemperatures();                                      //request temperature from sensor
    temp = sensors.getTempC(Temp01);                                    //get temperature from sensor without having to manually put in address
    return temp;                                                        //make temperature available
  }
  
  
  
  //---------------------------------------------------------
  //tempRamp function. Takes time as an input and specifies
  //whether it is time for a heat ramp, and if so, specifies
  //the ramping rate.
  //---------------------------------------------------------
  void tempRamp()
  {
  
    // Get current time, store in object 'now'
    DateTime now = RTC.now();
  
    //create a current time variable (in min from midnight)
    int time_min = now.hour() * 60 + now.minute();
  
    //specify rate of temp increase based on the temperature
    //range of the ramp, the duration of the low tide (in ms)
    //and how often this temperature increase will be initiated
    float lowTideDurationMS = duration * 60000;
    float rate = (Tmax - Tmin) / (lowTideDurationMS / timeDelay);
  
  
    //series of if else statements to apply heating during the low tide period
    if (time_min >= Start_1 && time_min < endTime_1 && Tset < Tmax)
    {
      Tset = Tset + rate;
  
    }
    else if (time_min < Start_1 || time_min >= endTime_1)
    {
      Tset = Tmin;
  
    }
  
  }
  //---------------------------------------------------------
  
  
  //---------------------------------------------------------
  //tideValve function. Takes a time input and specifies when
  //a valve opens to initiate low tide (water leaves tank)
  ////---------------------------------------------------------
  void tideValve()
  {
    // Get current time, store in object 'now'
    DateTime now = RTC.now();
  
  
    if (float(Start_2 + duration) / 1440 > 1)                    // simple test to see if the second low tide will
    {                                                            //extend across midnight and into a new day
      newDay = true;
    } else {
      newDay = false;
    };
  
    //create a current time variable (in min from midnight)
    int time_min = now.hour() * 60 + now.minute();
  
    if (time_min >= Start_1 && time_min < endTime_1 || time_min >= Start_2 && time_min < endTime_2 || newDay == true && time_min > Start_2 || newDay == true && time_min < endTime_2) //if its low tide
    {
      digitalWrite(lowTideRelay, HIGH);                           //turn on Relay1 to power valve (open valve)
      digitalWrite(lowTide_LED, HIGH);                            // turn on indicator LED
    }
    else  {                                                       //if its high tide
      digitalWrite(lowTideRelay, LOW);                            //reverse Relay1 (close valve)
      digitalWrite(lowTide_LED, LOW);                            //turn off indicator LED
    }
  
    tideValveState = digitalRead(lowTideRelay);                  //determine whether the valve is open (1) or closed (0)
  }
  //---------------------------------------------------------
  
  
  //---------------------------------------------------------
  //heater function. Specifies how much power to provide to the heater
  //to achieve a desired ramp rate (based on Tset)
  //---------------------------------------------------------
  
  //The function for PWM applied above 19C may need some explanation. The d19 - toMax values increases with increasing setTemp.
  //this values is then multiplied by 0.025 (to put the values in the proper range) and added to 1. The pow() function raises this
  //value to the power of 2 (squares it). This in turn is multiplied by 255. The result is that at higher set temperatures 255 is 
  //multiplied by progressively larger values (1.1, 1.4, 1.63), changing the scale. Thus when this value is multiplied by the temperature 
  //differential at a higher set temp a differential of 0.2 result in greater power than a differential of 0.2 at a lower set temp. Below
  //19C the simple differential * 255 seems to work pretty well.
  
  void heater() {
    
          deltaT = temp - Tset;              //calculate the differential between current (actual) temp and set temp
      //    float d19 = Tmax - 19;            //calculate the range between the maximum ramp temp and 19C
      //    float toMax = Tmax - Tset;        //calculate the difference between the Tmax temp and the current set temp
          
      //    if(Tset <= 19) {                  //if set temp is below 19C
      //    PulseWM = abs(deltaT) * 255;      //...set the PWM value (0 to 255) to the (temp differential * 255) (the abs() keeps PWM positive)
      //    if(PulseWM >255) {                //if the PWM value calculated is greater than 255
     //       PulseWM = 255;                  // ...set it to 255 (as this is the max allowed)
     //     }
     //      if(deltaT <= 0) {                        //if the temperature differential (temp - Tset) is zero or negative
      //       analogWrite(Heater_Relay, PulseWM);    //...apply the PulseWM value to the heater relay
      //     } else if (deltaT > 0) {                 //otherwise if the differential is positive
      //       analogWrite(Heater_Relay, 0);          //... turn the relay off (no power)
       //    }
       //   }else if (Tset > 19) {                                              //if instead, the set temp is above 19C
           PulseWM = abs(deltaT) * 255;
       //    PulseWM = abs(deltaT) * (pow((1+((d19-toMax)*0.025)),2) * 255);    //specify the PulseWM value using this function
           if(PulseWM >255) {                                                //Again, if PulseWM is above 255
            PulseWM = 255;                                                   //...set it to 255
          }
          if(deltaT <= 0) {                                                  //if the differntial is zero or less
            analogWrite(Heater_Relay, PulseWM);                              //...apply the PulseWM valu to the relay
          } else if(deltaT > 0) {                                            //otherwise if the differential is positive
            analogWrite(Heater_Relay, 0);                                    //...turn the relay off
          }
        //  }
  }
  
  //---------------------------------------------------------
  
  
  //---------------------------------------------------------
  //sd_card function. Specifies how and what to write to SD card
  //---------------------------------------------------------
  void sd_card() {
    
    FileSystem.begin();
    String dataString;                                                        //make an empty data string
    dataString += String(getDateTime());                                      //add to that string data from the getDateTime function (below)
    dataString += ",";                                                        //add a comma to separate entries
    dataString += String(temp);                                               //add the measured temperature as a string
    dataString += ",";                                                        // etc....
    dataString += String(Tset);
    dataString += ",";                                                        // etc....
    dataString += String(tideValveState);                                  // uncomment if Unpredictable heating is run on the arduino 
    dataString += ",";                                                      //connected to the tide valve
    dataString += String(deltaT);
    dataString += ",";
    dataString += String(PulseWM);
  
    File dataFile = FileSystem.open("/mnt/sd/test.txt", FILE_APPEND);    //define a datafile, with a name ".txt" and
                                                                            //save location, if file exist add to it, if not make it
    if (dataFile) {
      dataFile.println(dataString);                                        //print the string made above into data file
      dataFile.close();                                                    //close the file, until called again
    }
  
  }
  //---------------------------------------------------------
  
  
  //---------------------------------------------------------
  //getDateTime function. Specifies how to get dateTime data from server
  //---------------------------------------------------------
  
  String getDateTime() {
    String result;                                                         //create an empty string
    Process datetime;                                                      //specify a Process entity called datetime
  
    datetime.begin("date");   // with datetime get the current date
    datetime.addParameter("+%D-%T");                                     //format the date so we get the date (%D) and the current time (%T) 
  
    datetime.run();                                                      //run this function to actually get datetime
  
    while (datetime.available() > 0) {                                   //return the result of datetime
      char c = datetime.read();
      if (c != '\n')
        result += c;
    }
    return result;
  }
  
  
  //---------------------------------------------------------
  // newTmax function. For unpredictable heat ramps, specifies the correct
  // maximum temperature
  //---------------------------------------------------------
  
  
  void newTmax() {
    DateTime now = RTC.now();                                        //get time
  
  byte MonthDays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; //specify days in each month
  
  
     today = now.day();                                           //define today's numerical day
     elapsedDays = today - startDay;                              //calculate the number of elapsed days since the start day
     previous_month_index = (now.month() - 1) - 1;                      //calculate the index for the previous month (keeping in mind
                                                                     //that the indexing starts at 0
    if (now.month() == 0) {                                          //if the current month is 0 (Jan), the previous month was 11 (Dec)
      previous_month_index = 11;
    }
  
    //if in the above substraction elapsed days is <0 the experiment has gone into a second month (start = 28, today = 2,
    //elapsedDays = 2-28 = -26. Additionally if the current year is divisible evenly by 4, its a leap year and Feb has 28
    //days. The number of elapsed days if you have gone into a new month is the negative value from substraction, plus the
    //number of days in the previous month. The code below applies this math, keeping track of leap years.
  
    if (elapsedDays < 0 ) {
      elapsedDays += MonthDays[previous_month_index];                //Start with days from previous month
      if((previous_month_index == 1) && (now.year() % 4) == 0)      // Test if previous month was Feb and if it is a leap year
      elapsedDays++;                                          //if Yes, add 1 more day
    } else
      elapsedDays = today - startDay;                        //otherwise proceed as normal
   
    if (elapsedDays > TempProgSize) {                         //if the elapsed days exceed the number of assigned temperature
      elapsedDays = 0;                                        //values, use a roll-over and go back to the beginning.
    }
  
    Tmax = TempProg[elapsedDays];                               //once you have determined what day of the experiment you are in
  }                                                               //select that value from the TempProg array
  //---------------------------------------------------------
  

Did you happen to recompile the program between the last good run and the current bad run?
Paul

I have multiple replicate codes (just the serial address to the temperature sensor is different each one) and have tried uploading the code without recompiling and also uploaded one with recompiling and it doesn't seem to make a difference - both still give me the incorrect time and date on the SD. Is it possible that recompilation could affect how the RTC data is communicated to the SD card?

Can you expand on what's incorrect about the time? Is it just garbage? Does time increment correctly even if it's the wrong time? If you reset the board, does time carry on incrementing or does it seem to reset to an earlier time?

What do you see if you print out the time held in now in setup? Does that make sense?

The time and date are still in the correct formats, but just incorrect (wrong day, month, year and wrong hour/minute). When I add a print function to print to the serial monitor, it prints the correct time and date!

Ok, so the time from the RTC is correct.

In your sd_card() function, if you print out the time from getDateTime() and also the contents of dataString (once you've populated it), do they agree or is getDateTime() right and dataString wrong?

I don't use the String type myself, preferring to use a straight char array and the strcpy/strncpy, strcat/strncat type functions. I also make use of the sprintf function which I think will work nicely for you instead of using String.

Interestingly they match, but both print the incorrect date/time on the serial monitor. Could you expand on the sprintf function? I inherited this code through a coworker and have only made adjustments to keep it up to date/shape to my specific needs so unfortunately my knowledge of coding is pretty basic and centers around troubleshooting this existing code - but I would love to update it with something that may work better or be more reliable (especially as it currently isn't working). Thank you for your help - I really appreciate it!

You need to investigate further why getDateTime() is returning the wrong time/date in the sd_card() function but correctly at the start.

sprintf() is pretty much the same as printf() but it "prints" to a data array instead.

You need to define a buffer to put the output in - something like this:

char buff[32];

And then you can "print" to it like this:

sprintf(buff, "Time: %02d:%02d:%02d",now.hour(),now.minute(),now.second());

You should look up the format specifiers for printf() - those are the bits like %02d in the line above. In this case they say that I want a 2 digit integer with a leading zero (if needed). So if your time was, say, 12hr 34min 56sec, then the buffer gets filled with:

Time: 12:34:56

You need to keep track of how many characters you expect to "print" and create a buffer big enough for this.

Hi markd833,

After playing around with it for a bit, it appears the it is getting time from the internet rather than from the RTC module. When I configure the yun to my home wifi and run the code, it stamps the correct time and date to the SD card, but when the yun is not connected to wifi, it reverts back to the incorrect time and date. This makes sense as the previous times I have ran the systems I was connected to wifi, but I am in a new location now that uses eduroam, which I know is more complex to connect to, so I haven't. Looks like I need to either connect to eduroam to use the original code or alter the code to ensure its communicating with RTC properly. This was probably something that was obvious in the code - its been a steep learning curve for me! Thanks for your help.