Writing data to an SD card without the Serial Monitor

Hello all!

I am having a bit of a trouble with my project. I connected a SD module to a small circuit and combined two sketches to get the sketch I needed. The strange thing however is that the arduino only writes data to the SD card when the serial monitor is opened. If the serial monitor is not opened while the programm is running the SD card will remain empty. I will eventually have to disconnect the circuit from the computer and make it as small as possible so that is why this problem really buggs me.
I double checked everything and even got some help from more experienced people at my University but they too were not able to fix my problem. My guess is that there is some kind of bug in the standard library that is included in the sketch (SD.h) , I already tried an updated library (SDFat) but unfortunately that was a bit too complicated for me to comprehend because it used more advanced coding in the Arduino IDE.
The problem is either in something so simple that I somehow do not see it or, more likely, it is just a bug in the library.
I really hope that some of you can help me out! thanks for replying:)

Picture of my set up:

This is my code (the problem also occurs with the default SD sketch):

#include <SD.h>

const int chipSelect = 4;

int inPinSwitch = 3;
int outPinLED = 2;

int stateLED = LOW;
int reading;
int previous = HIGH;

long time = 0;
long debounce = 200;

void setup()
{
pinMode(inPinSwitch, INPUT);
pinMode(outPinLED, OUTPUT);

Serial.begin(9600);
while (!Serial) {
;
}

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

pinMode(10, OUTPUT);

if (!SD.begin(chipSelect)) {
Serial.println("Card failed, or not present");

return;
}
Serial.println("card initialized.");

}

void loop()
{
reading = digitalRead(inPinSwitch);

if (reading == HIGH && previous == LOW && millis() - time > debounce) {
if (stateLED == HIGH)
{
stateLED = LOW;
}
else

stateLED = HIGH;

time = millis();
};

if (stateLED == HIGH)
{

String dataString = "";

for (int analogPin = 0; analogPin < 2; analogPin++) {
int sensor = analogRead(analogPin);
dataString += String(sensor);
if (analogPin < 1) {
dataString += ",";
}
}

File dataFile = SD.open("datalog.txt", FILE_WRITE);

if (dataFile) {
dataFile.println(dataString);
dataFile.close();
Serial.println(dataString);
}

else {
Serial.println("error opening datalog.txt");
};

delay(250);
}

digitalWrite(outPinLED, stateLED);

previous = reading;
}

What is this for?

  while (!Serial) {
    ; 
  }

Thanks for the fast reply!
It is in the standard SD sketch and only needed for the leonardo, it has no further function for the Arduino Uno.

Quote from the sketch:

// wait for serial port to connect. Needed for Leonardo only

more likely, it is just a bug in the library.

Not that libraries can't have bugs but actually that's the last place to look, the problem is always in your new code.

only needed for the leonardo

Is this code running on a Leonardo?


Rob

I am using the Arduino Uno but removing that line from the code does not have any effect on the problem;)

It would be nice to get some debugging output-do you have another arduino you can use softwareserial to talk to and have that one echo to the terminal?

Hmm, the serial monitor should have no bearing on writing to the SD card, opening it will reset the Arduino but apart from that once it's open the Arduino wouldn't know if it was there or not.

How do you verify what's on (or not on) the card?


Rob

The LED behaviour ought to make it clear whether your sketch is actually running - can you confirm that it is?

I suggest you add some diagnostic output in the 'SD error' cases, for example by blinking in LED in an obviously recognisable sequence (and make them unique). All it needs is a blocking function which loops through the appropriate number of on/off transitions with delays in between - it doesn't need to impact the structure of your sketch at all.

Given that you also see the problem with the standard sketches, and there's nothing in your logic which would make the SD output depend on the serial port, I suspect you have a hardware problem. The most likely cause I can think of is that the power supply is not providing adequate voltage or current. How are you powering it, and what voltage are you actually getting on the 5V rail?

Thanks for all the replies guys,

@Graynomad: I check whats on the card by just opening it with my laptop and checking if there is new data in the datalogger.txt, that is how I noticed that it only writes data to the SD card when the serial monitor is opened.

@PeterH: I tried what you suggested and no error was given, the voltage that is going through the rail is around 4.92 volts

