DS3231 RTC library and difficult to format CSV file time/date in column

Dear all,

I am reading data from a sensor and sending the data to readings.csv file on the SD card.
For the clock I am using the library DS3231 from this website:
http://www.rinkydinkelectronics.com/library.php?id=73
For the SD card I am using the standard SD.h library in the IDE.

I read the documentation of the RTC and I have 2 difficulties:

  1. I am not able to get separately the value of year, month, day, hour, minutes, sec but I can get them all together like 08:43:40 or 11.01.20
  2. The character ("\t") is not recognised. I mean, I am trying to use that in order to write to the next cell on CSV file horizontally.

I am able to write to the following line trough println instruction and it works fine.

Any help or suggestions will be really appreciated.

The part of the code of interest is:

// If the file opened OK, write to it on SD card
lcd.clear();
if (readings) 
  {
    lcd.print("file OPEN");
    delay(1000);
readings.print(rtc.getMonthStr());
readings.print("\t");
readings.print(rtc.getTimeStr());
readings.print("\t");
readings.print(rtc.getDateStr());
//readings.print(\t);
//readings.print(h);
//readings.print(\t);
//readings.print(m);
//readings.print(\t);
//readings.print(s);
//readings.print(\t);
readings.print(t);
readings.print("\t"); // Prints a TAB
readings.println(h); // Prints the value specified and RETURN
    // close the file:
    readings.close();
    lcd.clear();
    lcd.println("file CLOSE");
    delay(1000);
  } 
  else 
  {
    // if the file didn't open, print an error:
    lcd.println("file not open");
    delay(4000);
  }

The full code is:

// Libraries
  #include <dht.h> // Includes the libraries for the sensor
  #include <LiquidCrystal.h> // Includes the libraries for the LCD
  #include <DS3231.h>; // Includes the libraries for the clock
  #include <SPI.h>; // Includes the libraries for the Serial Peripheral Interface that allows the Master (Arduino) to control a slave device
  #include <SD.h>; // Includes the libraries for the SD card
// Interface and Objects definitions
  DS3231 rtc(SDA, SCL); // Initialises the DS3231 using the hardware interface
  #define dataPin 2 // Defines pin number to which the sensor is connected (avoid D4-9 and A0 used by LCD)
  dht DHT; // Creates a DHT object
  LiquidCrystal lcd(8,9,4,5,6,7); // Creates a LCD LiquidCrystal object
  const int chipSelect = 10; // Assigns the pin for the SPI-SD chip selection
  
void setup() 
{
  pinMode(chipSelect, OUTPUT); // Ensures that the SPI-SD selection pin is an output
  rtc.begin(); // Initialises the rtc object
  // rtc.setDOW(TUESDAY); // Sets Day-of-Week to TUESDAY
  // rtc.setTime(15, 46, 05); // Sets the time to 12:00:00 (24hr format)
  // rtc.setDate(10, 1, 2017); // Sets the date to January 1st, 2017
  lcd.begin(16, 2); // Initialises the interface to the LCD screen, and specifies the dimensions
  lcd.print("Initialising SD");
  delay (2000);
  lcd.clear();
    if (!SD.begin(chipSelect)) 
    {
      lcd.println("SD failed!");
      return;
    }
    lcd.println("SD OK");
    delay(2000);
    lcd.clear();
  lcd.print("Reading sensor"); // Prints to the LCD
  delay (4000); // Waits 4 seconds
}

