Soil humidity datalogger

Hello!
I'm working on a datalogger (using Arduino MEGA) for a few measurements for my master of science thesis. The logger has 12 soil humidity sensors, one sensor for relative humidity and temperature, two fans, and LCD that automatically showcases the current measurements in a certain order as a simple button is clicked. The measurements happen every 30 seconds and all the data is logged, together with the date and time, on an SD card.
Everything works but, for some reason, sometimes the file just does not get created. Obviously I've put a few lines that stop the whole thing if

  1. an SD module is not present
  2. the file cannot be created/accessed for the first time (this is necessary to write header)
  3. the file cannot be accessed during a measurement

The error messages never appear. I can't understand what I'm doing wrong, I suspected that maybe it could be because I take the SD out at the wrong time, so I'm using the LED on the board to signal when the measurement is taking place. I always take it out during the resting cycle.
The code is a little long so I'll hide it.

DHT to pin 22
LCD: rs = 2, en = 3, d4 = 4, d5 = 5, d6 = 6, d7 = 7
Soil sensors to pins A15-A4
Button to pin 24
RTC (clock) to pin 20(SDA) and 21(SCL)
SD to pin 50 (MISO), 51 (MOSI), 52 (SCK), 53 (CS)


#include <LiquidCrystal.h>
#include <SimpleDHT.h>
#include <RTClib.h>
#include <Wire.h>
#include <SD.h>
#include <SPI.h>

void writeTime();

#define ENABLEA 9
#define ENABLEB 11
#define DIRA 8
#define DIRB 10
SimpleDHT11 dht11(22); //RH and T 
const int rs = 2, en = 3, d4 = 4, d5 = 5, d6 = 6, d7 = 7;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);  
RTC_DS3231 rtc;  //clock
DateTime nowDT;
File data_file;
int soil1t = 0;  // for soil humidity
int soil1b = 0;
int soil2t = 0;
int soil2b = 0;
int soil3t = 0;
int soil3b = 0;
int soil4t = 0;
int soil4b = 0;
int soil5t = 0;
int soil5b = 0;
int soil6t = 0;
int soil6b = 0;
//const int SDpin = 20; 
const int buttonPin = 24; 
bool buttonState = 0;
byte temperature = 0;
byte humidity = 0;
unsigned long previousMillis = 0;
const int interval = 30000;


void setup() {
  
  pinMode(LED_BUILTIN, OUTPUT); // pin 13 lights up when measurements are being taken 
  lcd.begin(16, 2);
  lcd.print("Prova LCD");
  delay(1000);
  lcd.clear();
  
  pinMode(buttonPin, INPUT_PULLUP);
  Serial.begin(9600);
  digitalWrite(LED_BUILTIN, LOW);


  // setup SD
  if (SD.begin(53))
  { 
    Serial.println("modulo SD pronto");
    lcd.setCursor(0,0);
    lcd.print("SD OK");
    delay(1000);
    lcd.clear();
  } 
  else
  { 
    Serial.println("SD non funzionante");
    lcd.print("errore SD (1)");    
    while(1);
  }

  // writing Header on data sheet (date, time, RH, T, 1Top, 1Bottom, 2T, 2B ... 6T, 6B)

  data_file = SD.open("test1.txt", FILE_WRITE);
  if (data_file) 
  {
    Serial.print("Intesto il file...");
    lcd.print("intesto il file");
    data_file.print("date, time, RH, T, 1T, 1B, 2T, 2B, 3T, 3B, 4T, 4B, 5T, 5B, 6T, 6B");
    data_file.print("\n");
    data_file.close();
    Serial.println("fatto");
    lcd.clear();
    lcd.print("file OK");
    delay(1000);
    lcd.clear();
  } 
  else 
  {
    Serial.println("SD non aperta. Cambia SD o prova a formattarla.");
    lcd.print("errore SD (2)");
    while(1);
  }   

  // clock setup
  if (! rtc.begin())
  {
    Serial.println("Clock non funzionante");
    lcd.print("errore clock");
    while (1);
  }
  else 
  { 
    Serial.print("Imposto il tempo...");
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); 
    // rtc.adjust(DateTime(2023, 4, 12, 3, 0, 0)); //if we need to start the thing without a pc
    Serial.println("fatto");
    lcd.print("Clock OK");
    delay(1000);
    lcd.clear();
  }
 
  //setup theta sensors 
  pinMode(A15, INPUT);    //for now only A15-A11, relative to 1T, 1B, 2T, 2B e 3T (see photo for reference)
  pinMode(A14, INPUT);
  pinMode(A13, INPUT);
  pinMode(A12, INPUT);
  pinMode(A11, INPUT);
  pinMode(A10, INPUT);
  pinMode(A9, INPUT);
  pinMode(A8, INPUT);
  pinMode(A7, INPUT);
  pinMode(A6, INPUT);
  pinMode(A5, INPUT);
  pinMode(A4, INPUT);

  pinMode(ENABLEA, OUTPUT);
  pinMode(ENABLEB, OUTPUT);
  pinMode(DIRA, OUTPUT);
  pinMode(DIRB, OUTPUT);

  digitalWrite(ENABLEA, HIGH); // fans
  digitalWrite(ENABLEB, HIGH);
  digitalWrite(DIRA, HIGH); 
  digitalWrite(DIRB, HIGH);

}

