SD card data acquisition

Hello all,

I am trying to write data from 4 pressure transducers to a microSD card using a SD shield. My code worked perfectly fine switching between high and log on pin 12 until I added commands to write to the SD card. Now the program switches between both high and low loops for pin 12 without having meet the condition in my if statements.

#include <SD.h>

File file;

void setup() 
{

// Sets analog pins to input
pinMode(A0, INPUT);
pinMode(A1, INPUT);
pinMode(A2, INPUT);
pinMode(A3, INPUT);

// Sets analog pins to input
pinMode(13, INPUT);
pinMode(12, OUTPUT); 


// Opens the serail connection
Serial.begin(250000);
SD.begin(10);

}

void loop()

{
  
unsigned long startTime;
unsigned long intreval = 2000UL; // 120 seconds
unsigned long previousInterval = 0;
unsigned long intreval1 = 5000UL; // 60 seconds
unsigned long previousInterval1 = 0;


while  (digitalRead(13) == HIGH);
file = SD.open("WR_TEST4.TXT", O_CREAT | O_WRITE);
{
      startTime = millis();
  
  for (;millis() < startTime + 2000UL;)
  {
        char tuf[10];
  digitalWrite(12, LOW);
  sprintf(tuf,"low ");
  file.print(tuf);
  dataLog();
  
  
 if (digitalRead(13) == LOW)
  {
    file.flush();
    break;
  }
  
  } 
 
  for (;millis() < startTime + 5000UL;)
   {
    char tuf1[10];
   digitalWrite(12, HIGH);
   sprintf(tuf1,"high ");
   file.print(tuf1);
   dataLog();
   file.flush();
  if (digitalRead(13) == LOW)
   {
    file.flush();
    break;
   }
   }
} 
} 
void dataLog()
{  


 char buf[100];
 char buf1[50];
 
 //Pressure transducers
 int PT1A;
 int PTT1;
 int PT1B;
 int PT1C;
 

 
   unsigned long runMillis= millis();
   unsigned long allSeconds=millis()/1000;
   int runHours= allSeconds/3600;
   int secsRemaining=allSeconds%3600;
   int runMinutes=secsRemaining/60;
   int runSeconds=secsRemaining%60;

   // Sets values of incoming analog pin data to transducer nnumbers
   PT1A = analogRead(A0); // Reads data from analog pin A0
   PTT1 = analogRead(A1); // Reads data from analog pin A1
   PT1B = analogRead(A2); // Reads data from analog pin A2
   PT1C = analogRead(A3); // Reads data from analog pin A3

 
   sprintf(buf,"Runtime %02d:%02d:%02d ",runHours, runMinutes, 
            runSeconds);
   sprintf(buf1,"PT1A: %d; PTT1: %d; PT1B: %d; PT1C: %d", PT1A, PTT1, PT1B, PT1C);   
   
   
   file.print(buf);
   file.println(buf1);
   
}

Use CTRL T to format the sketch.
Please use code tags.
Use the </> icon in the posting menu.

[code] Paste sketch here. [/code]

for (;millis() < startTime + 2000UL;)
Did you want to use:
if (millis() < startTime + 2000UL)

Suggest you make these global:
unsigned long startTime;
unsigned long intreval = 2000UL; // 120 seconds
unsigned long previousInterval = 0;
unsigned long intreval1 = 5000UL; // 60 seconds
unsigned long previousInterval1 = 0;

Essentialy I want it to run through the first for loop:

 for (;millis() < startTime + 2000UL;)

and when the condition is meet switch to the other for loop:

for (;millis() < startTime + 5000UL;)

in both loops in need the data to be written to my SD card.

My code ran just fine when I was writing to the Serial monitor.

void setup()
{

  // Sets analog pins to input
  pinMode(A0, INPUT);
  pinMode(A1, INPUT);
  pinMode(A2, INPUT);
  pinMode(A3, INPUT);

  // Sets analog pins to input
  pinMode(13, INPUT);
  pinMode(12, OUTPUT);


  // Opens the serail connection
  Serial.begin(250000);

}

void loop()

