[SOLUCIONADO]Guardar fecha y hora de módulo RTC en SD

¿Qué tal? Estoy intentando realizar un datalogger con un DHT11, un DS1307 y un módulo micro SD Catalex. He probado cada uno de ellos por separado y perfecto, DHT11 + DS1307 también funciona, DHT11 + SD perfecto; pero cuando intento juntar el DS1307 y la SD siempre me da error al intentar abrir el archivo. He buscado todo lo posible en el foro y otros sitios, pero no he encontrado solución al problema. Seguramente será una tontería, pero muchos ojos ven más que dos, así que os pido ayuda.
Os dejo las URL en las que más me he apoyado y el código del programa con los tres módulos juntos:

https://forum.arduino.cc/index.php?topic=443140.0

https://forum.arduino.cc/index.php?topic=357438.0

/*  
 *  BUS SPI
 *  SCK-----> 13(UNO) 52(MEGA)
 *  MOSI----> 11(UNO) 51(MEGA)
 *  MISO----> 12(UNO) 50(MEGA)
 *  CS------>  8(UNO) 8(MEGA) 
 *  
 *  BUS I2C
 *  SDA-----> A4(UNO) 20(MEGA)
 *  SCL-----> A5(UNO) 21(MEGA)
 */

// 1.- LIBRERIAS INCLUIDAS

#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include <RTClib.h>
#include <DHT.h>

// 2.- CREACIÓN DE OBJETOS Y DEFINICIÓN DE PINES

RTC_DS1307 RTC;

#define DHTPIN 2
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);

const int CS = 8;  // Para este módulo.

// 3.- VARIABLES A CREAR 

byte temperatura = 0; // Recoge los datos de temperatura cada minuto.
byte humedad = 0;     // Recoge los datos de humedad cada minuto.

// 4.- SETUP

void setup()
{
  // Inicialización de dispositivos

  Serial.begin(9600);
  dht.begin();
  Wire.begin();
  RTC.begin();

  // Se establece fecha y hora sólo la primera vez, una vez hecho se comenta esta línea
  

  RTC.adjust(DateTime(__DATE__,__TIME__));
  if(!RTC.isrunning())
  {
    Serial.println("RTC no listo");
    delay(3000);
  }

  pinMode(53, OUTPUT);
  
  Serial.print("Inicializando SD...");
  
  // Mira si la tarjeta está presente y puede ser inicializada

  if (!SD.begin(CS)) 
  {
    Serial.println("Fallo o tarjeta no presente");
    return;
  }
  Serial.println("Tarjeta SD OK");
  delay(2000);
}

// 5.- LOOP

