Neste tutorial vamos mostrar como usar a memória EEPROM interna do Arduino. A EEPROM está presente em todas as versões do Arduino, mas muitas vezes a falta de conhecimento de sua existência é contornada com a instalação de memórias EEPROM externas ou mesmo de um cartão de memória SD de vários gibabytes para armazenar algumas poucas variáveis ou dados.
Uma EEPROM (de Electrically-Erasable Programmable Read-Only Memory) é um tipo de memória que pode armazenar valores que serão retidos mesmo quando a energia é desligada e pode ser programada e apagada várias vezes, eletricamente. Pode ser lida um número ilimitado de vezes, mas só pode ser apagada e programada um número limitado de vezes, que varia normalmente entre 100.000 e 1 milhão.
A quantidade de memória EEPROM presente em um Arduino varia conforme o microcontrolador instalado na placa: 1024 bytes para o ATmega328, 512 bytes no ATmega168 e ATmega8, e 4 KB (4096 bytes) sobre o ATmega1280 e ATmega2560.
Vamos usar a biblioteca EEPROM para ler e escrever valores na memória EEPROM, esta biblioteca já vem instalada na IDE e existem três exemplos de uso na aba File/Examples/EEPROM.
Para usar esta função basta incluir a biblioteca no início do sketch desta forma:
#include <EEPROM.h>
Uma vez que a biblioteca é incluída no programa, um objeto EEPROM está disponível para o acesso a memória. A biblioteca fornece comandos para ler e escrever dados na memória. A biblioteca EEPROM requer que você especifique o endereço de memória que você deseja ler ou escrever. Isto significa que você precisa se manter a par de onde cada valor é escrito de forma que quando você for ler o valor, acesse a partir do endereço correto.
Para escrever um valor na memória, use:
EEPROM.write(address, value);
Onde:
address – posição da memória que será escrito, é um inteiro entre 0 e 1023 (UNO);
value - valor a ser armazenado inteiro entre 0 e 255 (um único byte).
Agora vamos entender o exemplo que está disponível na IDE do arduino para a utilização deste comando, primeiro devemos montar um potenciômetro na entrada 0 do arduino conforme mostrado na figura abaixo, em seguida devemos fazer o upload do código do sketch mostrado mais abaixo para o arduino.
Este exemplo simplesmente salva periodicamente na EEPROM os valores lidos na entrada analógica para que possam ser acessados posteriormente.
Código exemplo para o comando EEPROM.Write:
/*
* Exemplo EEPROM Write
* Armazena valores lidos na entrada analógica na EEPROM.
* Estes valores permanecerão guardados mesmo que a placa
* seja desligada e podem ser recuperados posteriormente pelo próximo sketch
*/
#include <EEPROM.h> // incluir a biblioteca
int addr = 0; // endereço de escrita na memória
void setup()
{
}
void loop()
{
// é preciso dividir val por 4 porque o range da entrada analógica
// vai de 0 a 1023 e cada byte da EEPROM só pode guardar
// valores compreendidos entre 0 e 255.
int val = analogRead(0) / 4;
// escreve o valor de val na EEPROM no endereço selecionado em addr.
// este valor permanecerá guardado mesmo
// que placa seja desligada da fonte de alimentação
EEPROM.write(addr, val);
// avança para o próximo endereço indo até o byte 512 da
// EEPROM, quando então retorna para o byte 0.
addr = addr + 1;
if (addr == 512)
addr = 0;
delay(100);
}
Este sketch começa com a inclusão da biblioteca EEPROM e da declaração da variável addr que define o endereço da EPROM a ser gravado. Em seguida é iniciado o loop principal com a realização da leitura do valor presente na entrada analógica 0 divido por 4 que é salvo em val. O valor de val é escrito no endereço da EEPROM indicado por addr. Em seguida o endereço é incrementado em uma unidade e se for igual a 512 é zerado. O programa aguarda por 100ms para então repetir indefinidamente o loop principal.
Para ler uma determinada posição de memória, use:
value = EEPROM.read(address);
Onde:
address – posição da memória que será lido, é um inteiro entre 0 e 1023 (UNO);
value - valor do endereço da EEPROM é um inteiro entre 0 e 255 (um único byte).
Abaixo vemos o exemplo da IDE do arduino para a utilização deste comando, não é necessário alterar o circuito montado para o exemplo anterior visto que este sketch usa apenas o canal serial do arduino através do cabo USB. Faça o upload do sketch abaixo para o arduino e abra o monitor serial, voce verá que os valores salvos na EEPROM pelo sketch anterior serão mostrados na tela do computador.
Código exemplo para o comando EEPROM.Read:
/*
* EEPROM Read
* Le o valor de cada byte da EEPROM e imprime na tela do computador.
* o código deste exemplo é de domíno público
*/
#include <EEPROM.h> // incluir a biblioteca
// inicia lendo apartir do primeiro byte (endereço 0) da EEPROM
int address = 0; // endereço de escrita na memória
byte value; // valor lido da EEPROM
void setup()
{
Serial.begin(9600); // inicializa o canal de comunicação serial
}
void loop()
{
// lê o byte no endereço atual da EEPROM
value = EEPROM.read(address);
// envia o valor lido para o computador pela porta serial
Serial.print(address);
Serial.print("\t");
Serial.print(value, DEC);
Serial.println();
// avança para o próximo endereço da EEPROM
address = address + 1;
// quando atingir o endereço 512 retorna
// para o endereço 0
if (address == 512)
address = 0;
delay(500);
}
Estes exemplos foram feitos para rodar em qualquer versão do arduino, por isso que só foram escritos ou lidos os endereços de 0 a 511 da EEPROM, se voce quiser pode ficar a vontade e tentar alterar o sketch para ler e escrever em todos endereços disponiveis na sua placa.
Agora voce pode estar se perguntando:
“Existe alguma forma de armazenar um valor maior que 255 na EEPROM?”
A resposta é sim e é algo fácil de se fazer, usando os comandos para a conversão de valores de 16 ou de 32 bits em bytes.
loByte = highByte(val);
hiByte = lowByte(val);
Onde:
val - qualquer tipo de variavel
loByte - byte com a parte mais baixa de val
hiByte - byte com a parte mais alta de val
Vamos agora alterar o primeiro programa de forma a salvarmos os valores lidos da entrada analógica sem ter dividir o valor por 4 de forma a não perder a resolução da medida.
/*
* Exemplo EEPROM Write
* Armazena valores lidos na entrada analógica na EEPROM.
* Estes valores permanecerão guardados mesmo que a placa
* seja desligada e podem ser recuperados posteriormente pelo próximo sketch
*/
#include <EEPROM.h> // incluir a biblioteca
int addr = 0; // endereço de escrita na memória
void setup()
{
}
void loop()
{
// lê o valor na entrada analógica e guarda em val
int val = analogRead(0);
// divide val que é um inteiro de 16 bits em dois bytes
byte hiByte = highByte(val);
byte loByte = lowByte(val);
// escreve o byte mais significativo de val na EEPROM no endereço selecionado em addr
EEPROM.write(addr, hiByte);
// escreve o byte menos significativo de val na EEPROM no endereço selecionado em addr+1.
EEPROM.write(addr+1, loByte);
// avança para o próximo endereço pulando de 2 em 2, pois estamos armazenando
// valores com dois bytes cada até alcançar o byte 512 da
// EEPROM, quando então retorna para o byte 0.
addr = addr + 2;
if (addr == 512)
addr = 0;
delay(100);
}
O código anterior divide o valor lido na entrada analógica em dois bytes que são armazenados em dois endereços consecutivos da EEPROM.
Agora devemos alterar o segundo sketch para poder recuperar os valores salvos na EEPROM, para isso usaremos a função word que converte dois bytes em um inteiro de 16bits. A sintaxe deste comando é mostrada abaixo.
value = word(x)
value = word(h, l)
Onde:
value - uma word
x - uma variável de qualquer tipo
h - a parte alta de uma word
l - a parte baixa de uma word
/*
* EEPROM Read
* Le o valor de cada byte da EEPROM e imprime na tela do computador.
* o código deste exemplo é de domíno público
*/
#include <EEPROM.h> // incluir a biblioteca
// inicia lendo apartir do primeiro byte (endereço 0) da EEPROM
int address = 0; // endereço de escrita na memória
byte value; // valor lido da EEPROM
void setup()
{
Serial.begin(9600); // inicializa o canal de comunicação serial
}
void loop()
{
// lê o byte no endereço atual da EEPROM
byte hiByte = EEPROM.read(address);
byte lowByte = EEPROM.read(address +1);
value = word(hiByte, lowByte);
// envia o valor lido para o computador pela porta serial
Serial.print(address);
Serial.print("\t");
Serial.print(value, DEC);
Serial.println();
// avança para o próximo endereço da EEPROM
address = address + 2;
// quando atingir o endereço 512 retorna
// para o endereço 0
if (address == 512)
address = 0;
delay(500);
}
Para a utilização da EEPROM, é aconselhável sempre fazer um mapa das variáveis que estão sendo guardadas e os seus respectivos endereços, para assegurar que nenhum endereço seja usado por mais de uma variavel, e que os valores de bytes múltiplos não sobresecrevam outras informações.
É isso, a EEPROM é um recurso muito útil e fácil de usar no Arduino, porém relativamente pouco utilizado.
Para limpar a memoria da EEPROM basta utilizar o seguinte código:
/*
*
* Limpa a memória da EEPROM.
*
*/
#include <EEPROM.h>
void setup()
{
// Escreve " 0 " em todos os bytes da EEPROM
// (neste caso como e um arduino mega sao 512 bytes)
for (int i = 0; i < 512; i++)
EEPROM.write(i, 0);
// O LED acende quando a memoria estiver limpa
digitalWrite(13, HIGH);
}
void loop()
{
}
Lembrando que a quantidade de memória EEPROM presente em um Arduino varia conforme o microcontrolador instalado na placa: 1024 bytes para o ATmega328, 512 bytes no ATmega168 e ATmega8, e 4 KB (4096 bytes) sobre o ATmega1280 e ATmega2560.
Referências:
Margolis, Michael. Arduino Cookbook. Editora O’REILLY, 2011. Capítulo 18.