Go Down

Topic: Inconveniente con datalogger usando RTC DS1307, Memoria SD (Solucionado) (Read 1 time) previous topic - next topic

Tato84

Tengo un inconveniente con el datalogger, este debe registrar datos de un sensor (se incrementa por interrupcion INT0) cada cinco minutos en la SD con el uso de un RTC DS1307, (Fecha  Hora   Sensor), como se muestra a continuacion:


04/05/2018  00:00:00   0          
04/05/2018  00:05:00   100        
04/05/2018  00:10:00   20          
               .
               .
               .  

(hasta linea 288 para completar las 24 horas)
                                             

El inconveniente es que en algunos casos se pierde de una a cuatro lineas (cada linea son 24-26 bytes como se puede observar)



Code: [Select]


#include <SPI.h>
#include <Wire.h>
#include <SD.h>
#include "RTClib.h"
RTC_DS1307 rtc;
File myFile;

volatile unsigned int sensor;
unsigned long T0 = 0;
char filename[13];
char registro[30];
byte min_registro[12]={0,5,10,15,20,25,30,35,40,45,50,55};


void interrupcion_sensor()
{
  if (millis() > T0 + 250)
  { sensor++;
    T0 = millis();
  }
}

void setup()
{
  Serial.begin(9600);
  delay(3000);
  pinMode(10, OUTPUT);//MEMORIA SD
  pinMode(3,OUTPUT); //LED
  attachInterrupt(0, interrupcion_sensor, FALLING);
  Wire.begin();
  rtc.begin();

  if (!SD.begin(10)) {
   //Serial.println(F("Se ha producido un fallo al iniciar la comunicacion con la memoria SD"));
     return;
  }

  //Serial.println(F("Se ha iniciado la comunicacion correctamente con la memoria SD"));
 
 
  if (!rtc.isrunning())
  {
      myFile = SD.open("cfg.txt");
      if (myFile) {
      //Serial.println(F("Abriendo archivo cfg.txt"));
      if (myFile.available()) {
        byte day = myFile.parseInt();
        byte month = myFile.parseInt();
        int year = myFile.parseInt();
        byte hour = myFile.parseInt();
        byte minute = myFile.parseInt();
        byte second = myFile.parseInt();
        rtc.adjust(DateTime(year, month, day, hour, minute, second));
        }
        myFile.close();
        //Serial.println(F("Datos cargados correctamente al reloj en tiempo real"));
      
      }
      else
      {
    //Serial.println(F("Error abriendo archivo cfg.txt"));
    }
  }

}//FIN SETUP


void loop()
{

DateTime now = rtc.now(); // Obtiene la fecha y hora del RTC

snprintf(filename, sizeof(filename), "%02d%02d%04d.txt", now.day(), now.month(), now.year());  

  for (byte i = 0; i < 12; i++)
  {
    if ((now.minute() == min_registro[i]) && (now.second() == 0)) // Compara la hora del RTC con el ciclo de medicion
    {
      digitalWrite(3,HIGH); //inicia proceso de registro
      //Serial.println(F("Iniciando registro de datos en la memoria SD"));
      SD.begin(10); // se inicializa SD por si se retiro
      //Serial.println(F("Inicializar memoria SD"));
      delay(20);
      myFile = SD.open(filename, FILE_WRITE);
      if (myFile)
      {
        detachInterrupt(0);
        snprintf(registro, sizeof(registro), "%02d/%02d/%04d  %02d:%02d:%02d   %d", now.day(), now.month(), now.year(), now.hour(), now.minute(), now.second(), sensor);
        myFile.println(registro);
        myFile.close(); // cerrar archivo .txt
        sensor = 0;
       }


}}

delay(1000);
digitalWrite(3,LOW);//finaliza proceso de registro
} // fin de bucle








surbyte

No estas justo con el tamaÑo del buffer registro?

Puedes adjuntar un archivo donde se vea lo que has perdido?

Tato84

La primera columna es Fecha, segunda colmuna Hora y tercera columna es sensor (es un contador de pulso por INT0). Cada linea son 26 byte como maximo y se pierde datos de la siguiente forma:

El registra desde 00:00:00 hasta 23:55:00 (cada 5 minutos por 24 horas que da un total de 288 lineas)

En este ejemplo falta la linea de las 00:20:00 y ya desde las 00:25:00 hasta las 23:55:00 todo perfecto. De 288 lineas solo se registran 287.

