Successfully Write to SD Card only Once

I am trying to log sensor data to a SD card, however, no matter how i tried, it can only write to the SD card once and never again. Have been debugging for 2 days and no progress :frowning:
There is no error message (SD card is successfully opened), and seems no memory leak (FreeRam: 6689 constantly after .txt file on SD card is opened). if i use the "datalog" sample code to write string constant, it works well. i am using MEGA2560.

Is there anything thing wrong with my code?
Comments and suggestions are appreciated!

#include <String.h>
// for LCD
#include <LiquidCrystal.h>
// for DHT sensor and RTC
#include <Wire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include <DHT.h>
// for SD card
#include <SPI.h>
#include <SD.h>

#define DHTPIN 6     // what Arduino pin the DHT signal PIN is connected to
#define DHTTYPE DHT11   // DHT 11 

int sensorPin_sound = A0; // select the input pin for the sound meter
int sensorValue_sound = 0; // variable to store the value coming from the sensor

int sensorPin_light = A15; // select the input pin for the light meter
int sensorValue_light = 0; // variable to store the value coming from the sensor

DHT dht(DHTPIN, DHTTYPE);

const int chipSelect = 4; // for SD card
LiquidCrystal lcd(12, 11, 10, 9, 8, 7); // initialize the library with the numbers of the interface pins

volatile int LoggingState = HIGH; // state flag for ISR: LOW/HIGH: Logging disabled/ Logging enabled 
const int Log_freq = 5; // frequency devision for display refreshing and logging
volatile int Log_count = 0; // count

File sensorLog;

// --------------- SETUP ------------------------
void setup() {
  // set up the LCD's number of columns and rows: 
  lcd.begin(16, 2);
  // Print a message to the LCD.
  lcd.print("Temp/Humi Demo");
  
  // set up interrupt from button press
  attachInterrupt(0,ISR_Button,RISING); // digital pin 2 // up
  
  // start dht sensor
  dht.begin();
  
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }
 
  Serial.print("Initializing SD card...");
  // 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.");
  
  sensorLog = SD.open("datalog.txt", FILE_WRITE);
       // if the file is available, write to it:
      if (sensorLog) {
       sensorLog.println("success opend file");
       sensorLog.close();
       
       Serial.println("success opening txt file");
      }
      // if the file isn't open, pop up an error:
      else {
        Serial.println("error opening txt file");
        lcd.setCursor(0, 0);
        lcd.print("SD card read error! ");
      }
    
}

// ----------------- ISR ------------------------
void ISR_Button(){

  LoggingState = !LoggingState;
  lcd.clear(); //clear current lcd display
  lcd.begin(16, 2);
  if(LoggingState == HIGH){
    lcd.print("Logging Enabled");
  }
  else{
    lcd.print("Logging Disabled");    
  }

  delay(1000);
}

// --------------- LOOP ------------------------
void loop() {

  if(LoggingState == HIGH) // Only read and log when in Logging Started State - can be changed using button press
{  
  // set the cursor to column 0, line 1 (note: line 1 is the second row, since counting begins with 0):
  lcd.setCursor(0, 1);
  lcd.display();
    
  // display Temperature and Humidity
//  float h = dht.readHumidity();
  int h = dht.readHumidity();
  // Read temperature as Celsius
//  float t = dht.readTemperature();
  int t = dht.readTemperature();
  // display sound and light level
  sensorValue_sound = analogRead (sensorPin_sound);
  sensorValue_light = analogRead (sensorPin_light);
  
  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(t) 
  ) {
    Serial.println("Failed to read from DHT sensor!");
    return;
  }
    delay(1000);
    /// Logging into SD card
    Log_count++;
    if(Log_count == Log_freq) // time to log
    {
      Log_count =0;
      
      sensorLog = SD.open("datalog.txt", FILE_WRITE);
      Serial.print(F("FreeRam: "));Serial.println(FreeRam());

      // if the file is available, write to it
      if (sensorLog) {
        sensorLog.println("success open file");
        sensorLog.print(t);
        sensorLog.print(";");
        sensorLog.print(h);
        sensorLog.print(";");
        sensorLog.print(sensorValue_sound);
        sensorLog.print(";");
        sensorLog.print(sensorValue_light);
        sensorLog.println(";");
        sensorLog.close();
        
        Serial.print(t);
        Serial.print(";");
        Serial.print(h);
        Serial.print(";");
        Serial.print(sensorValue_sound);
        Serial.print(";");
        Serial.print(sensorValue_light);
        Serial.println(";");
        
        Serial.println("finish write txt file");
       }
      // if the file isn't open, pop up an error:
      else {
        Serial.println("error opening txt file");
        lcd.setCursor(0, 0);
        lcd.print("SD card read error! ");
      }
    }
 } // LoggingState == HIGH
}