void loop() {

  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) { // the measurements are taken every 30 seconds (from here to line 287)    
    previousMillis = currentMillis;

  digitalWrite(LED_BUILTIN, HIGH); // led lights up

  // opening the file and writing the date and time
  data_file = SD.open("test1.txt", FILE_WRITE);
  int err = SimpleDHTErrSuccess;

  if (data_file) {
    writeTime();
    data_file.close();
  }
  else { 
    Serial.println("SD non aperta. Cambia SD o prova a formattarla."); 
    lcd.print("errore SD(3)");
    while(1);
  }

  // RH and T measurements
  if ((err = dht11.read(&temperature, &humidity, NULL)) != SimpleDHTErrSuccess) 
  {
    Serial.print("Errore nella lettura del DHT");
    lcd.print("errore DHT");
    while(err = dht11.read(&temperature, &humidity, NULL) != SimpleDHTErrSuccess);
    lcd.clear();
  }
  else
  { 
    data_file = SD.open("test1.txt", FILE_WRITE);
    Serial.print("H = ");
    Serial.print(humidity);
    Serial.print(", T = ");
    Serial.println(temperature);
    data_file.print(humidity);
    data_file.print(",");
    data_file.print(temperature);
    data_file.print(",");
    data_file.close();
  }
  

  //writing theta measurements
  data_file = SD.open("test1.txt", FILE_WRITE);
  soil1t = analogRead(A15);
  data_file.print(soil1t);
  data_file.print(",");
  soil1b = analogRead(A14);
  data_file.print(soil1b);
  data_file.print(",");
  soil2t = analogRead(A13);
  data_file.print(soil2t);
  data_file.print(",");
  soil2b = analogRead(A12);
  data_file.print(soil2b);
  data_file.print(",");
  soil3t = analogRead(A11);
  data_file.print(soil3t);
  data_file.print(",");
  soil3b = analogRead(A10);
  data_file.print(soil3b);
  data_file.print(",");
  soil4t = analogRead(A9);
  data_file.print(soil4t);
  data_file.print(",");
  soil4b = analogRead(A8);
  data_file.print(soil4b);
  data_file.print(",");
  soil5t = analogRead(A7);
  data_file.print(soil5t);
  data_file.print(",");
  soil5b = analogRead(A6);
  data_file.print(soil5b);
  data_file.print(",");
  soil6t = analogRead(A5);
  data_file.print(soil6t);
  data_file.print(",");
  soil6b = analogRead(A4);
  data_file.print(soil6b);
  data_file.print("\n");
  data_file.close(); 
  
  digitalWrite(LED_BUILTIN, LOW);
  }

  while (millis() - previousMillis <= interval) //until it's not time for a new measurement, check if the button is pressed
  {
    // LCD shows data if button is pressed
    buttonState = digitalRead(buttonPin);
    if (buttonState == 0) 
      {
        Serial.println("Bottone");
        lcd.clear();

        lcd.print(nowDT.day());
        lcd.print("/");
        lcd.print(nowDT.month());
        lcd.print(",");
        lcd.print(nowDT.hour());
        lcd.print(":");
        if (nowDT.minute()<10)
        {
          lcd.print("0");
          lcd.print(nowDT.minute());
        }
        else 
        { lcd.print(nowDT.minute());} 
        lcd.print(":");
        if (nowDT.second()<10)
        {
          lcd.print("0");
          lcd.print(nowDT.second());
        }
        else { lcd.print(nowDT.second()); }
        delay(1000);
        
        lcd.clear();
        lcd.print("H = ");
        lcd.print(humidity);  
        lcd.setCursor(0, 1);
        lcd.print("T = ");
        lcd.print(temperature);
        delay(1500);

        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print("1T = ");
        lcd.print(soil1t);
        lcd.setCursor(0,1);
        lcd.print("1B = ");
        lcd.print(soil1b);
        delay(1500);

        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print("2T = ");
        lcd.print(soil2t);
        lcd.setCursor(0,1);
        lcd.print("2B = ");
        lcd.print(soil2b);
        delay(1500);

        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print("3T = ");
        lcd.print(soil3t);
        lcd.setCursor(0,1);
        lcd.print("3B = ");
        lcd.print(soil3b);
        delay(1500);

        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print("4T = ");
        lcd.print(soil4t);
        lcd.setCursor(0,1);
        lcd.print("4B = ");
        lcd.print(soil4b);
        delay(1500);

        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print("5T = ");
        lcd.print(soil5t);
        lcd.setCursor(0,1);
        lcd.print("5B = ");
        lcd.print(soil5b);
        delay(1500);

        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print("6T = ");
        lcd.print(soil6t);
        lcd.setCursor(0,1);
        lcd.print("6B = ");
        lcd.print(soil6b);
        delay(1500);

        lcd.clear();
        buttonState = 1;
      }
    }
}