{
  unsigned long startTime;
  unsigned long intreval = 2000UL; // 120 seconds
  unsigned long previousInterval = 0;
  unsigned long intreval1 = 5000UL; // 60 seconds
  unsigned long previousInterval1 = 0;


  while  (digitalRead(13) == HIGH)
  {
    startTime = millis();

    for (; millis() < startTime + 2000UL;)
    {
      char tuf[10];
      digitalWrite(12, LOW);
      sprintf(tuf, "low ");
      Serial.print(tuf);
      dataLog();
      if (digitalRead(13) == LOW)
      {
        break;
      }

      //(digitalWrite(12) == HIGH);
      //void dataLog();
      //delay(60000);
    }

    for (; millis() < startTime + 5000UL;)
    {
      char tuf1[10];
      digitalWrite(12, HIGH);
      sprintf(tuf1, "high ");
      Serial.print(tuf1);
      dataLog();
      if (digitalRead(13) == LOW)
      {
        break;
      }
    }
  }
}


void dataLog()
{
  char buf[100];
  char buf1[50];

  //Pressure transducers
  int PT1A;
  int PTT1;
  int PT1B;
  int PT1C;



  unsigned long runMillis = millis();
  unsigned long allSeconds = millis() / 1000;
  int runHours = allSeconds / 3600;
  int secsRemaining = allSeconds % 3600;
  int runMinutes = secsRemaining / 60;
  int runSeconds = secsRemaining % 60;

  // Sets values of incoming analog pin data to transducer nnumbers
  PT1A = analogRead(A0); // Reads data from analog pin A0
  PTT1 = analogRead(A1); // Reads data from analog pin A1
  PT1B = analogRead(A2); // Reads data from analog pin A2
  PT1C = analogRead(A3); // Reads data from analog pin A3


  sprintf(buf, "Runtime%02d:%02d:%02d ", runHours, runMinutes,
          runSeconds);
  sprintf(buf1, "PT1A: %d; PTT1: %d; PT1B: %d; PT1C: %d", PT1A, PTT1, PT1B, PT1C);
  Serial.print(buf);
  Serial.println(buf1);

}

Writing to an SD card uses the SPI bus, and on the UNO, digital pins 11, 12 and 13 are used by the SPI bus. Do not use these pins for other purposes when using SPI.

After making some changes to my code everything seems to be running smoothly. The only problem I'm having now is that while pin 13 has no power the clock is still ticking. Is there a way to make it so that the clock stays at zero till pin 3 reads high.

#include <SD.h>

File file;

void setup()
{

  // Sets analog pins to input
  pinMode(A0, INPUT);
  pinMode(A1, INPUT);
  pinMode(A2, INPUT);
  pinMode(A3, INPUT);

  // Sets analog pins to input
  pinMode(3, INPUT);
  pinMode(2, OUTPUT);


  // Opens the serail connection
  Serial.begin(500000);
  SD.begin(10);
  file = SD.open("WR_TEST5.TXT", O_CREAT | O_WRITE);
  
}

void loop()

{
  unsigned long startTime = 0;
  unsigned long intreval = 2000UL; // 120 seconds
  unsigned long previousInterval = 0;
  unsigned long intreval1 = 5000UL; // 60 seconds
  unsigned long previousInterval1 = 0;

  delayMicroseconds(10);

  while  (digitalRead(3) == HIGH)
  {
    delayMicroseconds(100);
    startTime = millis();

    for (; millis() < startTime + 2000UL;)
    {
      char tuf[10];
      digitalWrite(2, LOW);
      sprintf(tuf, "low ");
      //Serial.print(tuf);
      file.print(tuf);
      dataLog();

      if (digitalRead(3) == LOW)
      {
        break;
      }

    }

    for (; millis() < startTime + 7000UL;)
    {
      char tuf1[10];
      digitalWrite(2, HIGH);
      sprintf(tuf1, "high ");
      //Serial.print(tuf1);
      file.print(tuf1);

      dataLog();


      if (digitalRead(3) == LOW)
      {
        break;
      }
    } file.flush();
  }
}