When you say you can only write to the text file once, do you mean one line, one run of the Arduino, 1 character, just the characters in setup(). etc.?

void ISR_Button(){

  LoggingState = !LoggingState;
  lcd.clear(); //clear current lcd display
  lcd.begin(16, 2);
  if(LoggingState == HIGH){
    lcd.print("Logging Enabled");
  }
  else{
    lcd.print("Logging Disabled");    
  }

  delay(1000);
}

Why the lcd.begin() in the ISR and why after the lcd.clear() ?
Can you print to the lcd in an ISR ?
Does delay work in an ISR ?

arduinodlb:
When you say you can only write to the text file once, do you mean one line, one run of the Arduino, 1 character, just the characters in setup(). etc.?

For the current code, it only writes one line "success opend file" (as in Setup()) to the text file.

UKHeliBob:
Why the lcd.begin() in the ISR and why after the lcd.clear() ?
Can you print to the lcd in an ISR ?
Does delay work in an ISR ?

Yes print lcd works in ISR. i was trying to use a button to enable/disable logging, and display on the LCD.
Delay does not work normally in ISR.

arduinodlb:
Just as a test, change the sensorLog objects to be auto.

FILE sensorLog = SD.open("datalog.txt", FILE_WRITE);

Thank you for the suggestion, did you mean add "File" before sensorLog wherever it is used?
I tried and the result is the same, still only write the first time....

For the current code, it only writes one line "success opend file" (as in Setup()) to the text file.

I suggest that you work through your problem in two stages.

First, forget about the logging enable/disable states, and get your program reading and logging the data you want.

Then, work out how to best switch between the enabled disabled states. Reading a button press should not require an interrupt. As UKHeliBob has pointed out, your ISR is filled with errors and not likely to work.

Verify that your button wiring is correct. Read the button with digital read, determine the state, write the state to the lcd, let the logging routine conditional test execute or not.

Take a look at the StateChangeDetection example in the IDE examples 02 Digital. You may also need to debounce the switch so look at the Debounce example in there as well.

i used a "add up" approach from the Datalogger sample code, and now it is identified the problem is with LCD:

if i comment the line LiquidCrystal lcd(12, 11, 10, 9, 8, 7); before setup(), everything works fine: the time stamp and sensor data are all collected and logged to .txt file on the SD card, and the interrupt to enable/disable logging also works fine.

If i include the line LiquidCrystal lcd(12, 11, 10, 9, 8, 7);, suddenly it failed to read file on the SD card...

Any clue what is the cause? How come the LCD display interfere with SD card? (the LCD wiring works as validated use LCDDemo). i used the typical wiring: RS pin to digital pin 12; Enable pin to digital pin 11; D4 pin to digital pin 10; D5 pin to digital pin 9; D6 pin to digital pin 8; D7 pin to digital pin 7.

#include <SPI.h>
#include <SD.h>
#include <DHT.h>
#include <Wire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include <LiquidCrystal.h>

// On the Ethernet Shield, CS is pin 4. Note that even if it's not
// used as the CS pin, the hardware CS pin (10 on most Arduino boards,
// 53 on the Mega) must be left as an output or the SD library
// functions will not work.
const int chipSelect = 4;

#define DHTPIN 6     // what Arduino pin the DHT signal PIN is connected to


#define DHTTYPE DHT11   // DHT 11 
DHT dht(DHTPIN, DHTTYPE);

