unexpected format of data written to SD card

(I’m waiting on an RTC to include a real world time stamp but for the time being/testing I am brute forcing a timer.)

I’m writing three analog inputs (temp, pH & OD) to an SD card. I want a time stamp, the data type and the sensor reading all on the same line but what I’m getting is “: :” then the data type & reading.

I came across the following code that isn’t just converting millis() into MM/DD/HH/MM but rather has an actual time stamp. I’d prefer to stick to this method since it’ll make data analysis a little less tedious once I’m utilizing a RTC.

#include "wiring.c"

const int Adjust = 8;

void SetMillis () {
  char T[] = __TIME__;
  uint8_t oldSREG = SREG;
  cli();
  unsigned long temp = (unsigned long)((T[0]*10+T[1]-528)*60+T[3]*10+T[4]-528)*60
    +T[6]*10+T[7]-528+Adjust;
  timer0_millis = (unsigned long)temp*1000;
  SREG = oldSREG;
}

void setup() {
  SetMillis();
  // initialize serial communication
  Serial.begin(9600);
}

// Add a leading zero when necessary
void Print2 (int n) {
  if (n<10) Serial.print('0');
  Serial.print(n);
}

void loop() {
  // Demonstrate clock
  unsigned long Now = millis()/1000;
  int Seconds = Now%60;
  int Minutes = (Now/60)%60;
  int Hours = (Now/3600)%24;
  Print2(Hours); Serial.print(':'); 
  Print2(Minutes); Serial.print(':'); 
  Print2(Seconds); Serial.println();
  delay(1000);
}

My code (with the above code included) is as follows:

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

File myFile;

#define TEMP_INTERVAL             18000ul   // 30min      
#define OD_INTERVAL               18000ul   // 30min      
#define PH_INTERVAL               12000ul   // 20min      
#define PH_CO2_ADD_INTERVAL       60000ul     // 1min  
#define PH_CO2_CHECK_INTERVAL     600000ul    // 10min


// * * * * pH ADDED * * * *
unsigned long int avgValue;   //Store the average value of the sensor feedback
float b;
int buf[10], temp;

// Optical Density Sensor
const byte OD_Probe          = A5;   //
const byte Temp_Probe        = A0;   //
const byte pH_Probe          = A4;   //
const byte CO2_GateValve     = 3;
const byte pH_HIGH_THRESHOLD = 16.00;

unsigned long timeOD;
unsigned long timepH;
unsigned long timeTemp;
unsigned long timeCo2Add;
unsigned long timeCo2Chk;
unsigned long timeNow;

enum { ST_INIT, ST_ADD, ST_CHK };
int state;

#include "wiring.c"

const int Adjust = 8;

void SetMillis () {
  char T[] = __TIME__;
  uint8_t oldSREG = SREG;
  cli();
  unsigned long temp = (unsigned long)((T[0] * 10 + T[1] - 528) * 60 + T[3] * 10 + T[4] - 528) * 60
                       + T[6] * 10 + T[7] - 528 + Adjust;
  timer0_millis = (unsigned long)temp * 1000;
  SREG = oldSREG;
}

// -----------------------------------------------------------------------------
void setup () {
  Serial.begin (9600);

  Serial.print("Initializing SD card...");
  pinMode(10, OUTPUT);
  if (!SD.begin(4)) {
    Serial.println("Initialization failed!");
    return;
  }
  Serial.println("Initialization done.");
  myFile = SD.open("08112020.txt", FILE_WRITE);

  if (myFile) {
    Serial.print("Writing to 08112020.txt...");
    // myFile.println("testing 1, 2, 3.");
    myFile.close();
    Serial.println("done.");
  } else {
    Serial.println("error opening 08112020.txt");
  }

  myFile = SD.open("08112020.txt");
  if (myFile) {
    Serial.println("08112020.txt");
    while (myFile.available()) {
      Serial.write(myFile.read());
    }
    myFile.close();
  } else {
    Serial.println("error opening 08112020.txt");
  }

  pinMode (OD_Probe, INPUT);
  pinMode (CO2_GateValve, OUTPUT);
  pinMode (Temp_Probe, INPUT);
  pinMode (pH_Probe, INPUT);

  timeNow  = millis ();
  timeOD   = timeNow;
  timepH   = timeNow;
  timeTemp = timeNow;

  SetMillis();

}

// Add a leading zero when necessary
void Print2 (int n) {
  if (n < 10) Serial.print('0');
  Serial.print(n);

}

