No se registran los datos en la SD después de ciertas horas

Hola, tengo un problema. Soy nueva usando Arduino. Tengo dos Arduino Uno para le medición de sensores, los datos los almaceno en .TXT en una micro SD. He dejado mis pruebas corriendo por más de 24 horas (el intervalo de tiempo de adquisición de los datos es de 60seg), pero he notado que después de ciertas horas de trabajo ambos arduinos dejan de registrar datos como si se apagaran y vuelven a registrar los datos después de unas horas.

Leí en una pregunta que hicieron en el foro que tal vez tiene que ver con la capacidad de memoria que le quedó al arduino después de subir el sketch. Si es así, me gustaría saber que puedo hacer. Había pensado en decirle que despues de ciertos números de datos se guardara el archivo e iniciara otro, para así no sobre escribir y no perder mis datos anteriores.

Incluyo el código que estoy utilizando.

// ----------------------------------------------------------------------------------
//              LIBRERIAS PARA FUNCIONAMIENTO DE MODULOS Y SENSORES
// ----------------------------------------------------------------------------------

#include <Arduino.h>
#include <math.h>
#include <SPI.h>
#include <SD.h>
#include <Wire.h>   // incluye libreria para interfaz I2C
#include "RTClib.h"
#include <DHT.h>   
#include <Adafruit_MLX90614.h>         

// ----------------------------------------------------------------------------------
//                                      DECLARACIÓN 
// ----------------------------------------------------------------------------------

// Variable de tipo reloj
RTC_DS1307 RTC;
// Pin para el guardado en memoria SD
#define SSpin 10
// Pin para lectura del sensor digital de temperatura y humedad relativa
#define DHTPIN 2 
// Creación de variable tipo DHT11 o sensor de temperatura y humedad relativa
#define DHTTYPE DHT11
// Llamado de librerias de sensor DHT11
DHT dht(DHTPIN, DHTTYPE);
// Variable para guardado de datos de prueba de datos en tarjet SD
File archivo,D_sensores;
// I2C para Infrarrojo MLX90614
#define I2C_ADDR 0x5A //I2C adress
Adafruit_MLX90614 mlx = Adafruit_MLX90614();


