Problema: lectura RTC + Guardado en SD - WEMOS D1 R2

Buen día, es mi primer consulta en el foro ya que estoy haciendo mi primer proyecto de este tipo. Estoy haciendo una estación meteorológica para la facultad que mida: temperatura, humedad y registre lluvias (mm caidos), guardando estos datos en una SD y registrando tambien la fecha y hora de cada evento.

Hardware:
Placa Wemos D1 R2 (usando el gestor de tarjetas “esp8266 by ESP8266 Community“)
Sensor humedad y temperatura DHT11
Celda de carga (3kg) con amplificador HX711
Reloj en tiempo real RTC3231
Modulo SD

Tengo programas por separado para cada componente y todos funcionan perfectamente.

Acá les dejo un programa completo, con todos los sensores. Puse algunas líneas de más para ir verificando que los sensores están funcionando.

Los problemas que encuentro son 2:

  1. Cuando tengo las líneas de DateTime now = rtc.now() [...] : el loop sólo se corre una vez y deja de funcionar. Sin embargo, en el SD.open que tengo en el loop para guardar los datos en "datos.txt", si bien supuestamente abre el archivo ya que ingresa en el "if", no me guarda los datos que le estoy pidiendo, ni genera el archivo.

  2. Cuando saco las lineas de DateTime now = rtc.now() [...]: el loop corre normalmente, sin embargo tampoco guarda los datos en el archivo "datos.txt", ni genera el archivo.

Para verificar el funcionamiento de la SD cree las líneas en el setup para generar un archivo de prueba y funciona correctamente.

Por otro lado, en otras versiones que fui haciendo encontré que si yo declaraba las variables en el setup (haciendo que esas variables pasen a ser un valor constante) el archivo "datos.txt" se genera correctamente y guarda los datos (obviamente con valores constantes, lo cual no sirve para nada, pero capaz nos puede dar un indicio de lo que esté sucediendo).

Muchas gracias! Espero sus respuestas.

Código:

#include <SPI.h>
#include <SD.h> // Incluir la librería SD estándar de Arduino
#include "DHT.h" // Incluir la libreria del sensor Humedad y Temperatua
#include "HX711.h" // Incluir la libreria del sensor balanza
#include <Wire.h> // Incluir la libreria de I2C
#include <RTClib.h> // Incluir la libreria de RTClib

#define PIN_CS 15 // Pin usado para activar las comunicaciones SPI de la tarjeta SD
#define DHTTYPE DHT11   // DHT 11 - Sensor humedad y temperatura

const int DHTPin = 14;     // Pin de sensor Temp y Humedad
const int sensorPin = 12; // Pin sensor lluvia
const int DOUT=0; // Pin digital balanza
const int CLK=4; // Pin digital balanza

DHT dht(DHTPin, DHTTYPE);
HX711 balanza;
RTC_DS3231 rtc;

File datos;
File prueba;

String fechaString = "";
String sensorString = "";
float h;
float t;
float ll;
float pluviografo;
int ano;
int mes;
int dia;
int hora;
int minuto;