void loop()
{
  DateTime now = RTC.now();   // Coge la fecha y la hora del reloj
   Serial.print(now.day(),DEC);
   Serial.print("/");
   Serial.print(now.month(),DEC);
   Serial.print("/");
   Serial.print(now.year(),DEC);
   Serial.print("   ");
   Serial.print(now.hour(),DEC);
   Serial.print(":");
   Serial.println(now.minute(),DEC);
   Serial.println("");
   
  File archivo;

  // Se guardan los datos cada 10 minutos en la SD y se imprime la fecha y la hora al principio de la lectura.
  
  if(archivo)    // Si el archivo existe...
  {
      if(now.minute() == 0 && now.second() == 0)
      {
        temperatura = leerTemp();
        humedad = leerHum();
        archivo = SD.open("datos.txt", FILE_WRITE);
        archivo.print(now.day(),DEC);
        archivo.print("/");
        archivo.print(now.month(),DEC);
        archivo.print("/");
        archivo.print(now.year(),DEC);
        archivo.print("   ");
        archivo.print(now.hour(),DEC);
        archivo.print(":");
        archivo.println(now.minute(),DEC);
        archivo.println("");
        archivo.print("Temperatura: ");
        archivo.print(temperatura);
        archivo.println("ºC");
        archivo.print("Humedad: ");
        archivo.print(humedad);
        archivo.println("%");
        archivo.println("");
        archivo.close();
      }

      if(now.minute() == 10 && now.second() == 0)
      {
        temperatura = leerTemp();
        humedad = leerHum();
        archivo = SD.open("datos.txt", FILE_WRITE);
        archivo.print(now.hour(),DEC);
        archivo.print(":");
        archivo.println(now.minute(),DEC);
        archivo.println("");
        archivo.print("Temperatura: ");
        archivo.print(temperatura);
        archivo.println("ºC");
        archivo.print("Humedad: ");
        archivo.print(humedad);
        archivo.println("%");
        archivo.println("");
        archivo.close();
      }

    else if(now.minute() == 20 && now.second() == 0)
    {
      temperatura = leerTemp();
      humedad = leerHum();
      archivo = SD.open("datos.txt", FILE_WRITE);
      archivo.print(now.hour(),DEC);
      archivo.print(":");
      archivo.println(now.minute(),DEC);
      archivo.println("");
      archivo.print("Temperatura: ");
      archivo.print(temperatura);
      archivo.println("ºC");
      archivo.print("Humedad: ");
      archivo.print(humedad);
      archivo.println("%");
      archivo.println("");
      archivo.close();
    }

    else if(now.minute() == 30 && now.second() == 0)
    {
      temperatura = leerTemp();
      humedad = leerHum();
      archivo = SD.open("datos.txt", FILE_WRITE);
      archivo.print(now.hour(),DEC);
      archivo.print(":");
      archivo.println(now.minute(),DEC);
      archivo.println("");
      archivo.print("Temperatura: ");
      archivo.print(temperatura);
      archivo.println("ºC");
      archivo.print("Humedad: ");
      archivo.print(humedad);
      archivo.println("%");
      archivo.println("");
      archivo.close();
    }

    else if(now.minute() == 40 && now.second() == 0)
    {      
      temperatura = leerTemp();
      humedad = leerHum();
      archivo = SD.open("datos.txt", FILE_WRITE);
      archivo.print(now.hour(),DEC);
      archivo.print(":");
      archivo.println(now.minute(),DEC);
      archivo.println("");
      archivo.print("Temperatura: ");
      archivo.print(temperatura);
      archivo.println("ºC");
      archivo.print("Humedad: ");
      archivo.print(humedad);
      archivo.println("%");
      archivo.println("");
      archivo.close();
    }
   
    else if(now.minute() == 50 && now.second() == 0)
    {
      temperatura = leerTemp();
      humedad = leerHum();
      archivo = SD.open("datos.txt", FILE_WRITE);
      archivo.print(now.hour(),DEC);
      archivo.print(":");
      archivo.println(now.minute(),DEC);
      archivo.println("");      
      archivo.print("Temperatura: ");
      archivo.print(temperatura);
      archivo.println("ºC");
      archivo.print("Humedad: ");
      archivo.print(humedad);
      archivo.println("%");
      archivo.println("");
      archivo.close();
    }
  }
  
  else
  {
    Serial.println("Error abriendo datos.txt");
  }
  delay(1000);
}

// 6.- FUNCIONES EXTERNAS

byte leerTemp()
{
  byte temp;
  temp = dht.readTemperature();
  return temp;
}

byte leerHum()
{
  byte hum;
  hum = dht.readHumidity();
  return hum;
}

Espero que podáis ver algo que a mi se me escapa. Gracias por anticipado y perdón por el tocho.

File archivo;

  if (archivo)   // Si el archivo existe...

Un objeto File "vacío" nunca equivaldría a true en contexto booleano.

Además, si lo vas a abrir para escritura no tiene sentido verificar si existe; se crearía de cualquier modo.

Donde se vale realizar dicha verificación, es después de intentar abrirlo:

File archivo = SD.open("datos.txt", FILE_WRITE);

if (archivo) { // Si realmente se abrió
  // Hacer cosas con el archivo
  archivo.close(); //  Última pero indispensable
}

Tambien estas condicionando la grabacion de los datos a que los minutos sean x y los segundos exactamente 0 ,esto puede ser que no coincida teniendo un delay de 1 segundo durante el cual no se hace nada.Puedes usar millis() para que cada 10 minutos se ejecute la lectura y ahorrar lineas:

