0

So, maybe I'm too tired to see the obvious issue here, but my SD card script is causing a "blank" file to be created, then a secondary file to be correctly created.

I'm trying to store data logs, and I don't want to overwrite old logs, I just want to "move" them to the back of the queue. So I start with six files on the SD card:

DATA.TXT
DATA~1.TXT
DATA~2.TXT
DATA~3.TXT
DATA~4.TXT
DATA~5.TXT

Everything writes to DATA.TXT, and DATA~1.TXT through DATA~5.TXT are "old" logs, from oldest to newest. This means that, the next time I boot up the Arduino, I want the contents of DATA.TXT to be read into a new file called DATA~6.TXT, I want the old DATA.TXT to be deleted, and I want a new DATA.TXT to be created for the rest of the program. It should look like this:

DATA.TXT <=== New, blank file, primed for logging new data
DATA~1.TXT
DATA~2.TXT
DATA~3.TXT
DATA~4.TXT
DATA~5.TXT
DATA~6.TXT <=== "Old" DATA.TXT

In reality, it's creating two files: instead of DATA~6.TXT holding the contents it should, it's blank -- and a file called DATA~7.TXT is created with the contents of the "old" DATA.TXT. After that, it's writing to the "new" DATA.TXT as it should. Something is lost (or added) in shifting the data, for some reason, looking like this:

DATA.TXT <=== New, blank file, primed for logging new data
DATA~1.TXT
DATA~2.TXT
DATA~3.TXT
DATA~4.TXT
DATA~5.TXT
DATA~6.TXT <=== Blank, unused "new" file?
DATA~7.TXT <=== "Old" DATA.TXT

EDIT: Each file contains test data ( e.g. - file DATA~1.TXT contains a line like This is "DATA~1.TXT") So I can track which files are "moved," and where they go. That's how I know where the "old" DATA.TXT file is going, and how I know DATA~6.TXT is "blank." It's actually a blank file, with no data in it.

EDIT #2: As stated in the comments below, the Uno doesn't actually wait for a serial connection. I just tested this, and it is true... that being said: I'm still getting a blank DATA~6.TXT and DATA.TXT is being moved into DATA~7.TXT without cause.

Now that you know the goal, and (probably) see the issue, here's the code:

/*
 * Tests the SD card slot, assuring no functional code is missing
 * for BIB process to correctly log data.
 *
 */

#include <SPI.h>
#include <SD.h>

String fileName = "DATA.TXT";                       // Declare a filename with FAT 8.3 naming conventions
File dataLog;                                       // Store our "opened" file in an object

void setup(){
    Serial.begin( 115200 );
    while( !Serial ){                               // Wait for serial port to open before doing anything
    }

    Serial.println( "\nInitializing SD card..." );  // Start SD card
    if( !SD.begin( 4 ) ){
        Serial.println( "Initialization failed!" );
        while( 1 );
    }
    Serial.println( "Initialization done." );

    Serial.println( "\nChecking if we have a unique filename..." );
    if( SD.exists( fileName ) )                     // Give our data log a unique filename if the current filename already exists
        moveFiles();

    dataLog = SD.open( fileName, FILE_WRITE );      // Open our file for editing if it doesn't already exist
    Serial.println( "Created save file!" );

    // Write to file the first time
    if( dataLog ){
        Serial.println( "\nWriting int test to file..." );
        dataLog.println( "Testing Sequence1..." );
        dataLog.println( "\tSequence1 complete." );
        Serial.println( "\tFirst test written!" );
        dataLog.close();
        Serial.println( "\tData log closed." );
    }
    else
        Serial.println( "---Error opening data log file!---" );
}

void loop(){
}

// Moves the last `DATA.TXT` to `DATA~x.TXT` where `x` is the largest integer.
// This makes the "highest" numbered file the last data log, and `DATA.TXT` the current data log.
// Follows SFN8.3 standards of naming, with 8 chars for filename, 4 chars for extension, and preceeding
// periods converted to `~` chars.
// This leaves us with only 999 possible "backup" data logs.
void moveFiles(){
    bool sdCardFull = false;                            // Keep track of if our SD card is "full" or not
    byte num = 1;
    File newFile;

    String existingFile = String( "DATA~" ) + String( num ) + String( ".TXT" );     // Creates a filename of `DATA~num.TXT` to test

    // Check if this filename exists, too.  Iterate `num` to avoid overwriting currently existing files
    while( SD.exists( existingFile ) ){
        if( num == 999 ){          // If the SD card is full
            sdCardFull = true;
            noMoreRoom( sdCardFull );
        }

        num++;
        existingFile = String( "DATA~" ) + String( num ) + String( ".TXT" );
    }

    dataLog = SD.open( fileName );
    // Create the new file, with the new filename
    newFile = SD.open( existingFile, FILE_WRITE );

    // Move the old data log into the new filename
    while( dataLog.available() )
        newFile.write( dataLog.read() );

    // Close, remove, then re-open the data log
    newFile.close();
    dataLog.close();
    SD.remove( fileName );                          // Deletes the old data log
}

// We cannot find a good filename for the SFN8.3 format, since all of the available filenames have been
// used up, so we will stop the program from running until the SD card is cleaned up, before we "destroy"
// the last backup file.
void noMoreRoom( bool sdCardFull ){
    /*
    lcd.setCursor( 0, 0 );
    lcd.print( "   SD card is   " );
    lcd.setCursor( 0, 1 );
    lcd.print( "   too full!!   " );
    */

    Serial.println( "The SD card is full and we will not proceed until it is cleaned up." );

    while( sdCardFull ){}       // Do absolutely nothing until the SD card is "cleaned up"
}
  • 1
    Let me guess... you plug the board in (or program the board), then you open the serial terminal, and the program "starts running"...? What about the period between plugging it in (or programming it) and you opening the serial terminal? It runs then too you know... (assuming an Uno - but you don't specify which board you are using...) – Majenko Aug 14 '19 at 19:00
  • Yes, it's an Uno... and a Nano... and a Pro-Mini. And the sketch should be caught in the while( !Serial ) loop until the Serial Monitor is attached, right? – stillborn86 Aug 14 '19 at 19:07
  • No, that line is only for native USB boards as I remember. It will not wait for anything on an Uno or Nano – chrisl Aug 14 '19 at 19:17
  • Maybe you should first test for the file to actually contain data, before you move it. – chrisl Aug 14 '19 at 19:19
  • while (!Serial) works only for MCU with native USB (32u4, SAMD), not for Uno, Nano, Mega, Mini. Uno & co. reset on new connection. they start to run and then they are reset on new connection – Juraj Aug 14 '19 at 19:19
0

If you have Serial Monitor open in Arduino IDE and you do an Upload, the Serial Monitor disconnects to free the port for avrdude. After the upload finishes, the Serial Monitor reconnects. On new connection the Arduino resets.

Now after the avrdude finished with upload, the Arduino starts running and executes your setup() function. It creates the new file and suddenly the Serial Monitor reconnects and resets the Arduino. The setup() starts running again and creates the next file.

This will not happen if Serial Monitor is not open, but to prevent it, you can put a long delay at the beginning of setup().

  • If I upload the code, format the SD card, and power the Arduino with a coaxial jack (no serial monitor), then wait for over a minute (for the Arduino to run through whatever code it needs to), the issue is still there. So I'm not 100% convinced the Serial Monitor is the problem, here. That's why I confidently threw in "EDIT #2" in the post. – stillborn86 Aug 15 '19 at 14:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.