void dataLog()
{
  char buf[100];
  char buf1[50];

  //Pressure transducers
  int PT1A;
  int PTT1;
  int PT1B;
  int PT1C;



  unsigned long runMillis = millis();
  unsigned long allSeconds = millis() / 1000;
  int runHours = allSeconds / 3600;
  int secsRemaining = allSeconds % 3600;
  int runMinutes = secsRemaining / 60;
  int runSeconds = secsRemaining % 60;

  // Sets values of incoming analog pin data to transducer nnumbers
  PT1A = analogRead(A0); // Reads data from analog pin A0
  PTT1 = analogRead(A1); // Reads data from analog pin A1
  PT1B = analogRead(A2); // Reads data from analog pin A2
  PT1C = analogRead(A3); // Reads data from analog pin A3


  sprintf(buf, "Runtime%02d:%02d:%02d ", runHours, runMinutes,
          runSeconds);
  sprintf(buf1, "PT1A: %d; PTT1: %d; PT1B: %d; PT1C: %d", PT1A, PTT1, PT1B, PT1C);
  /*Serial.print(buf);
    Serial.println(buf1);*/

  file.print(buf);
  file.println(buf1);

}

Is there a way to make it so that the clock stays at zero till pin 3 reads high.

What clock?

Please explain what you are trying to achieve. The truncated for() loops (which act like while loops) within the while loop() is confusing. What do you want to log, and when do you want to log it?

It appears that you are sd logging the word "low" for two seconds as fast as,you can, and then some data, and then sd logging the word "high" for another 5 seconds and then some data with accumulated run time.

What is connected to pin3 and pin 2?

The millis() clock starts at run time, and timing is usually handled by subtraction. The value of millis() can not stay at 0 or be reset to 0 while the program is running.

I am logging data from 4 pressure transducers. The for loops are being used to toggle on and off a valve, which is connected to pin 2, while the data is being logged. The words "low" and "high" are being logged to the sd card to help me know if the valve was on or off when the data was logged. I am also printing at what time the data was logged, for instance:

low Runtime00:00:01 PT1A: 706; PTT1: 944; PT1B: 760; PT1C: 926

Pin 3 is being used to start the data logger. I have found if there is now power on the pin during initial start up, when power is applied the data logger will log that data from that clock time in the arduino. I require the data to be logged with a starting time of 00:00:00 when power is applied to pin 3.

I require the data to be logged with a starting time of 00:00:00 when power is applied to pin 3.

I have added some variables and code to record the first time when pin 3 goes HIGH. Then, the timeZeroMillis value is later subtracted from runMillis.

#include <SD.h>

File file;

boolean recordTimeZero = true;
unsigned long timeZeroMillis;

void setup()
{

  // Sets analog pins to input
  pinMode(A0, INPUT);
  pinMode(A1, INPUT);
  pinMode(A2, INPUT);
  pinMode(A3, INPUT);

  // Sets analog pins to input
  pinMode(3, INPUT);
  pinMode(2, OUTPUT);


  // Opens the serial connection
  Serial.begin(500000);
  SD.begin(10);
  file = SD.open("WR_TEST5.TXT", O_CREAT | O_WRITE);

}

void loop()

{
  unsigned long startTime = 0;
  unsigned long intreval = 2000UL; // 120 seconds
  unsigned long previousInterval = 0;
  unsigned long intreval1 = 5000UL; // 60 seconds
  unsigned long previousInterval1 = 0;

  delayMicroseconds(10);

  while  (digitalRead(3) == HIGH)
  {
    delayMicroseconds(100);
    startTime = millis();
    if (recordTimeZero)
    {
      recordTimeZero = false;
      timeZeroMillis = startTime;
    }

    for (; millis() < startTime + 2000UL;)
    {
      char tuf[10];
      digitalWrite(2, LOW);
      sprintf(tuf, "low ");
      //Serial.print(tuf);
      file.print(tuf);
      dataLog();

      if (digitalRead(3) == LOW)
      {
        break;
      }

    }

    for (; millis() < startTime + 7000UL;)
    {
      char tuf1[10];
      digitalWrite(2, HIGH);
      sprintf(tuf1, "high ");
      //Serial.print(tuf1);
      file.print(tuf1);

      dataLog();


      if (digitalRead(3) == LOW)
      {
        break;
      }
    } file.flush();
  }
}