void setup()
{ 
  Serial.begin(9600); // Preparar las comunicaciones serie para mostrar mensajes en la consola
 
  if (!rtc.begin()) { //// Iniciamos el Reloj en Tiempo Real
  Serial.println("No funciona el módulo RTC");
  return;
  }
// Ponemos en hora, solo la primera vez, luego comentar y volver a cargar.
// Ponemos en hora con los valores de la fecha y la hora en que el sketch ha sido compilado.
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));

  dht.begin(); // Iniciamos el sensor de humedad y temperatura y definimos las variables a utilizar
  Serial.print("Temperatura inicio: ");
  Serial.println(dht.readTemperature());
  Serial.print(" Humedad inicio: ");
  Serial.println(dht.readHumidity());
  
  pinMode(sensorPin, INPUT);  // Definir pin como entrada - Balanza
  pinMode(DOUT,OUTPUT); // Definir pin balanza como salida (probar con DOUT o CLK) - Balanza
  
  balanza.begin(DOUT, CLK); // Iniciamos el sensor de balanza
  balanza.set_scale(-542.5); // Establecemos la escala
  balanza.tare(20);  //El peso actual es considerado Tara.
  Serial.print("Lectura del valor de pluviografo:  ");
  Serial.print(balanza.get_units(20)/2.45,1);
  Serial.println("Pluviografo listo");  
  
  pinMode(PIN_CS,OUTPUT); // Es necesario configurar para salida de datos el pin conectado a CS/SS
  
  if(!SD.begin(PIN_CS)) { // Intentar inicializar las comunicaciones y el dispositivo y no hacer nada si no es posible
  Serial.println("Error iniciando la SD");
  return;
  }
  else {
  Serial.println("Tarjeta SD inicializada (pueden grabarse los datos)");
  }
  
  prueba = SD.open("prueba.txt",FILE_WRITE); // Archivo de prueba para generar archivo en SD
  if(prueba) {
  prueba.println("Escritura realizada con éxito");  
  Serial.println("Archivo de prueba generado con éxito");
  prueba.close();
  }
  else {
  Serial.print("Error generando el archivo de prueba");
  }
}

void loop() {
 
  fechaString = "";
  sensorString = "";
  h = dht.readHumidity();
  t = dht.readTemperature();
  pluviografo = balanza.get_units(20)/2.45;
  if(pluviografo < 0.05) { ll = 0; } else { ll = pluviografo; }

  DateTime now = rtc.now();

  ano = now.year();
  mes = now.month();
  dia = now.day();

  hora = now.hour();
  minuto = now.minute();
  
  fechaString += String (ano) + String ("/") + String (mes) + String ("/") + String (dia) + String (",");
  fechaString += String (hora) + String (":") + String (minuto);

  Serial.println(fechaString);

  sensorString += String (t) + String (",") + String (h) + String (",") + String (ll);
  
  Serial.println(sensorString);
  
  delay(1000);
  
  datos = SD.open("datos.txt",FILE_WRITE);
  if(datos) {
  Serial.println(datos);
  Serial.println("Documento creado correctamente");
  datos.print(fechaString);
  datos.println(sensorString);
  Serial.println(datos.size());
  datos.close();
  Serial.println("Datos guardados con éxito");
  }
  else {
  Serial.println("Error abriendo el archivo de escritura de datos");
  }
  delay(2000);
}

Monitor serie para el caso 1:

09:34:27.567 -> Lectura del valor de pluviografo:  -0.1Pluviografo listo
09:34:29.415 -> Tarjeta SD inicializada (pueden grabarse los datos)
09:34:29.415 -> Archivo de prueba generado con éxito
09:34:31.137 -> 2000/21/5,3:9
09:34:31.137 -> 18.30,58.00,0.00
09:34:32.157 -> 1
09:34:32.157 -> Documento creado correctamente
09:34:32.203 -> 0
09:34:32.203 -> Datos guardados con éxito

(Y ahí no realiza ninguna acción más).

Monitor serie para el caso 2:

09:37:14.670 -> Lectura del valor de pluviografo:  -0.2Pluviografo listo
09:37:16.524 -> Tarjeta SD inicializada (pueden grabarse los datos)
09:37:16.571 -> Archivo de prueba generado con éxito
09:37:18.299 -> 0/0/0,0:0
09:37:18.299 -> 18.40,58.00,0.00
09:37:19.271 -> 1
09:37:19.271 -> Documento creado correctamente
09:37:19.318 -> 0
09:37:19.318 -> Datos guardados con éxito
09:37:22.947 -> 0/0/0,0:0
09:37:22.947 -> 18.40,58.00,0.00
09:37:23.966 -> 1
09:37:23.966 -> Documento creado correctamente
09:37:23.966 -> 0
09:37:23.966 -> Datos guardados con éxito
09:37:27.634 -> 0/0/0,0:0
09:37:27.634 -> 18.50,58.00,0.00
09:37:28.621 -> 1
09:37:28.621 -> Documento creado correctamente
09:37:28.667 -> 0
09:37:28.667 -> Datos guardados con éxito

