COMO USAR LA MEMORIA EPROM DE ARDUINO
Cómo Usar La Memoria EEPROM De Arduino
Por si todavía no lo sabías, te diré que tu Arduino dispone de una memoria EEPROM, es decir, una memoria no volátil (como la de un disco duro) en la que puedes almacenar datos sin preocuparte de perderlos cuando le quites la alimentación a tu Arduino. En este post aprenderás cómo usar la memoria EEPROM de Arduino para reutilizar los datos importantes, recuperar la configuración de tu Arduino o incluso pasar datos de un sketch a otro.
Haz click para ir a lo que más te interese.
Tutorial Para Usar La Memoria EEPROM De Arduino
Generalmente la memoria EEPROM de Arduino suele estar bastante desaprovechada. No sé si será por desconocimiento o miedo a la hora de utilizarla pero es una lástima ya que, con unas cuantas líneas de código y por menos de 1kB de aumento en el tamaño del sketch, puedes tener a tu disposición un recurso realmente interesante.
Utilizar la EEPROM de tu placa es especialmente útil a la hora de guardar la configuración de tu Arduino (como por ejemplo las direcciones MAC e IP que aprendiste a usar en este artículo) pero su uso va mucho más allá. Si quieres calibrar un sensor (por ejemplo una LDR) para fijar sus valores límite, no tienes por qué utilizar un código que siempre calibre el sistema al iniciarse (en el setup), puedes implementar un código que calibre y guarde los datos en la memoria EEPROM y, una vez los hayas guardado, utilizarlos en otro sketch. Gracias a ello ahorrarás espacio en tu microcontrolador y te asegurarás de que esos datos no dependen del día o la zona en la que utilices tu sistema (volviendo al ejemplo de la LDR, puedes conseguir, por ejemplo, que si reinicias tu Arduino por la noche, conserve los dato almacenados durante el día).
Capacidad De La Memoria EEPROM De Tu Arduino
Cada modelo de placa posee una EEPROM distinta. Aunque en casi cualquier tipo de proyecto te va a sobrar espacio con independencia de tu Arduino, aquí tienes una lista con las diferentes capacidades de las memorias EEPROM:
Si quieres más información sobre las características de las distintas placas de Arduino puedes hacerlo a través de este link. Debes tener en cuenta que algunas placas (como la Lilypad) tienen varios modelos y la capacidad de sus memorias puede variar.
Programando la EEPROM
Puedes programar la memoria EEPROM de tu Arduino fácilmente utilizando la librería EEPROM.h (podrás encontrarla por defecto en la IDE).
En la memoria de tu Arduino debes trabajar por direcciones y byte a byte tanto para leer como para escribir. Esto significa que para una memoria de 1kB tendrás desde la dirección 0 hasta la 999 y podrás utilizar valores de 0 a 255. En caso de que quieras guardar valores mayores tendrás que dividirlos por bytes.
Utilizando Un Solo Byte
Leer y escribir un solo byte es realmente sencillo. Aquí te dejo un ejemplo para que veas cómo se hace.
/*Uso De La Memoria EEPROM Con Bytes*/
//Se incluye la librería EEPROM
#include <EEPROM.h>
//Se crea una variable con el valor de la posición de memoria
//en la que se va a almacenar el byte.
int Direccion = 0;
//Se crean una variables para leer los valores de la memoria EEPROM
byte Val1;
byte Val2;
void setup()
{
Serial.begin(9600);
//Se almacena la información a guardar en un byte.
byte Informacion = B11001;// La “B” indica que el formato es binario
//También es posible almacenar la información leída a través de un
//sensor. Hay que tener en cuenta que el valor máximo de una variable
//tipo int es de 1023, mientras que el mayor valor que se puede almacenar
//en un solo byte es 255. Por tanto, se divide el valor resultante entre 4
//y a la hora de utilizar el valor se vuelve a multiplicar por 4. En el
//proceso se pierde precisión.
// need to divide by 4 because analog inputs range from
int Valor = analogRead(0) / 4;
//Se almacenan consecutivamente los valores anteriores.
EEPROM.write(Direccion, Informacion);
EEPROM.write(Direccion + 1, Valor);
}
void loop()
{
Val1 = EEPROM.read(Direccion);
Val2 = EEPROM.read(Direccion + 1);
Serial.print(“En la dirección “);
Serial.print(Direccion);
Serial.print(” se encuentra la información: “);
Serial.print(Val1, DEC);// DEC para datos en decimal.
delay(100);
Serial.print(“En la dirección “);
Serial.print(Direccion + 1);
Serial.print(” se encuentra la información: “);
Serial.print(Val2, DEC);// DEC para datos en decimal.
delay(100);
}
Utilizando Dos Bytes
El software de Arduino tiene instrucciones pensadas para obtener el byte más significativo y el menos significativo, esto es, el que está más a la izquierda y el que está más a la derecha. Si el elemento que quieres gestionar está compuesto solamente por un par de bytes, puedes utilizar estas instrucciones para separar fácilmente tu dato en dos bytes y almacenarlos de forma independiente.
//Se tiene una variable compuesta por 2 bytes, por ejemplo un tipo int.
int A = 800;
//Se crean dos variables de tipo byte para almacenar la información.
byte L;
byte H;
//Se almacenan los bytes más y menos significativos.
H = highByte(A);
L = lowByte(A);
//Se escriben los bytes en direcciones de memoria contiguas.
EEPROM.write(Direccion, H);
EEPROM.write(Direccion + 1, L);
Utilizando Más Bytes
Una cosa que no te he dicho en el caso anterior y que seguramente te habrás imaginado es que hay más de una forma posible de separar los datos. Si ya podías usar varios métodos para el caso anterior, imagínate en este.
La forma en la que yo lo suelo hacer es la siguiente:
- Almaceno el dato entero en una variable auxiliar (para no perder el dato original).
- Compruebo el número de bytes que tiene el dato.
- Guardo el byte más significativo en una variable de tipo byte.
- Almaceno el byte en la EEPROM.
- Desplazo ocho bits (un byte) de la variable auxiliar hacia la izquierda, de forma que el segundo byte de esa variable pase a ser el más significativo.
- Repito la operación tantas veces como grande sea el tamaño de la variable inicial.
Sé que así visto puede parecerte un poco lioso pero lo entenderás cuando veas el código.
//Se utiliza un elemento de tipo long (contiene 4 bytes).
long Dato = 123456789;
//Se almacena el dato en una variable auxiliar.
long AuxDato = Dato;
//Se define un byte para almacenar la información en la EEPROM.
byte B;
//La instrucción sizeof() devuelve el número de bytes de una variable
for (int i = 0; i < sizeof(Dato); i++) {
//Se guarda el byte más significativo
B = highByte(AuxDato);
EEPROM.write(i, B);
//Se desplazan 8 bits hacia la izquierda de modo que los 8 primeros
//bits se pierden y los 8 siguientes pasan a ser los primeros
AuxDato = AuxDato & lt; < 8;
}
Componiendo Bytes
Después de separar una variable en bytes para almacenarla en la memoria EEPROM de Arduino surge el problema de volverla a componer para recuperar la información. Si, por ejemplo, tienes una variable de tipo long separada en cuatro bytes dentro de tu EEPROM, al leer esos datos lo que tienes es cuatro bytes, no un long.
De nuevo existen varias formas de solucionar este problema. Te dejo la mía:
- Creo una variable del tipo que quiero recuperar y le asigno el valor 0 (de forma que sé que todos sus bits son 0).
- Defino otra variable igual a la anterior (la variable auxiliar).
- Leo un byte de la memoria EEPROM y lo almaceno en la variable auxiliar utilizando la instrucción OR, con lo que el byte queda almacenado en los ocho bits menos significativos de la variable auxiliar.
- Desplazo los bits de la variable auxiliar hacia la izquierda de modo que queden en la posición que me interesa.
- Realizo una nueva operación OR entre la variable auxiliar y la final.
- Limpio la variable auxiliar y repito el proceso tantas veces como sea necesario.
Con un vistazo rápido al código seguro que lo entiendes mejor.
//Variable que almacenará el resultado final.
long Dato = 0;
//Variable auxiliar (utilizada al mismo tiempo como byte).
long B;
for (int i = sizeof(Dato); i > 0 ; i–) {
//Se almacena el valor de la EEPROM en los bits menos significativos.
B = EEPROM.read(i - 1);
//Se desplazan los bits tantos bytes como sea necesario, teniendo en
//cuenta que el byte final no debe ser desplazado.
if (i != 1) {
B = B & lt; < (8 * i);
}
//Se almacena en la variable final el resultado de la operación OR de
//ambos datos. Al realizar la operación OR con una variable que solo
//contiene ceros (variable Dato), el resultado es el valor de la otra
//variable. OR implica => 0+0=0, 0+1=1, 1+0=1, 1+1=1.
Dato = Dato | B;
//Se limpia la variable auxiliar para que en las siguientes iteraciones
//no se cambie el resultado de los otros bytes.
B = 0;
}
Información Adicional: Trabajando Con Texto
Si los datos que vas a usar en la memoria EEPROM de tu Arduino son caracteres textuales (char o string) necesitas un paso previo antes de guardar la información. Debes gestionar los datos utilizando el código ASCII.
En este código cada letra corresponde a un byte por lo que, una vez separadas las cadenas de caracteres (string) utilizando la librería String.h y conocido el código de cada carácter (aquí te dejo un link con la tabla del código ASCII), no deberías tener ningún problema a la hora de almacenar texto (si tienes alguna duda, deja un comentario).
Ahora ya sabes cómo usar la memoria EEPROM de Arduino… ¿En qué proyecto la vas a utilizar? ¿Se te ocurre alguna mejora del código? ¡Seguro que sí!
Bueno, como siempre me despido recordándote que compartas el contenido si te gustó y animándote a suscribirte al blog.
Interacciones del lector
COMENTARIOS
Pasos para poner código en los comentarios:
- Pega el código en el software de Arduino (IDE).
- Selecciona el segmento que te interese y pulsa el botón secundario del ratón.
- Pulsa en la opción "Copiar como HTML".
- Pégalo en el comentario dentro de las etiquetas:
<div class="arduino_code"><code>PEGA AQUÍ TU CÓDIGO</code></div>
Luego que reinicie, arranque desde el ultimo minuto guardado … poder leerla en el mismo visor serial de arduino … no encuentro nada tan sencillo, la mayoria son de testear entradas analogicas
… Muchas gracias !!!
Ante todo muchas gracias por compartir y aportar a nivel de enseñanza a los nuevitos !!
Estoy nuevo en Arduino, anteriormente estube con Pics … pero como veo mas sencilla la forma de Arduino me tiré a hacer cosillas.
Estube haciendo algo de Arduino y modulo Bluetooth HC05, algo como un contador de 0 a 60, visualizandolo por un movil a travez de la aplicacion AppInventor, …
Todo bien con la conexion y todo eso, solo que al vizualizarlo en el celular me sale un conteo de numeros pero uno bajo otro osea 1, abajo 2, 3 …. quiza por usar Serial.println … no probe con Serial.print … …
Lo poco que pude corregir es poniendo en AppInventor un texto vacio del label visor cada conteo del clock, entonces me resetea el label cada pulso.
En Arduino puse una variable int que en el loop se suma si es menor a 60, sino se resetea luego un delay 1000
En el AppInventor puse un clock de 1000, si pongo menos parpadea …
No se si estoy haciendo algo mal, pero colocando un texto vacío al label en cada pulso de clock, borra el numero anterior y lo reemplaza bien, pero a veces saltea un numero …
Alguna idea ? .. si hace falta coloco el sketch … muchas gracias !!
fernando arbelaez
Podríamos ir almacenándolos para luego más tarde leerlos uno a uno?
Para poner en situación, utilizo Arduino Mega + Ramps 1.4 para manejar una impresora 3D, y al conectar la LCD, cuando modificas el firmware a través del USB y el IDE de arduino, cargas el código y sube correctamente, pero esos cambios no se guardan en la memoria FLASH donde Arduino guarda el Sketch. Cuando haces funcionar la impresora 3D, los valores modificados en el código no se aprecian por que no se han guardado. Se debe entonces acceder al código desde la LCD, modificarlo y guardarlo. De esta forma si se guardan.
mi otro problema es que no soy capaz de subir ningun sketch a los demas lylipad uso un ftdi pero nada tambien probe con un arduino sacando el integrado y nada no se donde fallo
salu2
Muchas gracias.
( alarmString = “0”+(String)aHora + “:” + “0” + (String)aMinutos + “: “+ “00”;) y no he podido lograr almacenar estos datos en la eeprom.
Tu colaboracion seria de gran ayuda!!
Gracias
Me podrias decir como hago para usar la eepro con una vector ,necesito armar un vector que indique distisntas fallas y la hora en que ocurrieron .quera evitar colocar un sd
desde ya muchas gracias
saludos
Quiero pedirte una sugerencia de como puedo trabajar con números negativos, he intentado guardar el valor entero “-1” en algún lugar de memoria EEPROM, pero al momento de leerlo me regresa el valor 254 por lo que puedo deducir que utiliza complemento a 1 o a 2(no recuerdo muy bien cual es) para guardar el valor, pero al momento de leerlo de la EEPROM está el problemas.
vuelvo por aquí ya que por navidad dejé algo aparcado el tema.
He probado a hacerlo con el doble reset y no lo consigo. El problema es que no dispongo de otro arduino por eso no he podido hacer la prueba que me comentas…
no sé si, antes de probar con otro arduino (tiene que ser el UNO o Nano?) habría alguna otra opción que pudiera probar.
gracias!
He hecho la prueba con un display alfanumérico que tenga un contador (minutos/segundos). Si le quito la alimentación, el contador vuelve a empezar de cero (no guarda el valor). debería seguir contando, ¿no?
con el tema de la tira me pasa lo mismo.
gracias!
Tengo un Arduino Pro Micro alimentado por una fuente externa, unos pulsadores y una tira de led conectada a ella.
Para cargar el programa conecto el microusb y descargo el programa.
Si, toco los pulsadores, la tira de led varía OK.
Si desconecto el cable microsub y toco los pulsadores, la tira de led varía OK (gracias a la alimentación externa).
Pero, si quito la alimentación externa del arduino/tira y vuelvo a conectar (un corte de luz, por ejemplo), tengo que volver a conectar el arduino al pc para volver a descargar el programa. La tira de led “se vuelve loca” y no varía y parece que el programa tampoco se ha guardado.
gracias!
Y…. ¿cómo podría solucionarlo? …Gracias!
He estado buscando y he visto esto:
https://learn.sparkfun.com/tutorials/pro-micro–fio-v3-hookup-guide/troubleshooting-and-faq
Una vez hecho esto, cargar el programa “normal”. con qué programador?
o hay que hacer algo más? gracias
mi pregunta es que no hayo como meter la LDR… si me podrias ayudar
y tambien que pensando que lo que haria es escribir en la eeprom luego leer y depende de el estado luego volveria a escribir para ver el estado de la persiana. entonces la EEPROM. en pocas palabras me terminaria la eeprom?? es otra pregunta :v gracias de ante mano si me podrias ayudar
tengo una duda no se si me puedas ayudar – ojala si.. estoy haciendo un cuenta kilometros la cuestion es que solo me es necesario guardas los kilometros recorridos hasta un instante antes de que se corte la corriente al arduino . ¿como puedo hacer para solo guardar el ultimo dato y sobreescribirlo en el anterior?
Comentarte que tienes una pequeña errata en la explicación.
Una variable de tipo “int” no tiene un rango de 0 a 1024 valores como dices tú, si no que tiene un rango de 0 a 4294967296 valores. Esto se produce porque no es 255 x 4, sino 2 ^ 32 (que sería 255 ^ 4).
Cabe añadir que el último bit se utiliza para indicar el signo, con lo cuál, en rango efectivo de una variable int va desde -4294967298 a 2147483647.
siendo el bit más significativo, el indicador del signo
El valor maximo del anterior adc de 10 bits todos sabemos que es 1023 o 3FFH tambien 11 1111 1111B que corresponden a 1024 intervalos de digitalización aludidos en el comentario.
Saludos y felicidades por el blog Enrique.
Mi pregunta es, puedo leer y escribir en el VOID LOOP a la vez?, y se que esto es importante porque la memoria EEPROM no tiene que ser leida mas que lo necesario, sino la pierdo como sabras. Y si es que puedo, me indicas aproximadamente como seria o donde puedo encontrar info.
Muchas gracias. Sos muy solidario compartiendo esto.
Te agradezco que compartas tus conocimientos sobre esta plataforma para quienes estamos iniciándonos a explorarlo. Yo ando con un proyecto en mente, quiero hacer un despertador. Mi problema es guardar la hora en la que se va activar el buzz. ya que debo guardar tanto la hora, min y seg.
Se me está haciendo algo complicado, si pudieras orientarme un poco te lo agradecerìa.
de antemano gracias por tu tiempo
Por lo demás, de 10…
Saludos.
Y si, llevas razón en cuanto a la frecuente confusión entre kilos en el sistema métrico y “kilos informáticos”. Sobre todo a la hora de comprar un disco duro o un lapiz USB o cualquier cosa de esas, donde haya muchos…
El post original me sirvio para aprender la raiz de los movimientos de bits que no lo entendia, y creo que entender la base de las cosas es lo mas importante de todo, mas alla de que despues lo uses o no.
Ya habia leido que resultaba util la nueva libreria de EEPROM porque tenia la funcion update, get y put, que entre otras cosas sirven para no escribir un dato en un destino que ya contenía el mismo dato, y por lo tanto no acortar la vida de la EEPROM sin sentido, y el get y put para trabajar con objetos completos como menciona muy bien Oscar. Asique por el comentario de Oscar me decidi al upgrade de mi IDE, y leyendo la libreria resulta que la funcion put, ademas utiliza update, asique cierra por todos lados.
Antes de nada, felicitarte Enrique por esta web: los tutoriales son muy claros y se nota que lo haces con mucho mimo. ¡Muchas gracias!
Y lo segundo…hace pocos días que ha salido una nueva versión del IDE (la 1.6.x) de Arduino que incluye en la librería EEPROM unos métodos nuevos que facilitan mucho la lectura y escritura de datos que ocupan más de un byte. La verdad es que vale la pena usarlos porque así no hay que estar jugando a nivel de bits. Aquí está la referencia: http://arduino.cc/en/Reference/EEPROM
Venga, hasta luego