void dataLog()
{
  char buf[100];
  char buf1[50];

  //Pressure transducers
  int PT1A;
  int PTT1;
  int PT1B;
  int PT1C;

  unsigned long runMillis = millis() - timeZeroMillis;
  //unsigned long allSeconds = (millis() / 1000;
  unsigned long allSeconds = runMillis / 1000;
  int runHours = allSeconds / 3600;
  int secsRemaining = allSeconds % 3600;
  int runMinutes = secsRemaining / 60;
  int runSeconds = secsRemaining % 60;

  // Sets values of incoming analog pin data to transducer nnumbers
  PT1A = analogRead(A0); // Reads data from analog pin A0
  PTT1 = analogRead(A1); // Reads data from analog pin A1
  PT1B = analogRead(A2); // Reads data from analog pin A2
  PT1C = analogRead(A3); // Reads data from analog pin A3

  sprintf(buf, "Runtime%02d:%02d:%02d ", runHours, runMinutes,
          runSeconds);
  sprintf(buf1, "PT1A: %d; PTT1: %d; PT1B: %d; PT1C: %d", PT1A, PTT1, PT1B, PT1C);
  /*Serial.print(buf);
    Serial.println(buf1);*/

  file.print(buf);
  file.println(buf1);

}

EDIT: I'm not clear on what is controlling pin 3 and if there are indeed breaks and resumptions of the data recording. If you want to reset the time after a break, then set recordTimeZero back to true when pin 3 goes low and the break occurs.

cattledog:
EDIT: I'm not clear on what is controlling pin 3 and if there are indeed breaks and resumptions of the data recording. If you want to reset the time after a break, then set recordTimeZero back to true when pin 3 goes low and the break occurs.

Thank you so much catteldog for all your help so far. I am fairly new to arduino and have been a bit lost. The changes you made work exactly how I need it to. Pin 3 is taking a reading from the first valve to see if it has power. If the first valve in the sequence has power then the test has commenced. If there is now power to pin 3 then the program stops. Now I'm just working on having the data be written to a txt file to the pc after each cycle for 1/2 a second.

I am trying to get my program to not only print to the SD card but to also print to the serial monitor/gobetwino. I keep getting mixed results. At this point it keeps just printing high to the serial monitor when it should be in the printing low and it never seems to print low at all. The high and low means that the valve im using is in the on(high) off(low) position. The txt file never prints high or low next to the Run Time at all.

#include <SD.h>

File file;

//void dataLog(char buf[], char buf1[]);


boolean recordTimeZero = true;
unsigned long timeZeroMillis;

void setup()
{

  // Sets analog pins to input
  pinMode(A0, INPUT);
  pinMode(A1, INPUT);
  pinMode(A2, INPUT);
  pinMode(A3, INPUT);

  // Sets analog pins to input
  pinMode(3, INPUT);
  pinMode(2, OUTPUT);

  // Opens the serial connection
  Serial.begin(500000);
  SD.begin(10);
  file = SD.open("WR_TEST5.TXT", O_CREAT | O_WRITE);

}

void loop()
{
  unsigned long startTime = 0;
  //unsigned long intreval = 2000UL; // 120 seconds
  unsigned long previousInterval = 0;
  //unsigned long intreval1 = 5000UL; // 60 seconds
  unsigned long previousInterval1 = 0;

  //char tuf[10] = "low";
  //char tuf1[10] = "high";

  delayMicroseconds(10);

  while  (digitalRead(3) == HIGH)
  {

    startTime = millis();
    if (recordTimeZero)
    {
      recordTimeZero = false;
      timeZeroMillis = startTime;
    }

    for (; millis() < startTime + 2000UL;)
    {
      char tuf[10];
      //digitalWrite(2, LOW);
      //sprintf(tuf, "low ");
      if (millis() < startTime + 1000UL)
      {
        //digitalWrite(2, LOW);
        //sprintf(tuf, "low ");
        //Serial.print(tuf);
        dataLog();
      }
      else if (millis() < startTime + 2000UL)
      {
        digitalWrite(2, LOW);
        sprintf(tuf, "low ");
        file.print(tuf);
        dataLog();
      }
      else if (digitalRead(3) == LOW)
      {
        break;
      }

    }

    for (; millis() < startTime + 5000UL;)
    {
      char tuf1[10];
      //digitalWrite(2, HIGH);
      //sprintf(tuf1, "High ");
      if (millis() < startTime + 3000UL)
      {
        digitalWrite(2, HIGH);
        sprintf(tuf1, "High ");
        Serial.print(tuf1);
        dataLog();
      }
      else if (millis() < startTime + 5000UL)
      {
        digitalWrite(2, HIGH);
        sprintf(tuf1, "High ");
        file.print(tuf1);
        dataLog();
      }
      else if (digitalRead(3) == LOW)
      {
        break;
      }

    } file.flush();
  }
}

