Arduino and writing file to SD - arduino

I have the following code
global
File logFile
and inside loop()
DateTime now = rtc.now();
String stringFilename = "";
stringFilename = String(now.year())+"_"+String(now.month())+"_"+String(now.day());
stringFilename += ".csv";
Serial.println(stringFilename);
char filename[stringFilename.length() + 1];
stringFilename.toCharArray(filename, sizeof(filename));
String dataString = "";
dataString += String(now.year());
Serial.print("Filename: ");
Serial.println(filename);
if (!SD.exists(filename)){
Serial.println("File does not exist");
logFile = SD.open(filename, FILE_WRITE);
}
if (logFile){
logFile.println(dataString);
}else{
Serial.println("Could not open file");
}
Filename is something like 2014_5_26.csv. SD empty. The above code won't open file for writing. If I substitute filename with a literal like "datalog.txt" it works. What am I doing wrong?
EDIT: I got what my problem was. The name was to long. It can be only up to 8 characters. Can I ask something different? Can I call SD.begin(chipSelect) in loop to determine if SD is present or is this called always on setup?

You can use it in loop but the program speed will be reduce.
Don't forget to close your file (SD.close()) before to be sure that your data are correctly written to the SD card

8.3 filename rules may apply. Your Date derived ("2014_5_26") filename appears to have 9 characters. When you use "datalog", that has 8 characters, it works.

Related

How can I call random jpg from sd card and display using drawSdJpeg

In the TFT_ESPI (Bodmer) Example/Generic/ESP32_SDcard_jpeg
I have run it on my esp32 on a 3.5" ili9341 with no problems.
I have changed the sd file names to numbers and called them as such ...
drawSdJpeg("/1.jpg", 0, 0); and as expected, runs the same.
I have used this code to display the images one after another ...
`File file;
File root = SD.open("/");
if(!root){
Serial.println("Failed to open root directory");
return;
}
file = root.openNextFile(); // Opens next file in root
while(file)
{
if(!file.isDirectory())
{
drawSdJpeg(file.name(), 0, 0); // This draws a jpeg pulled off the SD Card
delay(4000);
}
file = root.openNextFile(); // Opens next file in root
}
root.close();`
But I can't find a way to call a RANDOM file (image) and display it.
Can anyone help please, I would appreciate it.
Thank you.
And thank you to Bodmer for making many things possible !
SOLVED
Thanks to Bodmer
Yes, the drawSdJpeg function expects a string, so you need to create a string with the number in it plus the .jpg extension. For example:
char filename [20]; // 19 chars max + terminating null
int i = 42;
itoa(i,filename,10); // Put string version of a number in filename,
number base 10
strcat(filename, ".jpg"); // add .jpg to end of string
drawSdJpeg(filename, 0, 0);

Add quotes to start and end of String