// ----------------------------------------------------------------------------------
//                          CUERPO PRINCIPAL DEL CODIGO 
// ----------------------------------------------------------------------------------
void setup()
{  
  Serial.begin(9600);

  // ----------------------------------------------------------------------------------
  //                 INICIALIZACIÓN Y AJUSTE DE RELOJ CON HORA DE PC
  // ----------------------------------------------------------------------------------
  Wire.begin(); // Inicia el puerto I2C
  RTC.begin(); // Inicia la comunicaci¢n con el RTC
//  RTC.adjust(DateTime(__DATE__, __TIME__)); 		// Comentar cuando se trabaja arduino desconectado de PC y el reloj ya registro la hora alguna vez
  
  // ----------------------------------------------------------------------------------
  //         CREACIÓN Y ESCRITURA DE ENCABEZADO DE ARCHIVO DE DATOS DE SALIDA
  // ----------------------------------------------------------------------------------
  //++++++++++++++++++++++++++++ Lectura y guardado de sensores en tarjeta SD
  if (!SD.begin(SSpin))
  {
    Serial.println("Fallo en inicialización");
    return;
  }
  Serial.println("Inicialización correcta");

  // Creación de archivo de datos
  D_sensores = SD.open("EXT.txt", FILE_WRITE);    // Nota: Hacer archivos con nombres simples y sin usar guion bajo
  D_sensores.println("F,HH,Text,HRext,TAI,TOI,");
  D_sensores.close();

  // ----------------------------------------------------------------------------------
  //                            INICIALIZACIÓN DE SENSORES 
  // ----------------------------------------------------------------------------------

  // Inicialización de sensor de DHT11
  dht.begin();

  // Inicializacion de sensor BMP180
  //wait for serial connection to open (only necessary on some boards)
  while (!Serial);
  Wire.begin();

  // Inicialización MLX90614
   mlx.begin();

  // ----------------------------------------------------------------------------------
  //          DECLARACIÓN DE INTERVALO DE MEDICIÓN Y GUARDADO DE TIEMPO INICIAL
  // ----------------------------------------------------------------------------------
  
  // Paso de tiempo entre mediciones de sensor
  int Dt = 60;                        // Contador: {2,3,4,5,...} segundos 
  
   DateTime fecha = RTC.now();
    int t1_o = fecha.hour();
    int t2_o = fecha.minute();
    int t3_o = fecha.second();

  while (true) 
  {
    DateTime fecha = RTC.now();
    int t1 = fecha.hour();
    int t2 = fecha.minute();
    int t3 = fecha.second();

    int dif = ( (t1*3600) + (t2*60) + t3 ) - ( (t1_o*3600) + (t2_o*60) + t3_o );

    if ( dif == Dt )
    {
      float HR   = dht.readHumidity();     // Lectura de humedad relativa
      float Temp = dht.readTemperature();  // Lectura de temperatura en °C
      float TempAmbInfra = mlx.readAmbientTempC();
      float TempObjInfra = mlx.readObjectTempC();

      // Impresión en Monitor serie Arduino IDE
      Serial.print (fecha.day(),DEC);
      Serial.print ("/");
      Serial.print (fecha.month(),DEC);
      Serial.print ("/");
      Serial.print (fecha.year(),DEC);
      Serial.print (",");
      Serial.print (fecha.hour(),DEC);
      Serial.print (":");
      Serial.print (fecha.minute(),DEC);
      Serial.print (":");    
      Serial.print (fecha.second(),DEC);
      Serial.print (", Text= ");
      Serial.print(Temp);
      Serial.print("°C");
      Serial.print (", Hrext= ");
      Serial.print(HR);
      Serial.print(" %");
      Serial.print(",Tai= ");
      Serial.print(TempAmbInfra);
      Serial.print("°C");
      Serial.print(",Toi= ");
      Serial.print(TempObjInfra);
      Serial.println("°C");


      // Escritura en tarejta SD
      D_sensores = SD.open("EXT.txt", FILE_WRITE);
      D_sensores.print (fecha.day(),DEC);
      D_sensores.print ("/");
      D_sensores.print (fecha.month(),DEC);
      D_sensores.print ("/");
      D_sensores.print (fecha.year(),DEC);
      D_sensores.print (",");
      D_sensores.print (fecha.hour(),DEC);
      D_sensores.print (":");
      D_sensores.print (fecha.minute(),DEC);
      D_sensores.print (":");
      D_sensores.print (fecha.second(),DEC);
      D_sensores.print (",");
      D_sensores.print (Temp);
      D_sensores.print (",");
      D_sensores.print (HR);
      D_sensores.print (",");
      D_sensores.print (TempAmbInfra);
      D_sensores.print (",");
      D_sensores.print (TempObjInfra);
      D_sensores.println (",");
      D_sensores.close();
            
      // Guardado de tiempo de ultima medición
      t1_o = t1;
      t2_o = t2;
      t3_o = t3;
      // Espera de 1 segundo antes de continuar con el siguiente paso de tiempo
      delay (1000);
    }// End iF
  }// End while
  
}// End void setup

void loop()
{
  //
}

Y si tratas con

if ( dif >= Dt )

Para calcular la diferencia puedes hacer

unsigned long t4_o = fecha.unixtime();

que te devuelve el tiempo en segundos desde las 0:00:00 del 01/01/1970 y lo importante es que está en segundos (valga la redundancia).
Luego simplemente

unsigned long t4 = fecha.unixtime();