void loop() 
{
// Open the file on the SD card
  delay(2000);
  File readings = SD.open("readings.txt", FILE_WRITE); 
// Reading the data
  int readData = DHT.read22(dataPin); // Reads the data from the sensor
  float t = DHT.temperature; // Gets the values of the temperature
  float h = DHT.humidity; // Gets the values of the humidity
// Check if any reads failed and exit early (to try again).
    if (isnan(h) || isnan(t))
    {
      lcd.println("DHT FAIL!");
      return;
    }
// If the file opened OK, write to it on SD card
lcd.clear();
if (readings) 
  {
    lcd.print("file OPEN");
    delay(1000);
readings.print(rtc.getMonthStr());
readings.print("\t");
readings.print(rtc.getTimeStr());
readings.print("\t");
readings.print(rtc.getDateStr());
//readings.print(\t);
//readings.print(h);
//readings.print(\t);
//readings.print(m);
//readings.print(\t);
//readings.print(s);
//readings.print(\t);
readings.print(t);
readings.print("\t"); // Prints a TAB
readings.println(h); // Prints the value specified and RETURN
    // close the file:
    readings.close();
    lcd.clear();
    lcd.println("file CLOSE");
    delay(1000);
  } 
  else 
  {
    // if the file didn't open, print an error:
    lcd.println("file not open");
    delay(4000);
  }
// Printing the results on the LCD screen with time and date
  delay(2000);
  lcd.clear(); // Clears the LCD screen and positions the cursor in the upper-left corner
  lcd.print(rtc.getDateStr()); // Prints date
  lcd.setCursor(8,1); // Moves the cursor on the second line of the LCD
  lcd.println(rtc.getTimeStr()); // Prints time
  delay (4000);  // Waits 4 seconds
  lcd.clear(); // Clears the LCD screen and positions the cursor in the upper-left corner
  char tempF[6]; // Defines a character variable
  char humF[6];
  dtostrf(t, 5, 1, tempF); // Converts a float to a char array so it can then be printed easily
  dtostrf(h, 2, 0, humF);
  lcd.print("T:"); lcd.print(tempF); lcd.print((char)223); lcd.print("C ");
  // NOTE: char(223) identifies the degree symbol
  lcd.print("H: "); lcd.print(humF); lcd.print("%");
delay(2000); // Delays 2 seconds, as the DHT22 minimum sampling rate is 0.5Hz
}

Thanks a lot.

M.

The character ("\t") is not recognised. I mean, I am trying to use that in order to write to the next cell on CSV file horizontally.

Do you know what CSV stands for ?
It means Comma Separated Values, so why are you separating the values with tabs ?

  1. Getting the parts separate is not that hard. Just don't use the Str (from string) methods.
Time t = rtc.getTime();
//time
Serial.println(t.hour);
Serial.println(t.min);
Serial.println(t.sec);

//date
Serial.println(t.date); //day of month
Serial.println(t.mon); //month
Serial.println(t.year);

Serial.println(t.dow); //day of week, 1 = monday, 7 = sunday
  1. "\t" is a string with '\t' in it. But why not use what the name implies (CSV => Comma Separated Values)? Aka, just a ',' to separate the values. Granted, if you use European numbers (with a comma as decimal separator) things get messy :smiley:

UKHeliBob:
Do you know what CSV stands for ?
It means Comma Separated Values, so why are you separating the values with tabs ?

because when I wrote

readings.println(h, t); // Prints the value specified and RETURN

was not working, it was not changing the cell but just writing the two values one after the other in the same cell :frowning:

readings.println()?? really? :wink: Did you mean Serial.println()?

In that case, Serial.println(h, t) will NOT print a comma in between. The comma indicates a second parameter for the call to println(). You need to call

Serial.print(h);
Serial.print(',');
Serial.println(t);

septillion:
readings.println()?? really? :wink: Did you mean Serial.println()?

In that case, Serial.println(h, t) will NOT print a comma in between. The comma indicates a second parameter for the call to println(). You need to call

Serial.print(h);

Serial.print(',');
Serial.println(t);

I meant Filename.println()
I am writing on the SD card on a file named readings.csv

same for that, println(h, t) does not print h and t separated by a comma. t is simply the second parameter for the call to println(). Split it up into three calls like I did.

septillion:
same for that, println(h, t) does not print h and t separated by a comma. t is simply the second parameter for the call to println(). Split it up into three calls like I did.