#define INTERVALO 600000 // 10 minutos
unsigned long tiempo;
void setup() {
tiempo = millis();
  //tu codigo
}
void loop(){
  if ( (millis() - tiempo) > INTERVALO ) {
    // Entonces lees la hora y grabas datos
    tiempo = millis();
  }
}

Si prefieres como lo tienes ,pon todo el codigo que se repite en una funcion y la llamas.

¡Hola, que tal! No he tenido tiempo hasta esta mañana de ponerme a ello. Gracias por las respuestas.
Vamos por partes:

Lucario448: sabía que se me pasaba algo por alto, pero no lo veía. Lo cambié y funcionaba. Gracias.

jose: he hecho tal y como indicas y parece funcionar, solo que cuando pasa un tiempo empieza a ejecutar la condición del else. Paso el código a ver si se me ha ido algo o que. Gracias a ti también.

  DateTime now = RTC.now();   // Coge la fecha y la hora del reloj

  // Con esto nos ahorramos un montón de líneas
  
  char bufferFechaHora[17];
  sprintf(bufferFechaHora, "%02d/%02d/%02d %02d:%02d", now.day(), now.month(), now.year(), now.hour(), now.minute());
  
  Serial.println(bufferFechaHora); 
   
  File archivo = SD.open("datos.txt", FILE_WRITE);

  // Se guardan los datos cada 10 minutos en la SD y se imprime la fecha y la hora al principio de la lectura.
  
  if(archivo)    // Si el archivo existe...
  {
      if((millis() - tiempo) > intervalo)
      {
        temperatura = leerTemp();
        humedad = leerHum();

        archivo.println(bufferFechaHora);
        archivo.print("Temperatura: ");
        archivo.print(temperatura);
        archivo.println("ºC");
        archivo.print("Humedad: ");
        archivo.print(humedad);
        archivo.println("%");
        archivo.println("");
        archivo.close();
      
        Serial.println(bufferFechaHora); 
        Serial.println("Datos guardados correctamente");

        tiempo = millis();
     }

     else
     {
        Serial.println("Error abriendo datos.txt");
     }

  delay(1000);

En principio esto es una prueba, ya que iría dentro de otro programa más grande donde ya uso millis(), entonces no sé si puedo llamar a la función más veces.

Gracias.

Claro ,porque el else pertenece a la condicion if((millis() - tiempo) > intervalo) y siempre que no sea cierto saltara al else.La idea es que todo lo que concierne a la lectura de sensores y la escritura en la SD se ejecute solo cada intervalo de 10 minutos ,por lo tanto no tiene sentido que estes abriendo el archivo y preguntando si existe antes de saber si el intervalo ha pasado o no:

Si ha pasado intervalo de tiempo:
-Leo sensores
-Leo hora
-Abro fichero
-Grabo datos
Si no ha pasado el intervalo ,no hago nada ,o sea no hace falta clausula else.

Tambien puedes simultanear varios intervalos ,cada uno con su variable para almacenar el tiempo y su diferente tiempo.

Mira aqui.. quizas te sirva el ejemplo que puse:
Ejemplo Aqui

Bueno, al fin he conseguido que me guarde los datos cuando yo quiero. El problema que se me presenta ahora es que me los guarda un montón de veces (entre 16 y 24 he contado :o ) en lugar de 1. Éste es el código:

/*  
 *  BUS SPI
 *  SCK-----> 13(UNO) 52(MEGA)
 *  MOSI----> 11(UNO) 51(MEGA)
 *  MISO----> 12(UNO) 50(MEGA)
 *  CS------>  8(UNO) 8(MEGA) 
 *  
 *  BUS I2C
 *  SDA-----> A4(UNO) 20(MEGA)
 *  SCL-----> A5(UNO) 21(MEGA)
 */

// 1.- LIBRERIAS INCLUIDAS

#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include <RTClib.h>
#include <DHT.h>

// 2.- CREACIÓN DE OBJETOS Y DEFINICIÓN DE PINES

RTC_DS1307 RTC;

#define DHTPIN 2
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);

const int CS = 8;  // Para este módulo.

// 3.- VARIABLES A CREAR 