void writeTime()
{
  nowDT = rtc.now();

  // debug
  Serial.print(nowDT.day());
  Serial.print("/");
  Serial.print(nowDT.month());
  Serial.print(",");
  Serial.print(nowDT.hour());
  Serial.print(":");
  if (nowDT.minute()<10)
  {
    Serial.print("0");
    Serial.print(nowDT.minute());
  }
  else 
  { Serial.print(nowDT.minute());} 
  Serial.print(":");
  if (nowDT.second()<10)
  {
    Serial.print("0");
    Serial.println(nowDT.second());
  }
  else { Serial.println(nowDT.second()); }

  //  
  data_file.print(nowDT.day()); 
  data_file.print("/");
  data_file.print(nowDT.month());
  data_file.print(",");
  data_file.print(nowDT.hour());
  data_file.print(":");
  if (nowDT.minute() < 10)
  {
    data_file.print("0");
    data_file.print(nowDT.minute());
  }
  else
  { 
    data_file.print(nowDT.minute());
  }
  data_file.print(":");
  if (nowDT.second() < 10)
  {
    data_file.print("0");
    data_file.print(nowDT.second());
  }
  else
  { 
    data_file.print(nowDT.second());
  }
  data_file.print(",");
}

Thanks in advance!

No, we actually need to see the hidden code. Please read the forum intro...

Me too.

What type of help do you expect?

Sorry, I haven't used a forum in a few years :sweat_smile: it should be readable by now

This is good, but I know when to remove the SD as not to corrupt the file. The LED on pin 13 lights up when the file is being written and turns off as the system waits. During that waiting time the file is closed, so it's not getting corrupted.

I'd suggest you start by commenting out large chunks of the program to see if you can find where the problem lies.

I've not used the SD card library very much but I seem to recall from various forum posts that it's not a good idea to keep opening and closing the file you want to write to.

I think the general advice is to open the file during setup and then leave it open.

Thank you, I might try that. My only concern is that if the power goes out for some reason, the file is inevitably lost since it never closes except when you intend to take the sd out. So I'll think about it. Thank you!

I found NotePad++ opens those files without an issue. So far.

If that were true, it would be a serious problem and everyone would know about it, but they don't, so I'm betting it isn't. I'm also betting you will have far more grief with files full of junk if you refuse to follow the advice in post#8.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.