(SOLUCIONADO) Problemas al escribir/leer eeprom

Hola comunidad tengo un problema, con un codigo que es un reloj con sincronizacion interna (no puedo usar un rtc porque cuenta las horas, pero los dia llega a 999) para saber el tiempo de funcionamiento de un aparato. El problema es que no logro poder guardar la hora/minutos/dias y leerla en cada inicio en la eeprom y si se reinicia el arduino o ay un corte de energia vuelva a donde quedo, estoy un poco verde con el tema de la libreria eeprom.h.

Con otro ejemplo y haciendo una INT si puedo hacer funcionar la lectura y escritura pero con el codigo del reloj no, si alguien me da una mano me ayudaria mucho...

Desde ya muchas gracias

Aca el codigo:

#include <LiquidCrystal.h>// include the library code

#include <Time.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
  setTime(23,59,00,103,01,00);

  Serial.begin (9600); 
  lcd.begin(20, 4); 
 


}
  
  void loop(){

    time_t t = now();
    lcd.setCursor(0,0);
      lcd.print("Hora");

printDigits(hour());
  printDigits(minute());
lcd.print(" ");
  lcd.print("Dia:");
  lcd.print(day());
      delay(1000);

      
}

void printDigits(int digits){
 
  lcd.print(":");
  if(digits < 10)
    lcd.print('0');
  lcd.print(digits);
  
}

PD: Esta pregunta es media obvia pero ya dije que estoy verde con las eeprom, se debe poner algun otro codigo para que no se llene la memoria interna, o siempre al poner eeprom.write(posicion,variable) se sobreescribe en la posicion 1 en este caso.

Osea al escribirlo asi,no importa la cantidad de escritura que tenga porque siempre la va a sobreescribir en la posicion "1"?

Pregunto por he visto ejemplo que hacen un bucle for para grabar en la posicion 1 y la proxima escritura la haga en la 2 y asi hasta al 512 y luego regresa a la posicion 1 (en caso que queramos por ejmplo ver variales de un sensor).

Buenas Protheo,

Tengo una duda; Quieres guardar en la eeprom el número de horas de uso del aparato, o lo que quieres es guardar la fecha ?

Saludos,
Gerardo

Hola zarmack, modifique la libreria para que cuando se cumpla el ciclo de 24 hs marque en el lcd dia 1 y asi sucesivamente, hasta el dia 999, necesito que me guarde las dos cosas, osea no es la hora real sino el tiempo que tiene encendido el aparato, y que al reiniciarse o cortar la alimentacion vuelva al tiempo que estaba marcando y en el dia que estaba, logro hacerlo con otros ejemplosy un INT, pero al querer hacerlo con hour() o day(), no puedo.

Cada cuánto tiempo regrabarás datos en la EEPROM?
Recuerda que tienes unas 100.000 escrituras de crédito antes de que caduque.

Hola noter,la idea esque lo haga a cada minuto, osea cada cambio ya que no se sabe cuando se reiniciaria el micro, por eso preguntaba si al darle siempre la misma posicion se sobre escribe la ultimapor la nueva escritura o se suman

Yo lo haría así ...
Espero que te sirva !

#include <EEPROM.h>


uint16_t read_minutes(int addr)
{
 return(EEPROM.read(addr) * 256 + EEPROM.read(++addr));
}


void write_minutes(int addr, uint16_t m)
{
 EEPROM.write(addr, m / 256);
 EEPROM.write(++addr, m % 256);
}


uint16_t minutos = 0;
unsigned long start;


void setup()
{
 
 if(read_minutes(0) == 0xffff)
   write_minutes(0, minutos);

 minutos = read_minutes(0);
 start = millis();
}

void loop()
{
 if(millis() - start > 60000)
 {
   minutos += ((millis() - start) / 1000)
   write_minutes(0, minutos);
   start = millis();
 }
}

Ten en cuenta lo que apunta noter; tienes 100.000 escrituras antes de "que casque"; o sea que va a funcionar durante 1.666 días. Podrías pensar en escribir el dato cada 5 minutos en vez de cada minuto, o podrías hacer una rutina para escribir en diferentes posiciones de memoria cada vez.

Saludos,
Gerardo

60 x 24. = 1440 escrituras al día... En unos 70 días de uso continuo habrás fundido la EEPROM. Deberías poner un condensador (capacitor) y detector de corte de corriente para guardar sólo al haber corte de fluido.

Bien zarmack,pero que diferencia hay escribir siempre en la misma posicion o en diferentes, si por lo que me dijeron y estuve viendo son 100000 lecturas-escrituras antes de que muera la eeprom, si podria hacerlo hasta cada 1 hora, solo que tengo mas margen de error.

Pd: no me podrias explicar un poco elcodigo que me hiciste, porque alno saber mucho de eeprom,quisiera aprender.

Muchas gracias

Hola noter me interezo esa idea no se me habia ocurrido, que solo grabe al detectar el corte electrico. Vos decis poner un capacitor para que tarde en descargar un tiempo a que elmicro grabe y una funcion para al detectar, por ejemplo en el pin 3 le doy alimentacion directa de los 5 volts o de la fuente externa ( en el caso que lo pase a una placa) y en el codigo poner un digitalread si el pin 3 es LOW hacer la sentencia de grabado en la eeprom?