byte temperatura[5]; // Recoge los datos de temperatura cada minuto.
byte humedad[5];     // Recoge los datos de humedad cada minuto.
byte tempMin = 0;
//byte tempMax = 0;
int tempMedia = 0;

//int hora = 0;
int minuto = 0;
int segundo = 0;

// 4.- SETUP

void setup()
{
  // Inicialización de dispositivos

  Serial.begin(9600);
  dht.begin();
  Wire.begin();
  RTC.begin();

  // Se establece fecha y hora sólo la primera vez, una vez hecho
  // se comenta esta línea y se vuelve a cargar el programa.

  //RTC.adjust(DateTime(__DATE__,__TIME__));
  if(!RTC.isrunning())
  {
    Serial.println("RTC no listo");
    delay(3000);
  }

  pinMode(53, OUTPUT);
  
  Serial.print("Inicializando SD...");
  
  // Mira si la tarjeta está presente y puede ser inicializada

  if (!SD.begin(CS)) 
  {
    Serial.println("Fallo o tarjeta no presente");
    return;
  }
  Serial.println("Tarjeta SD OK");
  delay(2000);
}

// 5.- LOOP

void loop()
{
  DateTime now = RTC.now();   // Coge la fecha y la hora del reloj
  
  //hora = now.hour();
  minuto = now.minute();  
  segundo = now.second();
 
  char bufferFechaHora[17];   // Buffer para guardar la fecha y la hora

  // Se guardan los datos cada 5 minutos en la SD y se imprime la fecha y la hora al principio de la lectura.
  
      if(minuto == 0 && segundo == 0)
      {        
        temperatura[0] = leerTemp();
        humedad[0] = leerHum();

        // Convertimos los datos de fecha y hora en una cadena para poder guardarla de una vez
        sprintf(bufferFechaHora, "%02d/%02d/%02d %02d:%02d", now.day(), now.month(), now.year(), now.hour(), now.minute());

        File archivo = SD.open("datos.txt", FILE_WRITE);
        archivo.println(bufferFechaHora);
        archivo.print("Temperatura: ");
        archivo.print(temperatura[0]);
        archivo.println("ºC");
        archivo.print("Humedad: ");
        archivo.print(humedad[0]);
        archivo.println("%");
        archivo.println("");
        archivo.close();
      
        Serial.println("Datos guardados correctamente");        
      }

      else if(minuto == 5 && segundo == 0)
      {
        temperatura[1] = leerTemp();
        humedad[1] = leerHum();

        sprintf(bufferFechaHora, "%02d/%02d/%02d %02d:%02d", now.day(), now.month(), now.year(), now.hour(), now.minute());

        File archivo = SD.open("datos.txt", FILE_WRITE);
        archivo.println(bufferFechaHora);
        archivo.print("Temperatura: ");
        archivo.print(temperatura[1]);
        archivo.println("ºC");
        archivo.print("Humedad: ");
        archivo.print(humedad[1]);
        archivo.println("%");
        archivo.println("");
        archivo.close();
         
        Serial.println("Datos guardados correctamente");
      }

      else if(minuto == 10 && segundo == 0)
      {
        temperatura[2] = leerTemp();
        humedad[2] = leerHum();

        sprintf(bufferFechaHora, "%02d/%02d/%02d %02d:%02d", now.day(), now.month(), now.year(), now.hour(), now.minute());

        File archivo = SD.open("datos.txt", FILE_WRITE);
        archivo.println(bufferFechaHora);
        archivo.print("Temperatura: ");
        archivo.print(temperatura[2]);
        archivo.println("ºC");
        archivo.print("Humedad: ");
        archivo.print(humedad[2]);
        archivo.println("%");
        archivo.println("");
        archivo.close();
      
        Serial.println("Datos guardados correctamente");
      }

      else if(minuto == 15 && segundo == 0)
      {
        temperatura[3] = leerTemp();
        humedad[3] = leerHum();
        tempMin = temperatura[3];   // Se guarda como temperatura mínima

        sprintf(bufferFechaHora, "%02d/%02d/%02d %02d:%02d", now.day(), now.month(), now.year(), now.hour(), now.minute());

        File archivo = SD.open("datos.txt", FILE_WRITE);
        archivo.println(bufferFechaHora);
        archivo.print("Temperatura: ");
        archivo.print(temperatura[3]);
        archivo.println("ºC");
        archivo.print("Humedad: ");
        archivo.print(humedad[3]);
        archivo.println("%");
        archivo.println("");
        archivo.close();
      
        Serial.println("Datos guardados correctamente");
      }

      else if(minuto == 20 && segundo == 0)
      {      
        temperatura[4] = leerTemp();
        humedad[4] = leerHum();

        // Comprobamos si la nueva medición es menor que la anterior, si es así sustituye a la anterior
        if(tempMin > temperatura[4])
        {
          tempMin = temperatura[4];
        }

        sprintf(bufferFechaHora, "%02d/%02d/%02d %02d:%02d", now.day(), now.month(), now.year(), now.hour(), now.minute());

        File archivo = SD.open("datos.txt", FILE_WRITE);
        archivo.println(bufferFechaHora);
        archivo.print("Temperatura: ");
        archivo.print(temperatura[4]);
        archivo.println("ºC");
        archivo.print("Humedad: ");
        archivo.print(humedad[4]);
        archivo.println("%");
        archivo.println("");
        archivo.close();
      
        Serial.println("Datos guardados correctamente");
      }
   
      else if(minuto == 25 && segundo == 0)
      {
        temperatura[5] = leerTemp();
        humedad[5] = leerHum();

        // Igual que la anterior
        if(tempMin > temperatura[5])
        {
          tempMin = temperatura[5];
        }

        sprintf(bufferFechaHora, "%02d/%02d/%02d %02d:%02d", now.day(), now.month(), now.year(), now.hour(), now.minute());

        File archivo = SD.open("datos.txt", FILE_WRITE);
        archivo.println(bufferFechaHora);
        archivo.print("Temperatura: ");
        archivo.print(temperatura[5]);
        archivo.println("ºC");
        archivo.print("Humedad: ");
        archivo.print(humedad[5]);
        archivo.println("%");
        archivo.println("");
        archivo.close();
      
        Serial.println("Datos guardados correctamente");
      }

      // En esta última toma de datos se imprime la temperatura media y la temperatura mínima
      else if(minuto == 30 && segundo == 0)
      {
        for(int i=0;i<=5;i++)
        {
          tempMedia += temperatura[i];   // Sumamos todos los valores del array
        }

        tempMedia = tempMedia/6;    // y los dividimos entre el nº de valores

        sprintf(bufferFechaHora, "%02d/%02d/%02d %02d:%02d", now.day(), now.month(), now.year(), now.hour(), now.minute());

        File archivo = SD.open("datos.txt", FILE_WRITE);
        archivo.println(bufferFechaHora);
        archivo.print("Temperatura media: ");
        archivo.print(tempMedia);
        archivo.println("ºC");
        archivo.print("Temperatura mínima: ");
        archivo.print(tempMin);
        archivo.println("ºC");
        archivo.println("");
        archivo.close();
       
        Serial.println("Datos guardados correctamente");
      }
}

// 6.- FUNCIONES EXTERNAS

byte leerTemp()
{
  byte temp;
  temp = dht.readTemperature();
  return temp;
}

byte leerHum()
{
  byte hum;
  hum = dht.readHumidity();
  return hum;
}

Lo de que guarde datos cada 5 minutos es por no esperar una hora, aunque con una hora me hace lo mismo.

Hola.
Intenta implementar esto:
Crea una nueva variable global (bool guardado=false).

if ( (minuto%5) == 0) // Con este único if entrará cada cinco minutos. Los demás sobrarían.
{
    if (!guardado) // si no hemos guardado aún
    {
        // aquí guardamos los datos
        guardado=true; // "desarmamos" el guardado para que no entre más
    }
} 
else // si el minuto deja de ser el de guardado
{
    guardado = false; // "armamos" de nuevo el guardado para la siguiente ocasión
}

Ok. Al final lo he conseguido con añadirle un delay de 1 segundo. Lo he probado y funciona bien. Gracias a todos por vuestra ayuda.