Update:
I noticed something strange again, it did help me get further. As you can see in the code I made it so the writing of the data starts when the button is pressed and the LED goes on.
Resetting (pressing the resetbutton on the board) the arduino AFTER the LED is on causes the arduino to write the data to the file on the SD card (actually exactly the same as the serial monitor was doing). In other words: it works now, but only if I reset it after I press the button for the LED, there must be a more optimal way.
I think I am just not using the right code, does any of you know how I could get a better result with another code?

Opening the serial monitor causes the board to reset too, so it seems as if some part of your initialisation may not be working after the initial power up. Maybe the SD hardware needs a moment to initialise before it is ready to handle commands? You could test that theory by putting a fixed delay e.g. 100 ms at the start of setup().

I put a delay at the start of the void setup() as you instructed and tried it with several values but it did not work :confused:
It really only works if I press the resetbutton first, is there any way I could get te same result with the pins on the arduino and the software?

After you have the code loaded on the arduino, put a 100 ohm resistor between the arduino reset pin and 5v pin to defeat the serial port open/close reset and see if that makes a difference.

That too did not work. I am really starting to wonder if there is a solution here, any other tips?

I'd try to make progress by seeing which execution path is being followed. As I suggested, you can use another arduino as a proxy to send debug data to a serial terminal . If you don't, or that's causing issues too, use some leds to indicate where you are in the code.

I fixed it! not in the most optimal way but it works now, the data is written to the SD card without usage of the Serial Monitor. Now I can finally use the circuit without the computer.

It was a software 'problem' and this is my code now (more info below):

#include <SD.h>

const int chipSelect = 4;

int inPin = 3; // the number of the input pin
int outPin = 2; // the number of the output pin

int stateLED = LOW; // the current state of the output pin
int reading; // the current reading from the input pin
int previous = HIGH; // the previous reading from the input pin

// the follow variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long time = 0; // the last time the output pin was toggled
long debounce = 200; // the debounce time, increase if the output flickers

void setup()
{
// Open serial communications and wait for port to open:
Serial.begin(9600);
pinMode(inPin, INPUT);
pinMode(outPin, OUTPUT);
}

void loop()
{

reading = digitalRead(inPin);

// if the input just went from LOW and HIGH and we've waited long enough
// to ignore any noise on the circuit, toggle the output pin and remember
// the time
if (reading == HIGH && previous == LOW && millis() - time > debounce) {
if (stateLED == HIGH)
stateLED = LOW;
else
stateLED = HIGH;

time = millis();
}

digitalWrite(outPin, stateLED);

previous = reading;

if (stateLED == HIGH)
{
// Open serial communications and wait for port to open:
Serial.begin(9600);

//Serial.print("Initializing SD card...");
// make sure that the default chip select pin is set to
// output, even if you don't use it:
pinMode(10, OUTPUT);

// see if the card is present and can be initialized:
if (!SD.begin(chipSelect)) {
//Serial.println("Card failed, or not present");
// don't do anything more:
//return;
}
//Serial.println("card initialized.");

// make a string for assembling the data to log:
String dataString = "";

// read three sensors and append to the string:
for (int analogPin = 0; analogPin < 2; analogPin++) {
int sensor = analogRead(analogPin);
dataString += String(sensor);
if (analogPin < 1) {
dataString += ",";
}
}

// open the file. note that only one file can be open at a time,
// so you have to close this one before opening another.
File dataFile = SD.open("datalog.txt", FILE_WRITE);

// if the file is available, write to it:
if (dataFile) {
dataFile.println(dataString);
dataFile.close();
// print to the serial port too:
Serial.println(dataString);
}
// if the file isn't open, pop up an error:
else {
Serial.println("error opening datalog.txt");
}
delay(250);
}
}

As you can see I placed the largest part of the original standard code from the SD datalogger sketch from the void setup() in the void loop(), i then eliminated the debugging data since that was no longer important in the void loop() and especially I deleted the return command since that would make the entire sketch return to the start.

Big thanks to wildbill, because of his tips i found out where the problem was.

The problem was that that for my specific code certain parts have to be looped while this isnt necessary (or happens automatically) in the standard SD datalogger code. So therefore i placed the serial.begin(9600) and some additional and experimental code in the void.loop()

Yep, i am not entirely sure if my theory behind this fix is correct but whatever, it works.
Tnx for all your replies!