void dataLog()
{

  char tuf1[10];
  char tuf2[10];
  
  char buf1[50];
  char buf2[100];


  unsigned long runMillis = millis() - timeZeroMillis;
  unsigned long allSeconds = runMillis / 1000;
  int runHours = allSeconds / 3600;
  int secsRemaining = allSeconds % 3600;
  int runMinutes = secsRemaining / 60;
  int runSeconds = secsRemaining % 60;

  int PT1A;
  int PTT1;
  int PT1B;
  int PT1C;

  // Sets values of incoming analog pin data to transducer nnumbers
  PT1A = analogRead(A0); // Reads data from analog pin A0
  PTT1 = analogRead(A1); // Reads data from analog pin A1
  PT1B = analogRead(A2); // Reads data from analog pin A2
  PT1C = analogRead(A3); // Reads data from analog pin A3

  sprintf(buf1, "Runtime%02d:%02d:%02d ", runHours, runMinutes,
          runSeconds);

  sprintf(buf2, "PT1A: %d; PTT1: %d; PT1B: %d; PT1C: %d", PT1A, PTT1, PT1B, PT1C);

  for (; millis() < runMillis + 2000UL;)
  {
    if (millis() < runMillis + 1000UL)
    {
      digitalWrite(2, LOW);
      sprintf(tuf1, "low ");

      Serial.print(tuf1);
      Serial.print(buf1);
      Serial.println(buf2);
    }
    else if (millis() < runMillis + 2000UL)
    {
      digitalWrite(2, LOW);
      sprintf(tuf1, "low ");

      file.print(tuf1);
      file.print(buf1);
      file.println(buf2);
    }
  }

  for (; millis() < runMillis + 5000UL;)
  {
    if (millis() < runMillis + 3000UL)
    {
      digitalWrite(2, HIGH);
      sprintf(tuf2, "high ");

      Serial.print(tuf2);
      Serial.print(buf1);
      Serial.println(buf2);
    }
    else if (millis() < runMillis + 5000UL)
    {
      digitalWrite(2, HIGH);
      sprintf(tuf2, "high ");
      file.print(buf1);
      file.println(buf2);
    }
  }
}

Anyone have any ideas what I could try, or point me in the right direction?

Walk through your program step by step, perhaps using a pencil and paper to figure out where you are. The only part of loop which meets the millis() based truncated "for" loop criteria is up to the first call of dataLog().

You have basically duplicated the loop structure within dataLog() with the "for" loops which are the equivalent of "while" loops. Compare the code in dataLog() post#7 and post #9.

The first time you call dataLog() the millis() based "for" loops within that function use up all the time, and no code in loop() runs after the return to loop() from the first call to dataLog().

I think that you need to remove the timing from dataLog(), and just use it to write SD and serial output. Let the millis() based "for" loops in loop() control the timing.

The use of the truncated "for" loops for timing is very idiosyncratic. Why are you not using the more common "while" loop?

I'm not sure where your program is headed, but the blocking architecture may prove to be a problem down the road. Restructuring the program at this point is probably not worth doing if you were happy with the running version in #7 and its just a matter of working in the Serial and SD logging.

R1c4rd:

    for (; millis() < startTime + 2000UL;)

[...]
    for (; millis() < startTime + 7000UL;)

Change this to:

    for (millis() - startTime < 2000UL)
[...]
    for (millis() - startTime < 7000UL)

This way overflows are handled transparently (thanks to this being unsigned integers). Your code may get stuck after about 49 days, when millis() overflows.

I want to thank you all for your help. My program works fine now. I am now trying to find a way to convert the analog reading from my sensors, PT1A PTT1 PT1B PT1C , to PSI. I have included a link to the data sheet below. I am currently using 5Vdc for the supply voltage and the nominal output transfer function 5Vdc supply, the parameter is 0.5Vdc to 4.5Vdc (ratiometric to supply). Any one have any idea how i would go about converitng the an analog reading of, for instance, 114 to psi?

