Go Down

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

Tato84

Bien, da mas datos, como esta conectado al pin2, tiene alguna resistencia pull-down?
Es un atmega328, tiene una resistencia pull up de 10k, con el codigo original incrementaba en el momento que se queria y no registraba error, el unico problema era que a veces se perdia una linea de las 288 o como maximo 4 lineas, pero de resto todo perfecto, cuando no se realizaba ninguna pulsacion durante el dia, registraba puro 0 como debe ser.

surbyte

A ver.. me refería solo a la interrupción o sea tu pulsador conectado a pin 2. El resto claro que lo he leído y hasta te di una sugerencia de programa que me llevó algún tiempo.

Bien, porque no usas la técnica de @tauro0221 con algun capacitor mas bien de bajo valor, digamos 0.1uF asi no retrasas el evento.
Lo tienes a 5V y tu ISR detecta por FALLING, vaya!! que para que marque debe caer a 0.8V cómo puede ser posible eso?

Por otra parte dices

Quote
con el codigo original incrementaba en el momento que se queria y no registraba error
o sea que esto apareció con la sugerencia de @noter. Y ya lo has repetido asi que asi es el caso.
Lo que no entiendo es que cuando se cumplen los 5min

Me parece que hay que ser mas estrictos y aprovechar la sugerncia de noter pero no solo con minutos sino tmb con segundos
o sea dos flags o uno solo que se cumpla 1 sola vez.

Code: [Select]
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) ) {   // <== ESTO NO ME CONVENCE

Veo situciones repetidas para 0, 1 y 2 segundos.

Entonces nada lo detiene para repetir posibles 3 veces esta parte del código.

Veamos algo asi

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, flagSec = 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
        flagSec = true;
    }
}
else {
    if ( (now.minute()%5)==0 && now.second()<3 ) {
         if (flagSec)
            logging();
    }
  }
  delay(500);
  digitalWrite(3,LOW);//finaliza proceso de registro
} // fin de bucle

void logging() {
    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
    flagSec = false;
    attachInterrupt(0, interrupcion_sensor, FALLING); 
}


La otra alternativa es usa TimeAlarm, es algo que te iba a sugerir al comienzo pero como noter ofreció esa alternativa y la ví tan bien, creía que se resolvería.

Con TimeAlarm siempe hará el llamado cada 5 min y te olvidas de lo demás.

Tato84

Code: [Select]
if ( ((now.minute()%5)==0) && (now.second()<3) ) {   // <== ESTO NO ME CONVENCEla parte de && (now.second()<3) la agregue yo para evitar que cuando se apagara y encendiera el dispositivo por ejemplo al minuto 0,5,10... se registrara otra linea, pero si pense que quizas eso era lo que daba el fallo del sensor.

surbyte

Prueba esto con TimeAlarms

repito aunque lo digo en el código, hay que sincronizar si es de tu agrado la hora con la generación de la alarma cada 5 min

Code: [Select]
#include <SPI.h>
#include <Wire.h>
#include <SD.h>
#include "RTClib.h"
#include <TimeLib.h>    // https://github.com/PaulStoffregen/Time
#include <TimeAlarms.h> // https://github.com/PaulStoffregen/TimeAlarms

RTC_DS1307 rtc;
File myFile;

volatile unsigned int sensor;
unsigned long T0 = 0;
char filename[13];
char registro[30];
bool flag = false, flagSec = 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);
      }
  }

  // unico incoveniente sincronizar esto con el comienzo que desees.
  // es decir, tu fija el arranque de esta función.
  Alarm.timerRepeat(5*60, Repeats);           // timer for every 5 * 60 segundos

}//FIN SETUP


void loop() {

  Alarm.delay(500);
  // analizar cuando apagas este led
  digitalWrite(3,LOW);//finaliza proceso de registro
} // fin de bucle

void Repeats() {
  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());   
  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"));
  Alarm.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;
  }
  attachInterrupt(0, interrupcion_sensor, FALLING); 
}

noter

No es necesario controlar los segundos, surbyte, ya que la primera vez que se cumple la condición de minutos, desarmo la grabación posterior poniendo el flag guardado en true. No volverá a ser false, y por tanto volver a armarse hasta el minuto siguiente.
No creo que el problema del incremento del contador esté en esa parte de mi código.  Creo que sí se incrementa es porque se está produciendo la interrupción.
Me llama la atención que el pin no esté declarado como input, y caso de estar utilizando pullup interna, como input_pullup.