int sensorPin_sound = A0; // select the input pin for the sound meter
int sensorPin_light = A15; // select the input pin for the light meter

volatile int LoggingState = HIGH; // state flag for ISR: LOW/HIGH: Logging disabled/ Logging enabled 

LiquidCrystal lcd(12, 11, 10, 9, 8, 7); // initialize the library with the numbers of the interface pins


void setup()
{
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }

  // start dht sensor
  dht.begin();
 
  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);
  pinMode(chipSelect, 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.");
  
   File dataFile = SD.open("datalog.txt", FILE_WRITE);

  // if the file is available, write to it:
  if (dataFile) {
    dataFile.println("Date,Time,Temperature,Humidity,Sound,Light");
    dataFile.close();
  }
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening datalog.txt");
  }
  
   // set up interrupt from button press
  attachInterrupt(0,ISR_Button,RISING); // digital pin 2 // up
  
//  lcd.begin(16, 2);
}


// ----------------- ISR ------------------------
void ISR_Button(){

  LoggingState = !LoggingState;
//  lcd.clear(); //clear current lcd display
//  lcd.begin(16, 2);
  if(LoggingState == HIGH){
//    lcd.print("Logging Enabled");
    Serial.print("Logging Enabled");
  }
  else{
//    lcd.print("Logging Disabled");    
    Serial.print("Logging Disabled"); 
  }


}

void loop()
{
  
if(LoggingState == HIGH) // Only read and log when in Logging Started State - can be changed using button press
{  
  // make a string for assembling the data to log:
  String dataString = "";

  int sensor = dht.readTemperature();
  dataString += String(sensor);
  dataString += ",";
  sensor = dht.readHumidity();
  dataString += String(sensor);
  dataString += ",";
  sensor = analogRead(sensorPin_sound);
  dataString += String(sensor);
  dataString += ",";
  sensor = analogRead(sensorPin_light);
  dataString += String(sensor);

  // Process time and date
  tmElements_t tm;
  String stringTime = "";
  String stringDate= "";
  if (RTC.read(tm)) {
    stringTime = stringTime + save2digits(tm.Hour);
    stringTime = stringTime + ":";
    stringTime = stringTime + save2digits(tm.Minute);
    stringTime = stringTime + ":";
    stringTime = stringTime + save2digits(tm.Second);
    
    stringDate = stringDate + save2digits(tm.Month);
    stringDate = stringDate + save2digits(tm.Day);
    stringDate = stringDate + String(tmYearToCalendar(tm.Year)-2000);
  } else {
    if (RTC.chipPresent()) {
      Serial.println("The DS1307 is stopped.  Please run the SetTime");
      Serial.println();
    } else {
      Serial.println("DS1307 read error!  Please check the circuitry.");
      Serial.println();
    }
    delay(9000);
  }
  


  // 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.print(stringDate);
    dataFile.print(",");
    dataFile.print(stringTime);
    dataFile.print(",");
    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");
  }
  
//  // display on LCD as well
//  lcd.setCursor(0, 0);
//  lcd.print(stringDate);
//  lcd.print(",");
//  lcd.print(stringTime);
//  lcd.setCursor(0, 1);
//  lcd.print(dataString);
//  // -----------END of LCD ---------------
  
  delay(1000);
  
} // end of if (LoggingState == HIGH)
}

String save2digits(int number) {
  String value ="";
  if (number >= 0 && number < 10) {
    value="0";
  }
  value= String(value + number);
  return value;  
}

What pins does the SPI and SD libraries use?

Each time you open the file, you may be creating a new file, with one line of output in it.

If you want to add data to the file, you may need an "append" mode of opening the file.

I finally found the problem with my code: i wanted to use Interrupt 0 thus PIN2 and changed the LCD pins from lcd(12, 11, 5, 4, 3, 2) to lcd(12, 11, 10, 9, 8, 7). Apparently there is some incompatibility with SD card (with Ethernet shield). Once i changed the lcd pins back and uses PIN 19 for interrupt, everything works fine.

Thank you all for the suggestions.