Ok I will try this :slight_smile: Thanks!

The other issue is how to write in different column year/month/day/hour/min/sec/T/RH

This is what I would like to achieve in the CSV file :slight_smile:

Sorry for my incompetence guys but it is my very first project with Arduino...

LordKelvin:
This is what I would like to achieve in the CSV file :slight_smile:

But why don't you answer questions about WHY you want that?

Serial or SD, the principle is the same

          myFile = SD.open(filename, FILE_WRITE);//<<<<<<<<<<<<< OPEN
  myFile.print(hour);
  myFile.print(":");
  myFile.print(minute);
  myFile.print(":");
  myFile.print(second);
  myFile.print(",");

  myFile.print(InTemp);
  myFile.print(",");
  myFile.print(DrainTemp);
  myFile.print(",");
  myFile.println(ShrTemp);
       myFile.close();//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>CLOSE

How hard is that? If you are able to get the time as a package "08:43:40 " I can't see why you have a problem, just print a comma after it, as a CSV would expect.

septillion:
But why don't you answer questions about WHY you want that?

I would like to have the different value in different column because I need to manipulate them for graph etc for my experiment.

Nick_Pyner:
Serial or SD, the principle is the same

          myFile = SD.open(filename, FILE_WRITE);//<<<<<<<<<<<<< OPEN

myFile.print(hour);
  myFile.print(":");
  myFile.print(minute);
  myFile.print(":");
  myFile.print(second);
  myFile.print(",");

myFile.print(InTemp);
  myFile.print(",");
  myFile.print(DrainTemp);
  myFile.print(",");
  myFile.println(ShrTemp);
      myFile.close();//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>CLOSE




How hard is that? If you are able to get the time as a package "08:43:40 " I can't see why you have a problem, just print a comma after it, as a CSV would expect.

I will try to put the comma in order to write the next value in the adjacent horizontal cell in the CSV as soon as I have my board back :slight_smile: And I will let you know.

I tried to simply compile that bit of code you are suggesting in my full code and I got these errors:

Arduino: 1.7.11 (Windows 7), Board: "Arduino Uno"

sketch_jan11a.ino: In function 'void loop()':

sketch_jan11a.ino:60:16: error: 'hour' was not declared in this scope

sketch_jan11a.ino:62:16: error: 'minute' was not declared in this scope

sketch_jan11a.ino:64:16: error: 'second' was not declared in this scope

Error compiling.

This report would have more information with
"Show verbose output during compilation"
enabled in File > Preferences.

// DHT22 Sensor Temperature and Humidity project with LCD readings, RTC and SD logging - ACTIVATION

// Libraries
  #include <dht.h> // Includes the libraries for the sensor
  #include <LiquidCrystal.h> // Includes the libraries for the LCD
  #include <DS3231.h>; // Includes the libraries for the clock
  #include <SPI.h>; // Includes the libraries for the Serial Peripheral Interface that allows the Master (Arduino) to control a slave device
  #include <SD.h>; // Includes the libraries for the SD card
// Interface and Objects definitions
  DS3231 rtc(SDA, SCL); // Initialises the DS3231 using the hardware interface
  #define dataPin 2 // Defines pin number to which the sensor is connected (avoid D4-9 and A0 used by LCD)
  dht DHT; // Creates a DHT object
  LiquidCrystal lcd(8,9,4,5,6,7); // Creates a LCD LiquidCrystal object
  const int chipSelect = 10; // Assigns the pin for the SPI-SD chip selection
  