(Y así indefinidamente, como verán la linea que imprime el tamaño del archivo "datos.txt" antes de cerrarlo indica "0". Y como ya mencioné, ni siquiera aparece el archivo datos.txt en la SD.

//

ACTUALIZACIÓN 03/06/2021

Surbyte se ofreció a hacer una conexión remota para ver cual era el problema, teníamos 2:
1 - El void loop se detenía luego del primer registro.
2 - La memoria SD abría el archivo pero no graba el registro.

Del primer problema descubrimos que el inconveniente estaba con la función balanza.get_units(), eliminando esa linea el void loop continuaba. Aislamos el problema, y en un código aparte solo con la SD y la balanza funcionó perfectamente.

En posteriores pruebas que realicé, descubrí que si combinaba la lectura del RTC y de la balanza el loop se detenía, si dejaba sólo una de ella el loop continuaba.

El segundo problema logramos identificar que el inconveniente surge de la lectura del dht, los datos de la balanza y del RTC los graba con éxito, pero cuando incorporamos la lectura del dht no guarda ningún valor, ni siquiera los de la balanza y RTC.

Todavía no pude solucionar por completo ambos problemas.

Tu problema es que has malentendido string con String.
Usas Strings pero debes usar cadenas de bytes.
Entonces reemplaza la lectura de la hora por esto

He hecho modificaciones a tu código

#include <SPI.h>
#include <SD.h>         // Incluir la librería SD estándar de Arduino
#include "DHT.h"        // Incluir la libreria del sensor Humedad y Temperatua
#include "HX711.h"      // Incluir la libreria del sensor balanza
#include <Wire.h>       // Incluir la libreria de I2C
#include <RTClib.h>     // Incluir la libreria de RTClib

#define PIN_CS  15      // Pin usado para activar las comunicaciones SPI de la tarjeta SD
#define DHTTYPE DHT11   // DHT 11 - Sensor humedad y temperatura

const int DHTPin = 14;     // Pin de sensor Temp y Humedad
const int sensorPin = 12; // Pin sensor lluvia
const int DOUT = 0; // Pin digital balanza
const int CLK = 4; // Pin digital balanza

DHT dht(DHTPin, DHTTYPE);
HX711 balanza;
RTC_DS3231 rtc;

File datos;
File prueba;
char sensorbuffer[20];
char fechabuffer[20];
float h, t, ll;
float pluviografo;

void setup()
{
  Serial.begin(9600); // Preparar las comunicaciones serie para mostrar mensajes en la consola

  if (!rtc.begin()) { //// Iniciamos el Reloj en Tiempo Real
    Serial.println("No funciona el módulo RTC");
    return;
  }
  // Ponemos en hora, solo la primera vez, luego comentar y volver a cargar.
  // Ponemos en hora con los valores de la fecha y la hora en que el sketch ha sido compilado.
  // rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));

  dht.begin(); // Iniciamos el sensor de humedad y temperatura y definimos las variables a utilizar
  Serial.print("Temperatura inicio: ");
  Serial.println(dht.readTemperature());
  Serial.print(" Humedad inicio: ");
  Serial.println(dht.readHumidity());

  pinMode(sensorPin, INPUT);  // Definir pin como entrada - Balanza
  pinMode(DOUT, OUTPUT); // Definir pin balanza como salida (probar con DOUT o CLK) - Balanza

  balanza.begin(DOUT, CLK); // Iniciamos el sensor de balanza
  balanza.set_scale(-542.5); // Establecemos la escala
  balanza.tare(20);  //El peso actual es considerado Tara.
  Serial.print("Lectura del valor de pluviografo:  ");
  Serial.print(balanza.get_units(20) / 2.45, 1);
  Serial.println("Pluviografo listo");

  pinMode(PIN_CS, OUTPUT); // Es necesario configurar para salida de datos el pin conectado a CS/SS

  if (!SD.begin(PIN_CS)) { // Intentar inicializar las comunicaciones y el dispositivo y no hacer nada si no es posible
    Serial.println("Error iniciando la SD");
    return;
  }
  else {
    Serial.println("Tarjeta SD inicializada (pueden grabarse los datos)");
  }

  prueba = SD.open("prueba.txt", FILE_WRITE); // Archivo de prueba para generar archivo en SD
  if (prueba) {
    prueba.println("Escritura realizada con éxito");
    Serial.println("Archivo de prueba generado con éxito");
    prueba.close();
  }
  else {
    Serial.print("Error generando el archivo de prueba");
  }
}

void loop() {
  char strT[6], strH[6], strLL[6];
  
  h = dht.readHumidity();
  t = dht.readTemperature();
  pluviografo = balanza.get_units(20) / 2.45;
  if (pluviografo < 0.05) {
    ll = 0;
  } else {
    ll = pluviografo;
  }

  DateTime now = rtc.now();

  sprintf(fechabuffer,"%02d/%02d/%02d,%02d:%02d", now.year(), now.month(), now.day(), now.hour(), now.minute());
  Serial.println(fechabuffer);
  dtostrf(t, 3, 1, strT); // el primero es la cantidad de digitos incluida la coma y el segundo cant de decimales
  dtostrf(h, 3, 1, strH);
  dtostrf(ll, 3, 1, strLL);
  sprintf(sensorbuffer,"%s,%s,%s", strT, strH, strLL);
  Serial.println(sensorbuffer);

  delay(1000);

  datos = SD.open("datos.txt", FILE_WRITE);
  if (datos) {
    Serial.println(datos);
    Serial.println("Documento creado correctamente");
    datos.print(fechabuffer);
    datos.println(sensorbuffer);
    Serial.println(datos.size());
    datos.close();
    Serial.println("Datos guardados con éxito");
  }
  else {
    Serial.println("Error abriendo el archivo de escritura de datos");
  }
  delay(2000);
}

Hola! Gracias por tu comentario, es mi primer proyecto y hay muchas cosas que las estoy aprendiendo sobre la marcha. Igualmente, copie el código que pusiste pero sigo teniendo la misma respuesta en el monitor serial:

00:17:26.427 -> Lectura del valor de pluviografo:  0.2Pluviografo listo
00:17:28.278 -> Tarjeta SD inicializada (pueden grabarse los datos)
00:17:28.278 -> Archivo de prueba generado con éxito
00:17:30.039 -> 2021/06/02,00:17
00:17:30.039 -> nan,nan,0.1
00:17:31.010 -> 1
00:17:31.010 -> Documento creado correctamente
00:17:31.056 -> 0
00:17:31.056 -> Datos guardados con éxito

(No le des bola al valor "nan" simplemente no estaba conectado el dht al pin digital)

Como veras me sigue indicando que el tamaño del archivo sigue siendo 0 y luego del primer ciclo deja de correr.

Ayer tuve la posibilidad de probar este mismo código con una placa Arduino Mega original y funciono perfecto. No sé si habrá alguna configuración de la placa Wemos que deba modificar para que funcione o qué... no creo que esto sea algo muy complejo que la placa no pueda realizar, simplemente creo que hay algo que se debe considerar por ser otro tipo de placa que no lo estoy haciendo.

Nuevamente, muchas gracias por tu comentario!

El NAN es que no esta leyendo el DHT. Aisla el problema
Intenta medir el DHT11 por separado con la librería y confirma que lo hace correctamente.
Tienes un DHT11 o sea, mides temperatura como entero y humedad como entero, no tiene decimales. No se porque luego pretendes mostrar 1 decimal
Supuestamente esta conectado al pin 14. Confirma que funciona correctamente.
Cuando lo hagas continuamos.

Sisi. El DHt funciona correctamente. Simplemente es que se me salio cable al pin digital en ese momento, por eso salió el NAN. Pero funciona si coloco el cable, sin embargo, sigo teniendo el mismo problema que te mencionaba.