surbyte

Es una IRQ Serafín, no hace falta declararla como INPUT de ningún tipo.
Se usa como Interrupción.


Tato84

No es necesario controlar los segundos, surbyte, ya que la primera vez que se cumple la condición de minutos, desarmo la grabación posterior poniendo el flag guardado en true. No volverá a ser false, y por tanto volver a armarse hasta el minuto siguiente.
No creo que el problema del incremento del contador esté en esa parte de mi código.  Creo que sí se incrementa es porque se está produciendo la interrupción.
Me llama la atención que el pin no esté declarado como input, y caso de estar utilizando pullup interna, como input_pullup.
El detalle por lo menos de la parte de los segundos es que si se apaga el dispositivo y se enciente cuando aun el minuto es 0,5,10...55, es que se registra de nuevo otra linea, es por eso que requiere un control para segundos.

Con el codigo original que es practicamente lo mismo sin el bool no se registran valores a menos que utilice el pulsador ya he hecho pruebas por meses del datalogger, pero lo que pasaba era que se perdia 1 a 4 lineas de las 288, y en todo lo demas perfecto.

noter

Entiendo que pueda ser así, surbyte y que, al igual que el analogRead/analogWrite tampoco necesite la declaración del pin como entrada o salida, pero ¿se puede utilizar la pullup interna o habría que poner una resistencia externa obligatoriamente? Es que el hecho de que use pullup en lugar de pulldown me hace sospechar que está prescindiendo de resistencia, contando con la pullup interna y no sé si eso será correcto.

noter

En cuanto a lo de los segundos, entiendo por dónde vas, Tato84. Supongo que quieres descartar que si haces un reset justo nada más grabar, que al volver del reset no vuelva a grabar de nuevo, no?
Prueba tal y como tenía el primer código, pero declarando la variable bool salvado como true. Eso hará que  si al iniciar/resetear está en "minuto cero" (aunque hayan pasado más de tres segundos), no grabe hasta el siguiente minuto cero. No sé si eso te interesaría o prefieres lo de los tres segundos.

surbyte

Con la opcion con TimeAlarms no puede haber fallo. Si lo hay es porque el sensor falla.
Te aseguro que ese llamado se ejecuta solo una vez. De hecho al principio me dio un buen dolor de cabeza poque yo creia que quedaba activa y es solo un disparo.

noter

Perdón. Repasando veo ahora que lo de los tres segundos lo habías puesto por si era la causa de esas pulsaciones "fantasmas". Me temo que no es porblema software; que si hay pulsaciones es porque se está disparando la interrupción. Por ello estoy preguntando si tienes puesta alguna resistencia pull al interruptor. Otra cosa sería si estuviéramos hablando de rebotes, en cuyo caso se podría buscar solución hardware (condensador) o software (temporización). No obstante, voy a repasar el código por si acaso se me escapa algo, pero me extrañaría.

surbyte


noter

Bueno. No tiene nada que ver con el presunto problema, pero en la interrupción veo que usas un temporizador (supongo que para evitar rebotes). Yo lo hubiera puesto así:
Code: [Select]

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

Por evitar un potencial problema de desbordamiento del millis.
Otra cosa que haría, aunque tampoco creo que tenga influencia en tu caso, es dejar la activación de la interrupción (attachInterrupt) como último paso del setup.
Y de paso, podrías probar el funcionamiento sin el detach/atach al escribir en SD, por si acaso justamente ese attach es el que provoca que se lance interrupción.

surbyte

Estoy de acuerdo que el sistema solo a mostrado que tienes un potencial problema en otro lado.

Tato84

Perdón. Repasando veo ahora que lo de los tres segundos lo habías puesto por si era la causa de esas pulsaciones "fantasmas". Me temo que no es porblema software; que si hay pulsaciones es porque se está disparando la interrupción.
Aclarando todo lo que he leido: Lo de los 3 segundos lo coloque para evitar que se registre mas de una vez al apagarlo, lo de las pulsaciones fantasmas me esta ocurriendo cuando empece a hacer uso del booleano, con mi codigo original no tenia problemas de este tipo y regitraba cuantas pulsaciones hiciera, llevo muchos meses usandolo y haciendole mejoras dia a dia, pero luego note que se perdia de 1 a 4 lineas cosa que habia pasado por alto dado que son 288 lineas y es dificil notarlo, pero de resto perfecto, ahora aplicare varias mejoras a ver si lo soluciono.

Go Up