Protheo:
Bien zarmack,pero que diferencia hay escribir siempre en la misma posicion o en diferentes, si por lo que me dijeron y estuve viendo son 100000 lecturas-escrituras antes de que muera la eeprom, si podria hacerlo hasta cada 1 hora, solo que tengo mas margen de error.

Hola Protheo,

Lo que está limitado es la escritura; 100.000 veces cada uno de los bytes que tienes en la eeprom. En un principio (es en teoría) una vez alcanzas el límite, no dejan de funcionar todos la eeprom a la vez, si no que sólo el byte que has escrito esas 100.000 veces. El número de lecturas "es infinito".
Por ésto, si el dato lo escribes en 50 posibles posiciones (uno de unos 100 bytes de eeprom), en vez de 1666 horas, te duraría 1666 * 50 = 83300 horas; unos 3470 días; más de 9 años.

Perdona, que en un post anterior he puesto 1666 días y no son días; son horas. Estaba pensando una cosa y he escrito otra.

Saludos,
Gerardo

Protheo:
No me podrias explicar un poco elcodigo que me hiciste, porque alno saber mucho de eeprom,quisiera aprender.

Vamos a ello ...

La funcion read_minutes() lee de la eeprom un valor uint16_t o sea; 16 bits o 2 bytes; lo suficiente para almacenar 65535 minutos o 1092 horas)
Como parámetro le pasas la dirección de la eeprom en la que quieres escribir el primer byte.

uint16_t read_minutes(int addr)
{
 return(EEPROM.read(addr) * 256 + EEPROM.read(++addr));
}

La función write_minutes() es la inversa a read_minutes. En vez de leer, escribes y obviamente le tienes que especificar qué quieres escribir.

void write_minutes(int addr, uint16_t m)
{
 EEPROM.write(addr, m / 256);
 EEPROM.write(++addr, m % 256);
}

En la variable minutos vamos a almacenar los minutos de uso totales de la máquina, mientras que la variable start la usamos de apoyo para mantener la cuenta "del tiempo".

uint16_t minutos = 0;
unsigned long start;

En la función de setup, primero comprobamos si es la primera vez que usamos esa posicion de la eeprom, y si lo es, la ponemos a 0. Cuando no has usado la eeprom, en un atmega328, el valor que se obtiene al leerlo es 255 y por eso 255 * 256 + 255 = 65535 = 0xffff en hexadecimal.
Tras ésta comprobación, inicializamos minutos con el valor de la eeprom y start con el número de milisegundos pasados desde que hemos arrancado el arduino.

void setup()
{
 
 if(read_minutes(0) == 0xffff)
   write_minutes(0, minutos);

 minutos = read_minutes(0);
 start = millis();
}

En la función loop, primero analizamos si han pasado más de 60000 milisegundos (60 segundos) desde que actualizamos la última vez la variable start. En casoi positivo, calculamos el número de segundos que han pasado , se los sumamos a la variable minutos y escribimos en la eeprom el valor.
Si quisieses que se grabase cada 5 minutos, bastaría cambiar 60000 por 300000.
Y por último actualizamos el valor de start para que no volvamos a escribir hasta que pase el tiempo que necesitas ....

void loop()
{
 if(millis() - start > 60000)
 {
   minutos += ((millis() - start) / 1000)
   write_minutes(0, minutos);
   start = millis();
 }
}

Espero que te haya servido la explicación.

Saludos,
Gerardo

Usa un pequeño backup de batería que te asegure el tiempo para detectar corte de energía y salvar la información con seguridad en la eprom y asunto terminado.

Para responder eso hay que medir tu consumo, supongamos 100mA (x fijar un valor) y entonces debes establecer cuanto tiempo necesitas para salvar los datos.
Voy a exagerar por mucho y diré 20mseg

De manera que un una serie de baterias recargables en serie te darían ese bakcup aunque son varias para lograr 7VDC, algo que consigues con 6 baterias.
De modo que armas un puente de diodos mas un optoacoplador
AC mains zero crossing detector
y asi detectas que te quedaste sin energía, y entonces tienes tiempo de sobra para guardar los datos y poner si quieres el Arduino en SLEEP y despertarlo cuando vuelva la energía.

Te lo sugiero con baterías recargables pero hay muchas opciones que entreguen mas de 7V.
Debes incluir algo que las cargue mientras haya energía.
Un cargador simple con un LM317 sirve. Hay muchos ejemplos en internet.

Zarmack muchisimas gracias por la informacion mejor explicado imposible :grin: :grin:

Surbyte es la idea que me dio noter y la verdad que no se me habia ocurrido, vamos a ponernos manos a la obra.

Doy por solucionado el post, cuando tenga todo armado lo subo y asi lo comparto... Muchisimas gracias.

Lo se pero es lo que debes hacer, sumado a lo que te dijeron noter y Zarmack.
La bateria es el tema a considerar. Tal vez una de telefono inalámbrico sirva.. busca la que vaya bien con tu aplicación.
Claro que puedes usar mi sugerencia de 6 recargables. Es importante que tengas mas de 7VDC e ingreses por el conector externo.
Con el circuito extra detectas AC ON/OFF y decides que guardar con tiempo de sobra.
ahora bien... tal vez un buen capacitor sea mas simple que lo que expongo. Creo que lo dijo Noter (si el fue) y te de tiempo para sostener tu decisión, pero aun queda darte cuenta que te quedas sin energía.