void setup() 
{
  pinMode(chipSelect, OUTPUT); // Ensures that the SPI-SD selection pin is an output
  rtc.begin(); // Initialises the rtc object
  // rtc.setDOW(TUESDAY); // Sets Day-of-Week to TUESDAY
  // rtc.setTime(15, 46, 05); // Sets the time to 12:00:00 (24hr format)
  // rtc.setDate(10, 1, 2017); // Sets the date to January 1st, 2017
  lcd.begin(16, 2); // Initialises the interface to the LCD screen, and specifies the dimensions
  lcd.print("Initialising SD");
  delay (2000);
  lcd.clear();
    if (!SD.begin(chipSelect)) 
    {
      lcd.println("SD failed!");
      return;
    }
    lcd.println("SD OK");
    delay(2000);
    lcd.clear();
  lcd.print("Reading sensor"); // Prints to the LCD
  delay (4000); // Waits 4 seconds
}

void loop() 
{
// Open the file on the SD card
  delay(2000);
  File readings = SD.open("readings.txt", FILE_WRITE); 
// Reading the data
  int readData = DHT.read22(dataPin); // Reads the data from the sensor
  float t = DHT.temperature; // Gets the values of the temperature
  float h = DHT.humidity; // Gets the values of the humidity
// Check if any reads failed and exit early (to try again).
    if (isnan(h) || isnan(t))
    {
      lcd.println("DHT FAIL!");
      return;
    }
// If the file opened OK, write to it on SD card
lcd.clear();
if (readings) 
  {
    lcd.print("file OPEN");
    delay(1000);
readings.print(hour);
readings.print(":");
readings.print(minute);
readings.print(":");
readings.print(second);
readings.print(",");
readings.print(t);
readings.print(","); // Prints a TAB
readings.println(h); // Prints the value specified and RETURN
    // close the file:
    readings.close();
    lcd.clear();
    lcd.println("file CLOSE");
    delay(1000);
  } 
  else 
  {
    // if the file didn't open, print an error:
    lcd.println("file not open");
    delay(4000);
  }
// Printing the results on the LCD screen with time and date
  delay(2000);
  lcd.clear(); // Clears the LCD screen and positions the cursor in the upper-left corner
  lcd.print(rtc.getDateStr()); // Prints date
  lcd.setCursor(8,1); // Moves the cursor on the second line of the LCD
  lcd.println(rtc.getTimeStr()); // Prints time
  delay (4000);  // Waits 4 seconds
  lcd.clear(); // Clears the LCD screen and positions the cursor in the upper-left corner
  char tempF[6]; // Defines a character variable
  char humF[6];
  dtostrf(t, 5, 1, tempF); // Converts a float to a char array so it can then be printed easily
  dtostrf(h, 2, 0, humF);
  lcd.print("T:"); lcd.print(tempF); lcd.print((char)223); lcd.print("C ");
  // NOTE: char(223) identifies the degree symbol
  lcd.print("H: "); lcd.print(humF); lcd.print("%");
delay(2000); // Delays 2 seconds, as the DHT22 minimum sampling rate is 0.5Hz
}

That;s why I am getting confused. I feel like I am lacking knowledge re what a library can do and what not. Serial is OK, but SD card seems more challenging :frowning:

LordKelvin:
I would like to have the different value in different column because I need to manipulate them for graph etc for my experiment.

Then why do you try to use a tab in with Comma Separated Values? And for graphs I assume Excel? Just select Comma as delimiter while importing it :wink:

LordKelvin:
I tried to simply compile that bit of code you are suggesting in my full code and I got these errors:

That's because it was just a general example. Use the variables I showed you in reply #1.

Thanks a lot for your help.

I am just compiling and I got this:

Arduino: 1.7.11 (Windows 7), Board: "Arduino Uno"

sketch_jan11a.ino: In function 'void loop()':

sketch_jan11a.ino:71:17: error: no matching function for call to 'File::print(Time&)'

sketch_jan11a.ino:71:17: note: candidates are:

In file included from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Stream.h:26:0,

from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/HardwareSerial.h:29,

from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:223,

from C:\Program Files (x86)\Arduino\libraries\dht/dht.h:19,

from sketch_jan11a.ino:4:

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:58:12: note: size_t Print::print(const __FlashStringHelper*)