04/05/2018  00:00:00   300
04/05/2018  00:05:00   200
04/05/2018  00:10:00   20
04/05/2018  00:15:00   100
04/05/2018  00:25:00   50   


Puede perderse un registro a las 11:15:00, etcetera, no es en un punto exacto.


Tato84

Aca coloco un archivo de ejemplo donde se perdio una linea a las 03:10:00

surbyte

El error esta en tu propia rutina

Code: [Select]
for (byte i = 0; i < 12; i++)  {
    if ((now.minute() == min_registro[i]) && (now.second() == 0)) {


ya que

Code: [Select]
byte min_registro[12]={0,5,10,15,20,25,30,35,40,45,50,55};

obliga a que si o si el segundo sea 0 y si no lo es? no lo cumple
te cambio la rutina para que se aproxime sin tener esa restricción.

Code: [Select]
#include <SPI.h>
#include <Wire.h>
#include <SD.h>
#include "RTClib.h"
RTC_DS1307 rtc;
File myFile;
unsigned long start = 0;

volatile unsigned int sensor;
unsigned long T0 = 0;
char filename[13];
char registro[30];
byte min_registro[12]={0,5,10,15,20,25,30,35,40,45,50,55};
bool fsync = false;
bool fregistro = false;     // se usa para mantener encendido el led registro

void interrupcion_sensor() {
  if (millis() > T0 + 250)  {
      sensor++;
      T0 = millis();
  }
}

void setup()
{
  Serial.begin(9600);
  delay(3000);
  pinMode(10, OUTPUT);//MEMORIA SD
  pinMode(3,OUTPUT); //LED
  attachInterrupt(0, interrupcion_sensor, FALLING);
  Wire.begin();
  rtc.begin();

  if (!SD.begin(10)) {
   //Serial.println(F("Se ha producido un fallo al iniciar la comunicacion con la memoria SD"));
     return;
  }

  //Serial.println(F("Se ha iniciado la comunicacion correctamente con la memoria SD"));
 
 
  if (!rtc.isrunning())  {
      myFile = SD.open("cfg.txt");
      if (myFile) {
      //Serial.println(F("Abriendo archivo cfg.txt"));
      if (myFile.available()) {
          byte day = myFile.parseInt();
          byte month = myFile.parseInt();
          int year = myFile.parseInt();
          byte hour = myFile.parseInt();
          byte minute = myFile.parseInt();
          byte second = myFile.parseInt();
          rtc.adjust(DateTime(year, month, day, hour, minute, second));
          }
          myFile.close();
          //Serial.println(F("Datos cargados correctamente al reloj en tiempo real"));
      }
      else   {
          //Serial.println(F("Error abriendo archivo cfg.txt"));
    }
  }
  fsync = true; // habilito el flag para sincronizar
  fregistro = false;
}//FIN SETUP

void loop(){

  DateTime now = rtc.now();                   // Obtiene la fecha y hora del RTC
  if (now.minute() == min_registro[i] && now.second() == 0 && fsync) { // Compara la hora del RTC con el ciclo de medicion
      start = millis();
      fsync = false;                          // esto se usa una sola vez luego de energizado
  }

  snprintf(filename, sizeof(filename), "%02d%02d%04d.txt", now.day(), now.month(), now.year());   

  if (!false && millis()-start > TLOGGEO) {
    if ((now.minute() == min_registro[i]) && (now.second() == 0)) { // Compara la hora del RTC con el ciclo de medicion
        digitalWrite(3,HIGH); //inicia proceso de registro
        //Serial.println(F("Iniciando registro de datos en la memoria SD"));
        if (!SD.begin(10)) {
            Serial.println(F("Se ha producido un fallo al iniciar la comunicacion con la memoria SD"));
            // si falla la incialización como te enteras?   
            // agregar hora de la falla
        }

        //Serial.println(F("Inicializar memoria SD"));
        delay(20);
        myFile = SD.open(filename, FILE_WRITE);
        if (myFile)   {
            detachInterrupt(0);
            snprintf(registro, sizeof(registro), "%02d/%02d/%04d  %02d:%02d:%02d   %d", now.day(), now.month(), now.year(), now.hour(), now.minute(), now.second(), sensor);
            myFile.println(registro);
            myFile.close(); // cerrar archivo .txt
            sensor = 0;
        }
    }
    start = millis();
    fregistro = true;
  }
  if (fregistro && millis()-tregistro > 1000UL) {
      digitalWrite(3,LOW);//finaliza proceso de registro 
      fregistro = false;
  }
} // fin de bucle

noter

Me permito compartir la solución que utilicé yo para caso similar. Dado que los minutos son múltiplos de cinco, prescindo del array min_registro. En su lugar declaro una variable bool salvado=false.
Luego, en el loop lo controlaría así:

Code: [Select]

  if (salvado) {
    if( (now.minute%5)>0 ) {
      salvado=false; // Si el resto de minuto/5 no es cero, "armamos" el siguiente salvado
    }
  }
  else {
    if ( (now.minute%5)==0 ) {
      /// incluimos el código para guardar en SD
      salvado=true; // y desarmamos el salvado para evitar guardar más veces
    }
  }


Saludos.

Tato84

Para determinar si la sd esta colocada o si el rtc se configuro bien hice esto :) pero esto solo esta en el setup en el loop no coloque eso, solo esta SD.begin(10); // en caso de que se haya sacado la memoria SD

Code: [Select]

 if (!SD.begin(10)) {
   Serial.println(F("Se ha producido un fallo al iniciar la comunicacion con la memoria SD"));
   digitalWrite(3,HIGH); //Led se mantiene encendido indicando un error
   while(1);
  }

  Serial.println(F("Se ha iniciado la comunicacion correctamente con la memoria SD"));
 
 
  if (!rtc.isrunning())
  {
      myFile = SD.open("cfg.txt");
      if (myFile) {
      Serial.println(F("Abriendo archivo cfg.txt"));
      if (myFile.available()) {
        byte day = myFile.parseInt();
        byte month = myFile.parseInt();
        int year = myFile.parseInt();
        byte hour = myFile.parseInt();
        byte minute = myFile.parseInt();
        byte second = myFile.parseInt();
        rtc.adjust(DateTime(year, month, day, hour, minute, second));
        }
        myFile.close();
        Serial.println(F("Datos cargados correctamente al reloj en tiempo real"));
        digitalWrite(3,HIGH); //Led titila indicando que ha sido exitoso el proceso.
        delay(500);
        digitalWrite(3,LOW);
        delay(500);
        digitalWrite(3,HIGH);
        delay(500);
        digitalWrite(3,LOW);
        delay(500);
        digitalWrite(3,HIGH);
        delay(500);
        digitalWrite(3,LOW);
      }
      else
      {
    Serial.println(F("Error abriendo archivo cfg.txt"));
    digitalWrite(3,HIGH); //Led se mantiene encendido indicando un error
    while(1);
    }
  }

Lucario448

El error esta en tu propia rutina

Code: [Select]
for (byte i = 0; i < 12; i++)  {
    if ((now.minute() == min_registro[i]) && (now.second() == 0)) {

Yo lo hubiera dicho porque independientemente del if, el ciclo iba a iterar siempre. ¿Quizá bloquearse con un while?

Code: [Select]
while ((now.minute() != min_registro[i]) || now.second()) { // Se bloquea hasta que el tiempo se alinie
  delay(500); // No ser tan agresivos con la solicitud de datos
  now = rtc.now();
}



Tato84

Noter he probado el codigo con tu metodo y le agregue un detalle de maximo 2 segundos en caso de que se apague y prenda el dispositivo para que no vuelva a regitrar en el mismo intervalo de 5 minutos, luego deje el datalogger activo sin registrar ninguna pulsacion durante un dia, ya aparecen las 288 lineas pero se registran 1 o 2 pulsaciones por INT0 sin que este haya ocurrido, en tu caso te sucedio algo similar?

Aca coloco el codigo y anexo el .txt

Code: [Select]

#include <SPI.h>
#include <Wire.h>
#include <SD.h>
#include "RTClib.h"
RTC_DS1307 rtc;
File myFile;

volatile unsigned int sensor;
unsigned long T0 = 0;
char filename[13];
char registro[30];
bool flag=false;

void interrupcion_sensor()
{
  if (millis() > T0 + 250)
  { sensor++;
    T0 = millis();
  }
}


void setup()
{
  
  pinMode(10, OUTPUT);//MEMORIA SD
  pinMode(3,OUTPUT); //LED
  digitalWrite(3,HIGH); ///////////////////////////
  delay(500);           // DISPOSITIVO ENCENDIDO //
  digitalWrite(3,LOW);  //////////////////////////
  
  Serial.begin(9600);
  delay(3000);
  attachInterrupt(0, interrupcion_sensor, FALLING);
  Wire.begin();
  rtc.begin();

  
  if (!SD.begin(10)) {
   Serial.println(F("Se ha producido un fallo al iniciar la comunicacion con la memoria SD"));
   digitalWrite(3,HIGH); //Led se mantiene encendido indicando un error
   while(1);
  }

  Serial.println(F("Se ha iniciado la comunicacion correctamente con la memoria SD"));
  
  
  if (!rtc.isrunning())
  {
      myFile = SD.open("cfg.txt");
      if (myFile) {
      Serial.println(F("Abriendo archivo cfg.txt"));
      if (myFile.available()) {
        byte day = myFile.parseInt();
        byte month = myFile.parseInt();
        int year = myFile.parseInt();
        byte hour = myFile.parseInt();
        byte minute = myFile.parseInt();
        byte second = myFile.parseInt();
        rtc.adjust(DateTime(year, month, day, hour, minute, second));
        }
        myFile.close();
        Serial.println(F("Datos cargados correctamente al reloj en tiempo real"));
        digitalWrite(3,HIGH); //Led titila indicando que ha sido exitoso el proceso.
        delay(500);
        digitalWrite(3,LOW);
        delay(500);
        digitalWrite(3,HIGH);
        delay(500);
        digitalWrite(3,LOW);
        delay(500);
        digitalWrite(3,HIGH);
        delay(500);
        digitalWrite(3,LOW);
      }
      else
      {
    Serial.println(F("Error abriendo archivo cfg.txt"));
    digitalWrite(3,HIGH); //Led se mantiene encendido indicando un error
    while(1);
    }
  }
}//FIN SETUP


void loop()
{

DateTime now = rtc.now(); // Obtiene la fecha y hora del RTC

snprintf(filename, sizeof(filename), "%02d%02d%04d.txt", now.day(), now.month(), now.year());    

if (flag) {
    if( (now.minute()%5)>0 ) {
      flag=false; // Si el resto de minuto/5 no es cero, "armamos" siguente flag
    }
  }
  else {
    if ( ((now.minute()%5)==0) && (now.second()<3) ) {
      digitalWrite(3,HIGH); //inicia proceso de registro
      //Serial.println(F("Iniciando registro de datos en la memoria SD"));
      SD.begin(10); // se inicializa SD por si se retiro
      //Serial.println(F("Inicializar memoria SD"));
      delay(20);
      myFile = SD.open(filename, FILE_WRITE);
      if (myFile)
      {
        detachInterrupt(0);
        snprintf(registro, sizeof(registro), "%02d/%02d/%04d  %02d:%02d:%02d   %d", now.day(), now.month(), now.year(), now.hour(), now.minute(), now.second(), sensor);
        myFile.println(registro);
        myFile.close(); // cerrar archivo .txt
        sensor = 0;
       }
    flag=true; // y desarmamos flag para evitar guardar más veces
    attachInterrupt(0, interrupcion_sensor, FALLING);  
    }
  }
  delay(500);
  digitalWrite(3,LOW);//finaliza proceso de registro
} // fin de bucle






surbyte

En el post#8 adjuntas un archivo y en el se ven cosas como esta

Quote
07/05/2018  21:35:00   1
07/05/2018  21:40:00   2
Esos son los errores?

surbyte

Surbyte analizaba tu modificacion al codigo pero en la parte de min_registro siempre va a comparar con 0 porque nada recorre el array para compararlo con now.minute() y se necesita un for para que recorra el array o implementar algo diferente a un array como hizo noter, y Tloggeo en este caso 5 minutos de cierta forma estaria fuera de sincronia con los minutos del rtc si se busca que sincronice con 0,5,10,15...55 desde mi punto de vista.
SI se me olvidó algo que indicara a i que valor tomar porque solo se usa una vez para ponerlo en sincronía. No entendiste o no me expliqué bien cual fue mi idea.

Mi idea era que nos sincronicemos con el reloj y de ahi seguimos con millis()
Asi que leyendo donde esta el minuto asignar el i que le corresponde.
Deja, la opción de @noter me parece mucho mejor.

Tato84

En el post#8 adjuntas un archivo y en el se ven cosas como esta

Esos son los errores?
Exactamente esos son los errores y no comprendo porque el sensor se incrementa solo.

surbyte


Tato84

El sensor es un pulsador que va por INT0 y se incrementa por flanco de bajada, en si un contador de pulsos por interrupcion externa usando INT0.

surbyte

Bien, da mas datos, como esta conectado al pin2, tiene alguna resistencia pull-down?

Go Up