I'm working with a project that consist on sending data that I receive from the console terminal from Arduino IDE. I have been able to get the data that I have typed inside the console and store on a variable. My variable is a String, when I get the data that I have typed from the console, it comes like this: This is text. I would need to concat one quote to the start and one to the end, so it will stay like: "This is text". I would need that because to write the data inside esp32 SPIFFS it has to be inside quotes.
String wifi_name;
if (Serial.available()){
wifi_name = Serial.readString();
}
if (wifi_name == NULL){
Serial.print("File size: ");
Serial.print(file.size());
Serial.println(", O valor dentro da string é nulo, nada será adicionado ao arquivo");
delay(2500);
}else{
write_file_info(wifi_name);
}
void write_file_info(String message) {
file = SPIFFS.open("/wifi.txt", FILE_WRITE);
if (!file){
Serial.println("Error opening file");
return;
}else{
Serial.println("Success opening file");
}
if (file.print("\message\")){ //This line I would need to have quotes in the end and start
Serial.println("File was written");
}else{
Serial.println("File was not written");
}
file.close();
}
I would need that the message part if (file.print("message")) stayed between quotes, but since it is a String, I can't apply the quotes.
https://www.arduino.cc/en/Tutorial/BuiltInExamples/StringAdditionOperator
And to concat special character like " you can use escape character like this "\"" + text + "\"" .

Recieving two sets of string-data from Processing to Arduino into two variables

I'm desperatly trying to get arduino to divide a string from processing into two sets of variables. In the code below I've decided to just type the important parts but x and y does of course contain the correct values. Any solution would be appreciated. These are my two attempts so far:
Attempt 1 doesn't work at all.
1.Processing:
myPort.write(x + "," + y + "\n");
1.Arduino:
String tempX = Serial.readStringUntil(44);
String tempY = Serial.readStringUntil(10);
String x = tempX.substring(0,tempX.length() -1);
String y = tempY.substring(0,tempY.length() -1);
Attempt 2 where x works correctly but not y.
2.Processing:
String [] dataToSend = new String [2];
dataToSend [0] = x;
dataToSend [1] = y;
String joinedData = join(dataToSend, ":");
myPort.write(joinedData);
2.Arduino:
String x = Serial.readStringUntil(":");
Serial.read(); //next character is comma, so skip it using this
String y = Serial.readStringUntil('\0');
First, don't worry about combining them on the Processing side. Sending two strings one right after the other is the same as sending one long string. It's all being broken into bytes on the Serial line and nobody can tell where one print line stops and the next starts.
myport.write(x);
myport.write(',');
myport.write(y);
myport.write('\n')
will work just as good.
Then on the Arduino side you most likely want to shy away from the String class. Read the data character by character into a char array.
char myArray[howLongTheStringIs];
char x[howLongXIs];
char y[howLongYIs];
int index = 0;
This gets called over and over in loop and picks up serial data as it comes in:
while (Serial.available()){
char c = Serial.read();
myArray[index] = c; // add c to the string
myArray[++index] = 0; // null terminate our string
if(c == '\n'){ // if we are at the end of the string
handleString();
}
}
Then you have a function to parse your string there are lots of ways to do that:
If you don't know anything about the strings other than the separator use strtok:
void handleString(){
char* ptr = strtok(myArray, ":"); // get up to the ":" from the string
strcpy(x, ptr); // copy into x
ptr = strtok(NULL, "\n"); // get from the separator last time up to the next "\n"
strcpy(y, ptr); // copy into y
index = 0 // reset our index and
myArray[0] = 0; // and clear the string
}
That's all untested and uncompiled and written in the reply box, so if I made a little typo in there please forgive and correct. But something like this should work. If you already know the exact lengths of the strings (or can send them from the processing code) then the handleString method can be simpler. If you've got something short to do with x and y and don't need them after that then maybe you can just keep pointers to where they are in myArray. It all depends on what the larger picture goal of your code is. But something like this should get the job done.

File name for file on Arduino SD card won't save

I'm making a data logging system, just for fun and learning the language. If I want to save a variable ".txt" file with an INT it works fine. Now I bought an RTC and I want the name to be as following: "Data_'DATE&TIME'.txt".
As you can see in the code below, I made a function newFileName what should be doing this, but my output also below is nothing like it. And on the SD card nothing even saves.
The things in comments are things I tried.
int CURRENT_FILE = 1;
String dataString = "";
String currentFileName = "";
String currentTimeStamp = "";
void setDatumTijd(){
t = rtc.getTime();
currentTimeStamp = rtc.getDateStr();
currentTimeStamp += "--";
currentTimeStamp += rtc.getTimeStr();
currentTimeStamp.replace(':', '.');
delay(50);
}
void makeNewFile(String currentTimeStamp){
char fileName[50];
char timeStamp[20];
// sprintf(timeStamp, currentTimeStamp.c_str());
sprintf(fileName, "Data_%d.txt", currentTimeStamp.c_str());
//currentFileName = fileName;
//currentFileName.toCharArray(fileName,50);
//currentTimeStamp += ".txt";
//currentTimeStamp.toCharArray(fileName, (currentTimeStamp.length()+1));
Serial.println(fileName);
currentFileName = fileName;
File dataFile = SD.open(fileName, FILE_WRITE);
saveHeader(currentFileName, currentTimeStamp);
dataFile.close();
}
enter image description here
The library that comes with Arduino doesn't support long filenames, it only supports "8 bytes for filename"."3 bytes for file type", and in your case, it is clearly exceeding that limit.
This all is due to the reason that most of the Arduino boards has lesser RAM.
But if you still want to go ahead, you can use the following library.
https://github.com/greiman/SdFat
This library supports Long File names and if I remember correctly, the Arduino Standard Library is also the wrapper of the library created by the same author.
https://forum.arduino.cc/index.php?topic=58549.msg421288#msg421288
Note: Long File Names consumes much RAM.

Arduino+Ethernet-SD shield, listing all filenames existing files on the SD card

I have:
Arduino MEGA 2560;
Ethernet+SD shield http://www.amazon.com/dp/B0022TWQ22/?tag=stackoverfl08-20 ;
SD card 2GB FAT.
SD contains 400 files with names 00000000; 0000001; 0000002; ... 00000098; 0000099; 0000100; ... 00000398; 00000399.
I need to construct String var which will contain all the Filenames separated by ";" like this:
sdata = "0000001;0000002;0000003 ... 00000398;00000399;";
Code:
#include <SdFat.h>
#include <SPI.h>
const uint16_t chipSelect = SS;
char cnamefile[9];
String sdata="";
SdFat sd;
SdFile file;
void setup() {
Serial.begin(9600);
Serial.println("hi");
sdata="";
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) sd.initErrorHalt();
Serial.println("List files");
while (file.openNext(sd.vwd(), O_READ)) {
file.getFilename(cnamefile);
file.close();
sdata = sdata + String(cnamefile) + ";";
}
Serial.print(sdata);
}
void loop() {
}
Listening to the COM port i see:
hi
List files
00000005;00000006;00000007;00000008;00000009;00000010;00000011;00000012;00000013;00000014;00000015;00000016;00000017;00000018;00000019;00000020;00000021;00000022;00000023;00000024;00000025;00000026;00000027;00000028;00000029;00000030;00000031;00000032;00000033;00000034;00000035;00000036;00000037;00000038;00000039;00000040;00000041;00000042;00000043;00000044;00000045;00000046;00000047;00000048;00000049;00000050;00000051;00000052;00000053;00000054;00000055;00000056;00000057;00000058;00000059;00000060;00000061;00000062;00000063;00000064;00000065;00000066;00000067;00000068;00000069;00000070;00000071;00000072;00000073;00000074;00000075;00000076;00000077;00000078;
How to fix this problem and put all filenames in one variable?
Information for: 400 names and 400 ";" its 3600 bytes. When i try to read any file and put all its contents (more than 3600 bytes) in "String sdata" it works normally. Problem only with listing.
Please help me in sorting out this issue.
This seems about the correct place that your program will fail. This innocent line is your problem:
sdata = sdata + String(cnamefile) + ";";
String concatentation like this will use 2X the memory of the sdata for a short moment. This is the how you should view the sequence of operations in that one line
// compiler has done this for you:
String temp1234 = sdata + String();
// note that at this moment, memory usage is now 2x sdata
String temp1235 = temp1234 + ";";
// now you can have 3x the memory used
// assignment to variable
sdata = temp1235;
// now can delete temporary variable
// compiler will do this
//temp1234.delete()
//temp1235.delete()
You are trying to create strings up to 3k bytes but have only 8k total RAM, so will not be able to do the above.
This demonstrates a couple of points about Strings. Your concatenation above on one line, is not necessarily better than this two line form:
sdata = sdata + String(cnamefile);
sdata = sdata + ";";
In this second form, you are ensured there will only be one temporary variable for the intermediate result.
This leads to the next hint. You should be thinking how am I going to escape the temporary variable. That is why we have += operator. Your best chance is to concatenate like this:
sdata += String(cnamefile);
sdata += ";";
If the += operator is available on the String class, the compiler will use this. That operator may be able to use a more memory efficient way of concatenation. For example, if the String was preallocated with some extra memory, then it could just place the new characters into the existing buffer.
In general this is a great learning method about strings in constrained memory spaces, because you must understand some compiler internals and operator details that are often ignored in large CPU environments.
Given the sizes you are suggesting, you will probably only be able to fit in RAM if you change to an approach of pre-constructing a String buffer and filling it with the file names. In other words: don't use String on a microcontroller.

Resources