size_t print(const __FlashStringHelper *);

^

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:58:12: note: no known conversion for argument 1 from 'Time' to 'const __FlashStringHelper*'

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:59:12: note: size_t Print::print(const String&)

size_t print(const String &);

^

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:59:12: note: no known conversion for argument 1 from 'Time' to 'const String&'

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:60:12: note: size_t Print::print(const char*)

size_t print(const char[]);

^

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:60:12: note: no known conversion for argument 1 from 'Time' to 'const char*'

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:61:12: note: size_t Print::print(char)

size_t print(char);

^

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:61:12: note: no known conversion for argument 1 from 'Time' to 'char'

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:62:12: note: size_t Print::print(unsigned char, int)

size_t print(unsigned char, int = DEC);

^

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:62:12: note: no known conversion for argument 1 from 'Time' to 'unsigned char'

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:63:12: note: size_t Print::print(int, int)

size_t print(int, int = DEC);

^

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:63:12: note: no known conversion for argument 1 from 'Time' to 'int'

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:64:12: note: size_t Print::print(unsigned int, int)

size_t print(unsigned int, int = DEC);

^

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:64:12: note: no known conversion for argument 1 from 'Time' to 'unsigned int'

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:65:12: note: size_t Print::print(long int, int)

size_t print(long, int = DEC);

^

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:65:12: note: no known conversion for argument 1 from 'Time' to 'long int'

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:66:12: note: size_t Print::print(long unsigned int, int)

size_t print(unsigned long, int = DEC);

^

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:66:12: note: no known conversion for argument 1 from 'Time' to 'long unsigned int'

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:67:12: note: size_t Print::print(double, int)

size_t print(double, int = 2);

^

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:67:12: note: no known conversion for argument 1 from 'Time' to 'double'

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:68:12: note: size_t Print::print(const Printable&)

size_t print(const Printable&);

^

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:68:12: note: no known conversion for argument 1 from 'Time' to 'const Printable&'

Error compiling.

This report would have more information with
"Show verbose output during compilation"
enabled in File > Preferences.

// DHT22 Sensor Temperature and Humidity project with LCD readings, RTC and SD logging - ACTIVATION

// Libraries
  #include <dht.h> // Includes the libraries for the sensor
  #include <LiquidCrystal.h> // Includes the libraries for the LCD
  #include <DS3231.h>; // Includes the libraries for the clock
  #include <SPI.h>; // Includes the libraries for the Serial Peripheral Interface that allows the Master (Arduino) to control a slave device
  #include <SD.h>; // Includes the libraries for the SD card
// Interface and Objects definitions
  DS3231 rtc(SDA, SCL); // Initialises the DS3231 using the hardware interface
  #define dataPin 2 // Defines pin number to which the sensor is connected (avoid D4-9 and A0 used by LCD)
  dht DHT; // Creates a DHT object
  LiquidCrystal lcd(8,9,4,5,6,7); // Creates a LCD LiquidCrystal object
  const int chipSelect = 10; // Assigns the pin for the SPI-SD chip selection
  
void setup() 
{
  pinMode(chipSelect, OUTPUT); // Ensures that the SPI-SD selection pin is an output
  rtc.begin(); // Initialises the rtc object
  // rtc.setDOW(TUESDAY); // Sets Day-of-Week to TUESDAY
  // rtc.setTime(15, 46, 05); // Sets the time to 12:00:00 (24hr format)
  // rtc.setDate(10, 1, 2017); // Sets the date to January 1st, 2017
  lcd.begin(16, 2); // Initialises the interface to the LCD screen, and specifies the dimensions
  lcd.print("Initialising SD");
  delay (2000);
  lcd.clear();
    if (!SD.begin(chipSelect)) 
    {
      lcd.println("SD failed!");
      return;
    }
    lcd.println("SD OK");
    delay(2000);
    lcd.clear();
  lcd.print("Reading sensor"); // Prints to the LCD
  delay (4000); // Waits 4 seconds
}

