I want to read a number from a file on an SD card. Then add 1 to the number and over-write back to the file. This number will be used as a filename for a file that the sketch will make. In this way the sketch will make a new file everytime I start or reset the Arduino. However I have problem with reading correct datatype, and overwriting the file. Maybe I fail on the datatypes (Ascii, char, int..) and O_WRITE command? . Any help appreciated. Writing and reading the final measurement file is OK. In example below I hoped to step filename up from 21.txt to 22.txt, and so further on by resetting. Maximum 99 needed. The code seems to read ascii-numer, and doesnt overwrite, neither write back the new filename.
My code so far:
//SD Adafruit MicroSD card breakout+ http://adafru.it/254
//GND to ground, 5V to 5V, CLK to pin 13, DO to pin 12, DI to pin 11, and CS to pin 10.
#include "SD.h"
#include "SPI.h"
int chipSelect=10; // CS=Ship Select til pin 10
File LogFile; // Variable for filename where measured data shal be dumped
File FileNameF; // Variable for the filename where the incrementing filname is stored
int DumpFileName;
String CompFN;
void setup() {
Serial.begin(9600);
if (!SD.begin(chipSelect)) {
Serial.println("Initiating failed");
return;}
Serial.println("Initiating done");
//Open file FNF.txt where previous filename without file-extension is stored (for example 21)
FileNameF=SD.open("FNF.txt");
if(FileNameF) {
while(FileNameF.available()){
DumpFileName=FileNameF.read();
//Serial.print("FNF.txt available: ");Serial.println(DumpFileName);
}
}
else{
Serial.print("FNF.txt not available");
}
//Add 1 to filename
DumpFileName=DumpFileName+1; //Hoping DumpFileName at this stage gets 21+1=22
Serial.print("New filename: ");Serial.println(DumpFileName);
FileNameF.close();
//Open file FNF.txt with TRUNC to overwrite it, and write new 1 incremented filname back to it
// without file extention
FileNameF=SD.open("FNF.txt",O_TRUNC);
FileNameF.print(DumpFileName); //Hoping FNF.txt at this stage contains only 22
FileNameF.close();
//Add file-extention, open file to send measurements to
CompFN=DumpFileName+".txt";
Serial.print("Compleete new filename: ");Serial.println(CompFN);
LogFile=SD.open(CompFN,FILE_WRITE); //Hoping this would open a file 22.txt
}
void loop() {
if(LogFile) {
LogFile.println("Testing");
Serial.println("Testing");
LogFile.flush();
delay(250);
}
}`
A File represents that thing on disk; it has a name, but that name is a string. So it is confusing to say these variables are for the filename
If you just return here after failure, the loop function will run anyway
read returns a single byte, with the value 0 to 255. It also will return -1 if there is nothing to read. Now, you're also checking available, so that shouldn't happen, but the function's declared behavior does not change. It needs to return 257 possible values, so instead of a byte or char it returns an int.
Reading one byte at a time, if the file contains the two characters "21", the final value will be the code point for '1': 49 (decimal)
File should have readString, which returns the whole (remaining) file content as a String. You can then use toInt to convert that to an integer.
I didn't quite understand your need.
But see if this code helps.
//SD Adafruit MicroSD card breakout+ http://adafru.it/254
//GND to ground, 5V to 5V, CLK to pin 13, DO to pin 12, DI to pin 11, and CS to pin 10.
#include "SD.h"
#include "SPI.h"
int chipSelect = 10; // CS=Ship Select til pin 10
File LogFile; // Variable for filename where measured data shal be dumped
File FileNameF; // Variable for the filename where the incrementing filname is stored
int DumpFileName;
String CompFN;
//---------------------------------------------------------------------
void setup() {
Serial.begin(9600);
if (!SD.begin(chipSelect)) {
Serial.println("Initiating failed");
return;
}
debug_wrd_SD();
debug_rdr_SD();
Serial.println("Initiating done");
//Open file FNF.txt where previous filename without file-extension is stored (for example 21)
FileNameF = SD.open("FNF.txt");
if (FileNameF) {
while (FileNameF.available()) {
DumpFileName = FileNameF.read();
}
}
else {
Serial.print("FNF.txt not available");
}
//Add 1 to filename
DumpFileName = DumpFileName + 1; //Hoping DumpFileName at this stage gets 21+1=22
Serial.print("New filename: "); Serial.println(DumpFileName);
FileNameF.close();
//Open file FNF.txt with TRUNC to overwrite it, and write new 1 incremented filname back to it
// without file extention
FileNameF = SD.open("FNF.txt", O_TRUNC);
FileNameF.write(DumpFileName); //Hoping FNF.txt at this stage contains only 22
FileNameF.close();
//Add file-extention, open file to send measurements to
CompFN = String(DumpFileName) + ".txt";
Serial.print("Complete new filename: "); Serial.println(CompFN);
}
//---------------------------------------------------------------------
void loop() {
LogFile = SD.open(CompFN, FILE_WRITE); //Hoping this would open a file 22.txt
if (LogFile) {
LogFile.println("Testing");
Serial.println("Testing");
LogFile.flush();
delay(250);
LogFile.close();
}
}
//---------------------------------------------------------------------
void debug_wrd_SD() {
FileNameF = SD.open("FNF.txt", FILE_WRITE);
if (FileNameF) {
FileNameF.write(22);
}
FileNameF.close();
}
//---------------------------------------------------------------------
void debug_rdr_SD() {
FileNameF = SD.open("FNF.txt");
if (FileNameF) {
while (FileNameF.available()) {
Serial.println(FileNameF.read());
}
}
FileNameF.close();
}
A simple way to do this is to have an special file that contains the next number. When you want to create the next file, you open the file, read the number, increment it by one and write it back to the file, close the file. Use the number you read from the file to create your unique file name.
I find this a lot simpler that looping for all the file names and trying to open to see if it exists.
What you propose is exactly what I try to do, and also how I tried to explain it in the question. However I have problems to make a code that does this. I think I go wrong with datatypes and command for overwrite
I think it would be cleaner to encapsulate the whole open/read/increment/write sequence in a function that then returns the index to the caller. Something like this (untested)
int nextFileIndex(void)
// Return next file number or -1 if error
{
char fName[] = "FNF.txt";
int fileIndex;
File f;
//Open and read the index file
f = SD.open(fName);
if (f)
{
while (FileNameF.available())
fileIndex = FileNameF.read();
f.close()
}
else
fileIndex = -1;
// rewrite next number to file
if (fileIndex != -1)
{
f = SD.open(fName, O_TRUNC);
f.print(fileIndex+1);
f.close();
}
retuen(fileindex);
}
Thanks, I agree that a function makes it clerarer.
However it doesnt solve my problem.
fileIndex is defined as Int.
If for example textfile "FNF.txt" contains the number 1, fileIndex is read as 49 (decimal for ascii 1), and fileIndex+1 is 50. I know I can change to char, but it will be a problem when dec>57 when the special signs in ascii table comes (:;<=...)
Is there no easy way to read in numbers from a file and do normal math on them?
Here is the SD library reference SD | Arduino Documentation. If you believe this, then it looks like there is no way to read the whole integer directly. You could look in the header file to see if there is anything not documented in the class definition.
I assume that you are in control of the contents of the .txt file and all that will be in there is the integer. If you intend that the .txt file contains readable text (ie, ASCII characters) then you need to read the characters and convert then to an integer. This is very simply done. Untested code below.
fileIndex = 0;
while (FileNameF.available())
{
char c = FileNameF.read();
if (c >= '0' && c <= '9') // character is s digit
fileIndex = (fielIndex * 10) + (c - '0');
else
break; // character is no longer a digit, exit the loop
}
I'm using something like this to generate a "new file" with every start:
if (!SD.begin(chipSelect)) {
Serial.println(F("E: SD card failed, or not present"));
statusSd = 0;
}
else
{
Serial.println(F("SD card initialized."));
statusSd = 1;
sprintf(filename, "%d.csv", currentFile);
while (SD.exists(filename)) // determine a new logfile on every restart.
{
currentFile++;
sprintf(filename, "%d.csv", currentFile);
}
if (!SD.exists(filename)) // Print a header to the new logfile
{
logfile = SD.open(filename, FILE_WRITE);
logfile.println(F("lat,long,date,time,speed,result"));
logfile.close();
}
statusSd=2;
Serial.print(F("Current logfile:")); Serial.println(filename);
}
}
and some globals
// SD Card and Filesystem
const int chipSelect = 4;
uint16_t currentFile = 0;
File logfile;
char filename[10];
uint16_t entriesSd = 0; // how many Entries are made on SD
byte statusSd = 0;
do {
currentFile++;
sprintf(filename, "%d.csv", currentFile);
} while (SD.exists(filename)); // determine a new logfile on every restart.
// Print a header to the new logfile
logfile = SD.open(filename, FILE_WRITE);
Except it would start with 1.csv instead of 0.csv. Either way, it does get slower as there are more and more files; but maybe not slow enough that it matters.
Thank you. readString and toInt basically solved my problem, together with beeing very observant with data-types (int, char, string). Also I learned that Serial.print send back the actual ASCII code, wheras Serial.write send back the text.