La memoria EEPROM (del inglés Electrically Erasable Programmable Read-Only Memory = ROM programable y borrable eléctricamente) es una memoria no volátil. Esto significa que los datos que almacena no se pierden al desaparecer la alimentación de un dispositivo.
La EEPROM fue pensada para mantener aquellos datos que deseamos resguardar luego de apagar y reiniciar un microcontrolador, y disponer de ellos al retomar la operación.
El ATmega328P —el microcontrolador del Arduino UNO, el Nano y otros de la línea Arduino— tiene una capacidad de 1.024 bytes (1 Kb) de memoria EEPROM. La hoja de datos nos indica que la EEPROM del ATmega328P acepta hasta 100.000 ciclos de lectura/escritura. Parece mucho, pero el solo hecho de tener una cantidad de ciclos de escritura acotada ya nos indica que su función no es en nada similar a una RAM. Es para guardar datos, y no en forma momentánea y veloz, sino de manera durable. No ponga nunca operaciones con la EEPROM dentro de la función loop(), ya que, dada la velocidad de trabajo del microcontrolador, llegará rápidamente al límite de 100.000.
Tengamos también en cuenta otro dato importante: una operación de escritura en la EEPROM requiere 3,3 ms para completarse frente a la velocidad miles de veces superior de la RAM, capaz de operar a 20 MHz.
Para acceder a la memoria EEPROM debemos usar la librería EEPROM disponible de manera estándar desde el IDE de Arduino. La biblioteca —o librería— se llama EEPROM.h, y se debe incluir al inicio del programa.
Funciones en la biblioteca EEPROM:
FUNCIÓN EEPROM.read()
Lee un byte de la posición de memoria que indica su parámetro. De fábrica, todas las posiciones de memoria tienen escrito el valor 255 (0xFF).
Sintaxis:
EEPROM.read(direccion)
Parámetros:
direccion: la posición de memoria (de 0 a 1023 = 1024).
Ejemplo con EEPROM.read(), leer toda la EEPROM y mostrarla en Monitor Serie
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
#include <EEPROM.h> byte dato; void setup(){ Serial.begin(9600); // inicializar puerto serie for (int direccion=0;direccion<1024;direccion++) { for(int columna=0;columna<10;columna++) { // escribe hileras de 10 valores por línea // lee la posición EEPROM indicada por 'direccion' dato = EEPROM.read(direccion); Serial.print(direccion); // muestra la direccion del valor Serial.print(" ="); // separador Serial.print("\t"); // tabulacion Serial.print(dato); // muestra el valor en direccion Serial.print("\t"); // tabulacion direccion++; // incrementa direccion if(direccion==1024) break; // solo muestra hasta la direccion 1023 } Serial.println(); // salto a la sig línea direccion--; // decrementa direccion para la siguiente linea } } void loop(){ /* no hay lazo - solo se ejecuta en setup() */ } |
FUNCIÓN EEPROM.write()
Esta función escribe un byte en la posición indicada de la EEPROM. Tiene dos parámetros: el primero es la dirección de memoria (de 0 a 1023) donde se escribirá el byte; el segundo es el valor que se va a escribir en la EEPROM, que debe ser un valor entero entre 0 y 255. La función no retorna ningún valor.
Sintaxis:
EEPROM.write(direccion,valor)
Parámetros:
direccion: dirección en la memoria (de 0 a 1023)
valor: el valor a escribir en la memoria
Ejemplo: Escribir valores en un sector de la memoria
1 2 3 4 5 6 7 |
#include <EEPROM.h> // incluye la librería para el manejo de la memoria EEPROM void setup(){ for (int i = 0; i < 255; i++) // se ejecuta 255 veces. El lazo EEPROM.write(i, i); // escribe en la dirección de memoria i el valor de i } void loop(){} |
FUNCIÓN EEPROM.update()
Escribe un byte en la EEPROM. El valor es escrito solo si es diferente al valor que esta previamente almacenado en esa posición de memoria.
Sintaxis:
EEPROM.update(direccion,valor)
Parámetros:
direccion: la dirección de la memoria (0 a 1023)
valor: el valor a escribir en la memoria
FUNCIÓN EEPROM.put()
Esta función escribe cualquier tipo de dato en la EEPROM. El valor es escrito solo si es diferente al valor que esta previamente almacenado en esa posición de memoria, por lo que es mucho más versátil.
Sintaxis:
EEPROM.put(direccion,valor)
Parámetros:
direccion: dirección en la memoria (0 a 1023)
valor: valor a escribir en la memoria
Ejemplo: Guardar una variable tipo float en la memoria EEPROM
1 2 3 4 5 6 7 8 9 10 |
#include <EEPROM.h> // incluye la librería para el manejo de la memoria EEPROM void setup() { Serial.begin(9600); // inicializa el puerto serie float puntoFlotante = 7044.3; // declara una variable float int direccionInicio = 0; // declara una variable con la dirección inicial a escribir EEPROM.put(direccionInicio, puntoFlotante); // escribe en la dirección indicada Serial.println("Escribe una variable tipo float"); } void loop(){ /* no hay lazo - solo se ejecuta en setup() */ } |
FUNCIÓN EEPROM.get()
Permite leer cualquier tipo de dato en la EEPROM.
Sintaxis:
EEPROM.get(direccion,variable)
Parámetros:
direccion: dirección en la memoria (0 a 1023)
variable: el nombre de la variable donde guardaremos el valor leído de la memoria
Ejemplo: Leer un valor float
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include <EEPROM.h> // incluye la librería para el manejo de la memoria EEPROM void setup() { Serial.begin(9600); // inicializa el puerto serie float f = 0; // declara una variable float inicializada en 0 int direccion = 0; // declara la dirección de inicio Serial.print( "Leer valor float de la EEPROM: " ); // lee un valor float de la posición de memoria indicada EEPROM.get( direccion, f ); Serial.println( f, 3 ); // imprime el valor con 3 decimales } void loop(){ /* no hay lazo - solo se ejecuta en setup() */ } |
OPERADOR EEPROM[]
Este operador permite usar el identificador EEPROM[] como una matriz en la cual indicamos la dirección.
Sintaxis:
EEPROM[direccion]
Parámetros:
direccion: dirección en la memoria (0 a 1023)
Ejemplo: Uso del operador EEPROM[]
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include <EEPROM.h> void setup(){ Serial.begin(9600); // inicializa el puerto serie unsigned char val; val = EEPROM[0]; //lee un valor de la dirección 0 de la EEPROM EEPROM[1] = val; //escribe un valor en la dirección 1 de la EEPROM if(val == EEPROM[1]){ Serial.println( "Quedaron iguales" ); // imprime mensaje } } void loop(){ /* no hay lazo - solo se ejecuta en setup() */ } |