if (t4 - t4_o >= 60) {

y te evitas tantas cuentas.

Por cierto, todo lo que tienes dentro del lazo

while (true) {

deberías trasladarlo a loop() como para mantener el estándar de arduino.

Hay otros detalles que podrías cambiar, por ejemplo usar sprintf() para formatear la fecha y hora.

Saludos

Hazlo de este modo.
Esta operación esta generando overflow en determinadas circunstancias.

int dif = ( (t1*3600) + (t2*60) + t3 ) - ( (t1_o*3600) + (t2_o*60) + t3_o );

24 * 3600 = 86400 y eso supera a un entero.
Usa millis() en lugar de lo que estas usando.

// ----------------------------------------------------------------------------------
//              LIBRERIAS PARA FUNCIONAMIENTO DE MODULOS Y SENSORES
// ----------------------------------------------------------------------------------

#include <Arduino.h>
#include <math.h>
#include <SPI.h>
#include <SD.h>
#include <Wire.h>   // incluye libreria para interfaz I2C
#include "RTClib.h"
#include <DHT.h>   
#include <Adafruit_MLX90614.h>         

// ----------------------------------------------------------------------------------
//                                      DECLARACIÓN 
// ----------------------------------------------------------------------------------

// Variable de tipo reloj
RTC_DS1307 RTC;
// Pin para el guardado en memoria SD
#define SSpin 10
// Pin para lectura del sensor digital de temperatura y humedad relativa
#define DHTPIN 2 
// Creación de variable tipo DHT11 o sensor de temperatura y humedad relativa
#define DHTTYPE DHT11
// Llamado de librerias de sensor DHT11
DHT dht(DHTPIN, DHTTYPE);
// Variable para guardado de datos de prueba de datos en tarjet SD
File archivo,D_sensores;
// I2C para Infrarrojo MLX90614
#define I2C_ADDR 0x5A //I2C adress
Adafruit_MLX90614 mlx = Adafruit_MLX90614();

unsigned long Dt = 60000UL;      // 60*1000 msseg
unsigned long timeSave;
  

// ----------------------------------------------------------------------------------
//                          CUERPO PRINCIPAL DEL CODIGO 
// ----------------------------------------------------------------------------------
void setup() {  
  Serial.begin(9600);

  // ----------------------------------------------------------------------------------
  //                 INICIALIZACIÓN Y AJUSTE DE RELOJ CON HORA DE PC
  // ----------------------------------------------------------------------------------
  Wire.begin(); // Inicia el puerto I2C
  RTC.begin(); // Inicia la comunicaci¢n con el RTC
//  RTC.adjust(DateTime(__DATE__, __TIME__)); 		// Comentar cuando se trabaja arduino desconectado de PC y el reloj ya registro la hora alguna vez
  
  // ----------------------------------------------------------------------------------
  //         CREACIÓN Y ESCRITURA DE ENCABEZADO DE ARCHIVO DE DATOS DE SALIDA
  // ----------------------------------------------------------------------------------
  //++++++++++++++++++++++++++++ Lectura y guardado de sensores en tarjeta SD
  if (!SD.begin(SSpin))
  {
    Serial.println("Fallo en inicialización");
    return;
  }
  Serial.println("Inicialización correcta");

  // Creación de archivo de datos
  D_sensores = SD.open("EXT.txt", FILE_WRITE);    // Nota: Hacer archivos con nombres simples y sin usar guion bajo
  D_sensores.println("F,HH,Text,HRext,TAI,TOI,");
  D_sensores.close();

  // ----------------------------------------------------------------------------------
  //                            INICIALIZACIÓN DE SENSORES 
  // ----------------------------------------------------------------------------------

  // Inicialización de sensor de DHT11
  dht.begin();

  // Inicializacion de sensor BMP180
  //wait for serial connection to open (only necessary on some boards)
  while (!Serial);
  Wire.begin();

  // Inicialización MLX90614
   mlx.begin();
  
}// End void setup

void loop() {
  char buffer[20];
  DateTime fecha = RTC.now();

  if ( millis() - timeSave > Dt )     {
      float HR   = dht.readHumidity();     // Lectura de humedad relativa
      float Temp = dht.readTemperature();  // Lectura de temperatura en °C
      float TempAmbInfra = mlx.readAmbientTempC();
      float TempObjInfra = mlx.readObjectTempC();

      // Impresión en Monitor serie Arduino IDE
      sprintf(buffer, "%02d/%02d/%02d,%02d:%02d:%02d", fecha.day(), fecha.month(), fecha.year(), fecha.hour(), fecha.minute(), fecha.second());
      Serial.print(buffer);
      Serial.print (", Text= ");
      Serial.print(Temp);
      Serial.print("°C");
      Serial.print (", Hrext= ");
      Serial.print(HR);
      Serial.print(" %");
      Serial.print(",Tai= ");
      Serial.print(TempAmbInfra);
      Serial.print("°C");
      Serial.print(",Toi= ");
      Serial.print(TempObjInfra);
      Serial.println("°C");


      // Escritura en tarejta SD
      D_sensores = SD.open("EXT.txt", FILE_WRITE);
      sprintf(buffer, "%02d/%02d/%02d,%02d:%02d:%02d", fecha.day(), fecha.month(), fecha.year(), fecha.hour(), fecha.minute(), fecha.second());
      D_sensores.print(buffer);
      D_sensores.print (",");
      D_sensores.print (Temp);
      D_sensores.print (",");
      D_sensores.print (HR);
      D_sensores.print (",");
      D_sensores.print (TempAmbInfra);
      D_sensores.print (",");
      D_sensores.print (TempObjInfra);
      D_sensores.println (",");
      D_sensores.close();
            
      timeSave = milli();
    }// End iF
  }// End while
}

Gracias, voy a checar como me va.

Gracias, ahorita lo voy a compilar así. En algunos post vi lo de colocar en el loop lo que tengo dentro del while.

Lo que has hecho es la programación standard de C donde no existe el criterio setup() y loop().
setup se ejecuta 1 vez
Y loop se ejecuta como un while(1) asi que has hecho lo mismo y de hecho no hay nada mal en lo que habias programado.
El cambio real esta en usar millis() y contar los 60 segundos o 60000 mseg.
Tu error esta en las cuentas que generar un overflow.

Gracias, hoy voy a dejar en prueba este arduino y les comentaré que pasa.

Gracias, ayer deje corriendo los arduinos por 20 horas y registraron los datos sin problemas. No hubo perdida de datos, hoy dejaré nuevamente a prueba los arduinos pero por más tiempo.

Repito para que lo comprendas y lo recuerdes bien para la próxima.
Las operaciones en un microcontroladore tienen límites.
Un int o entero con signo va desde -2^15-1 hasta 2^15 o sea -32.767 hasta 32.768
Un unsigned int o enteror SIN signo va de 0 a 2^16 es decir 0 a 65.536
Tu cuenta de 24*3600 = 86.400 supera el limite de un entero con y sin signo.
Lo apropiado es un entero sin signo o sea 2^32 o sea 4.294.967.296
tampoco uses float. No es apropiado..
Asi que hay que tener preseten los limites de los tipos de variables empleados.

1 Like

¿Utilizaste unixtime?

Ese código hace que la variable timeSave se actualice cada 60001 milisegundos (o más, dependiendo del tiempo de proceso de lo que hay dentro del if), con lo eventualmente habrá un desfase con el RTC que haga que el programa salte una impresión.

Este efecto puede reducirse notablemente (pero no eliminarse del todo) cambiando la condición del if y reubicando la actualización de timeSave para ejecutarse inmediatamente al entrar al if, de esta forma:

if ( millis() - timeSave >= Dt )     {
   timeSave = millis(); 

Si se requiere eliminar por completo este efecto puede recurrirse al uso de interrupciones que monitoreen el pin SQW del RTC DS1307.

Aunque tal vez en esta aplicación esto no sea relevante, puede serlo en otras o cuando se usen valores de Dt más pequeños.

Tienes razón, un >= resuelve el problema.
Por cierto, el RTC tiene corrimientos mas importantes. Tengo un DS3231 que se supone es preciso y erra en minutos x dia. Ni hablar de un DS1302/07
Tampoco millis() es de fiar, si nos vamos a poner estrictos, ya que depende de la estabilidad del cristal (si lo tiene).
De todas maneras el mseg es real, asi que usar >=. Se me pasó.

O mejor

static uint32_t actualTime = millis();
if ( actualTime - timeSave >= Dt )     {
   timeSave = actualTime; 

Saludos

1 Like

no, no utilicé.

si, de hecho lo cambié a millis como me dijo @Surbyte. El día de antier lo dejé corriendo por 27 hrs y todo genial. Ese es el propósito, que pueda medir esos parámetros durante el tiempo que dure mi prueba experimental, sin tener perdidas de datos.
Gracias

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