void loop ()
{
  timeNow  = millis ();
unsigned long Now = millis()/1000;
  // -----------------------------------------------------------------------------

  // * * * * * Temp INTERVAL * * * * *

  if ((timeNow - timeTemp) >= TEMP_INTERVAL)
  {
    timeTemp = timeNow;
    int temp_Val = analogRead (Temp_Probe);

    myFile = SD.open("08112020.txt", FILE_WRITE);
    unsigned long Now = millis() / 1000;
    int Seconds = Now % 60;
    int Minutes = (Now / 60) % 60;
    int Hours = (Now / 3600) % 24;
    Print2(Hours); myFile.print(":");
    Print2(Minutes); myFile.print(":");
    Print2(Seconds); myFile.println();
    myFile.print(" Temp: ");
    myFile.println(((temp_Val) - 500) / 10);
    Serial.print("Temp: ");
    Serial.println(((temp_Val) - 500) / 10);
    myFile.close();
  }

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

  // * * * * * OD INTERVAL * * * * *

  if ((timeNow - timeOD) >= OD_INTERVAL)
  {
    timeOD     = timeNow;
    int od_Val = analogRead (OD_Probe);

    myFile = SD.open("08112020.txt", FILE_WRITE);
    unsigned long Now = millis() / 1000;
    int Seconds = Now % 60;
    int Minutes = (Now / 60) % 60;
    int Hours = (Now / 3600) % 24;
    Print2(Hours); myFile.print(":");
    Print2(Minutes); myFile.print(":");
    Print2(Seconds); myFile.println();
    myFile.print(" OD: ");
    myFile.println(od_Val);
    Serial.print("OD: ");
    Serial.println(od_Val);
    myFile.close();
  }

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

  // * * * * * pH INTERVAL * * * * *

  if ((timeNow - timepH) >= PH_INTERVAL)
  {
    int pH_Val;

    switch (state)  {
      case ST_INIT:

        for (int i = 0; i < 10; i++) //Get 10 sample value from the sensor for smooth the value
        {
          buf[i] = analogRead(pH_Probe);
          delay(10);
        }
        for (int i = 0; i < 9; i++) //sort the analog from small to large
        {
          for (int j = i + 1; j < 10; j++)
          {
            if (buf[i] > buf[j])
            {
              temp = buf[i];
              buf[i] = buf[j];
              buf[j] = temp;
            }
          }
        }
        avgValue = 0;
        for (int i = 2; i < 8; i++)               //take the average value of 6 center sample
          avgValue += buf[i];
        float pH_Val = (float)avgValue * 5.0 / 1024 / 6; //convert the analog into millivolt
        pH_Val = 3.5 * pH_Val;                  //convert the millivolt into pH value


        myFile = SD.open("08112020.txt", FILE_WRITE);
        unsigned long Now = millis() / 1000;
        int Seconds = Now % 60;
        int Minutes = (Now / 60) % 60;
        int Hours = (Now / 3600) % 24;
        Print2(Hours); myFile.print(':');
        Print2(Minutes); myFile.print(':');
        Print2(Seconds); myFile.println();
        myFile.print(" pH: ");
        myFile.println(pH_Val);
        Serial.print("pH: ");
        Serial.println(pH_Val);
        myFile.close();

        if (pH_Val >= pH_HIGH_THRESHOLD)  {
          state = ST_ADD;
          timeCo2Add = timeNow;
          timeCo2Chk = timeNow;

          digitalWrite (CO2_GateValve, LOW);
        }
        else
          timepH = timeNow;
        break;

      case ST_ADD:
        if ((timeNow - timeCo2Add) >= PH_CO2_ADD_INTERVAL)  {
          state = ST_CHK;
          digitalWrite (CO2_GateValve, HIGH);
        }
        break;


      case ST_CHK:
      default:
        if ((timeNow - timeCo2Chk) >= PH_CO2_CHECK_INTERVAL)  {
          state  = ST_INIT;
          timepH = timeNow;
        }
        break;
    }
  }
}

What is being written to the SD card is:
::
Temp: 52
::
OD: 480
::
pH: 15.10

I know there will be some drift in the timing but since this is only until I implement the RTC I don’t see a need to worry about it. I’m hoping/guessing my mistake in including the timestamp code is a simply fix but that may be my naivety.

That is really the hard way to emulate a clock when the Time library does it so easily.

The reason you see "::" in the file is that Print2 output goes to the serial monitor.

    Print2(Hours); myFile.print(":");
    Print2(Minutes); myFile.print(":");

+1 for the time library (TimeLib.h)

Change ‘Print2()’ to this:

// Add a leading zero when necessary
void Print2 (Stream &s, int n)
{
  if (n < 10) s.print('0');
  s.print(n);
}

Now you can pass Serial or myFile as the first argument to Print2() to get the text where you want it.

johnwasser:
Change ‘Print2()’ to this:

// Add a leading zero when necessary

void Print2 (Stream &s, int n)
{
  if (n < 10) s.print(‘0’);
  s.print(n);
}



Now you can pass Serial or myFile as the first argument to Print2() to get the text where you want it.

Thank you, will give this a try.