Sensor data sheet

  1. get the (factory calibrated) values from the data sheet of your sensor.

  2. calibrate yourself: apply known pressure to the sensor, take reading, use those measurements to calculate unknown pressure from the reading.

I am trying to convert the analog data coming from the pressure to voltage. The parameters should be 0.5Vdc to 4.5Vdc. The code I've uploaded has all the sensor data coming in as int.

void dataLog()
{
  char buf1[200];

  //Pressure transducers
  int PT1A;
  int PTT1;
  int PT1B;
  int PT1C;

  float vPT1A = 0.0;
  float vPTT1 = 0.0;
  float vPT1B = 0.0;
  float vPT1C = 0.0;

  // Sets values of incoming analog pin data to transducer numbers
  PT1A = analogRead(A0); // Reads data from analog pin A0
  PTT1 = analogRead(A1); // Reads data from analog pin A1
  PT1B = analogRead(A2); // Reads data from analog pin A2
  PT1C = analogRead(A3); // Reads data from analog pin A3


// Converts analog data to Vdc
  vPT1A = PT1A * (5.0 / 1023.0);
  vPTT1 = PTT1 * (5.0 / 1023.0);
  vPT1B = PT1B * (5.0 / 1023.0);
  vPT1C = PT1C * (5.0 / 1023.0);

  sprintf(buf1, "PT1A: %.2f; PTT1: %.2f; PT1B: %.2f; PT1C: %.2f",
          vPT1A, vPTT1, vPT1B, vPT1C);


  Serial.println(buf1);

}

With the current format above i get ? instead of numbers/data. I have also tried changing my variables from floats to doubles. The only thing that seems to work is changing

from:

  double vPT1A = 0.0;
  double vPTT1 = 0.0;
  double vPT1B = 0.0;
  double vPT1C = 0.0;

to:

  int vPT1A = 0.0;
  int vPTT1 = 0.0;
  int vPT1B = 0.0;
  int vPT1C = 0.0;

But even then the decimal becomes truncated making the data useless if the Vdc drops below 1.0. Seeing as the parameters should be 0.5Vdc to 4.5Vdc this causes a major issue. Can can anyone help point me in the right direction

for anyone that is interested, I couldn't get the floats to print to my char string without them comming out trunkated or unusful. I ended up having to print the strings seperatly from the floats.

void dataLog()
{
  char buf1[200];

  //Pressure transducers
  int PT1A;
  int PTT1;
  int PT1B;
  int PT1C;

  // Sets values of incoming analog pin data to transducer numbers
  PT1A = analogRead(A0); // Reads data from analog pin A0
  PTT1 = analogRead(A1); // Reads data from analog pin A1
  PT1B = analogRead(A2); // Reads data from analog pin A2
  PT1C = analogRead(A3); // Reads data from analog pin A3

  // Converts analog data to Vdc
  float vPT1A = PT1A * (5.0 / 1023.0);
  float vPTT1 = PTT1 * (5.0 / 1023.0);
  float vPT1B = PT1B * (5.0 / 1023.0);
  float vPT1C = PT1C * (5.0 / 1023.0);

  sprintf(buf1, "PT1A: ; PTT1: ; PT1B: ; PT1C: ",
          vPT1A, vPTT1, vPT1B, vPT1C);

  Serial.print("PT1A: ");
  Serial.print(vPT1A);
  Serial.print("; PTT1: ");
  Serial.print(vPTT1);
  Serial.print("; PT1B: ");
  Serial.print(vPT1B);
  Serial.print("; PT1C: ");
  Serial.println(vPT1C);
}

Serial.print() by default truncates floats at two decimals.
If you want more control and formatting when converting values to strings for printing, look at the printf(), sprinf() and snprintf() functions.

sprintf on the Arduino with he standard ide does not support floats.

would anyone know why the analog data coming in from the analog pins jumps around so much even when there is a steady stream of voltage being applied? For instance I'm giving it 1.5 volts and the readings from the pin are jumping from 20 up to 153 and back down.

For instance I'm giving it 1.5 volts and the readings from the pin are jumping from 20 up to 153 and back down.

Those numbers are not consistent with the value you should see: 1.5/5 * 1023 = 307. It looks like something is not properly connected.

Can you provide some information on the pressure sensors, and how you have them connected to the arduino and power?

Is the arduino ground connected to the sensor ground?