void loop() 
{
// Open the file on the SD card
  delay(2000);
  File readings = SD.open("readings.txt", FILE_WRITE); 
// Reading the data
  int readData = DHT.read22(dataPin); // Reads the data from the sensor
  float t = DHT.temperature; // Gets the values of the temperature
  float h = DHT.humidity; // Gets the values of the humidity
// Check if any reads failed and exit early (to try again).
    if (isnan(h) || isnan(t))
    {
      lcd.println("DHT FAIL!");
      return;
    }
// If the file opened OK, write to it on SD card
lcd.clear();
if (readings) 
  {
    lcd.print("file OPEN");
    delay(1000);
Time t = rtc.getTime();
//time
readings.println(t.hour);
readings.println(t.min);
readings.println(t.sec);

//date
readings.println(t.date); //day of month
readings.println(t.mon); //month
readings.println(t.year);

readings.print(t);
readings.print(","); // Prints a TAB
readings.println(h); // Prints the value specified and RETURN
    // close the file:
    readings.close();
    lcd.clear();
    lcd.println("file CLOSE");
    delay(1000);
  } 
  else 
  {
    // if the file didn't open, print an error:
    lcd.println("file not open");
    delay(4000);
  }
// Printing the results on the LCD screen with time and date
  delay(2000);
  lcd.clear(); // Clears the LCD screen and positions the cursor in the upper-left corner
  lcd.print(rtc.getDateStr()); // Prints date
  lcd.setCursor(8,1); // Moves the cursor on the second line of the LCD
  lcd.println(rtc.getTimeStr()); // Prints time
  delay (4000);  // Waits 4 seconds
  lcd.clear(); // Clears the LCD screen and positions the cursor in the upper-left corner
  char tempF[6]; // Defines a character variable
  char humF[6];
  dtostrf(t, 5, 1, tempF); // Converts a float to a char array so it can then be printed easily
  dtostrf(h, 2, 0, humF);
  lcd.print("T:"); lcd.print(tempF); lcd.print((char)223); lcd.print("C ");
  // NOTE: char(223) identifies the degree symbol
  lcd.print("H: "); lcd.print(humF); lcd.print("%");
delay(2000); // Delays 2 seconds, as the DHT22 minimum sampling rate is 0.5Hz
}

Why is this (still) in here? :wink:

readings.print(t);
readings.print(","); // Prints a TAB
readings.println(h); // Prints the value specified and RETURN

Sorry :o

What about the alternative solution to create a TXT file with commas like

a,b,t,h

And then when I import in Excel I tell it that there are "separators"?
It seems it will put in different columns...

Or perhaps this was the solution you meant????

I am appreciating your help

Mario

septillion:
Why is this (still) in here? :wink:

readings.print(t);

readings.print(","); // Prints a TAB
readings.println(h); // Prints the value specified and RETURN

NO ERRORS in compiling!!!

But now How can I print in the next 2 column the values of t and h from the sensor?

How can I print in the next 2 column the values of t and h from the sensor?

Add

readings.print(","); // Prints a TAB - Oh no it doesn't !
readings.print(someVariable);

for each extra variable you need to output but only use println() for the final one to terminate the line of data.

Then why do you try to use a tab in with Comma Separated Values?

Lets not get hung up on the name. csv is an extension that excel recognizes as contained delimited data. At the time you use Excel to open the file, you can tell it what delimiter you used. You can uses spaces, commas, semicolons, tabs, any letter, etc. It makes no difference.

Tab is a perfectly reasonable way of separating the data. Printing the file, from Notepad++ or other editor will also generate a nice looking output when using tabs, but not when using commas.

True, but it was just as to indicate the lack of knowlegde about a CVS. But indeed a tab should work fine as well if the SD library can handle it.

I think I learned LOADS today guys, you are very cool :slight_smile:

I am trying just now and I will post the final code soon if it works!