Tutorial: Usando a EEPROM do Arduino para armazenar dados de forma permanente

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á disponivel na IDE do arduino para a utilização deste comando, primeiro devemos montar um potenciometro 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.

 

Referências:

 

http://arduino.cc/en/Reference/EEPROM

http://arduino.cc/en/Reference/EEPROMRead

http://arduino.cc/en/Reference/EEPROMWrite

http://arduino.cc/en/Reference/LowByte

http://arduino.cc/en/Reference/HighByte

http://arduino.cc/en/Reference/WordCast

Margolis, Michael. Arduino Cookbook. Editora O’REILLY, 2011. Capítulo 18.

 

Exibições: 75592

Comentar

Você precisa ser um membro de Laboratorio de Garagem (arduino, eletrônica, robotica, hacking) para adicionar comentários!

Entrar em Laboratorio de Garagem (arduino, eletrônica, robotica, hacking)

Comentário de Wiechert em 14 novembro 2012 às 0:15

É isso ai Jo Ca, lembrando apenas 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.

Comentário de Jo Ca em 13 novembro 2012 às 21:46

Para limpar a memoria da eeprom basta utilizar o seguinte codigo:

#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()
{
}

Comentário de Sidney Alves Bastos em 9 julho 2012 às 12:06

Fiquei pensando em um uso para esta aplicação e pensei no seguinte.

Existe a possibilidade de usar um menu para dar entrada em dados, como hora de despertar. Quando eu escolher este valor ele seria armazenado na eeprom. Dai o programa leria este dado. Alguem pode sugerir como seria feito isso?

Comentário de Wiechert em 7 julho 2012 às 22:07

Erick,

Os dados gravados na EEPROM não são apagados quando é feito outro upload com a IDE do Arduino.

Como foi escrito no tutorial acima, o ATmega328 tem 1kbyte de memória EEPROM, a memória que voce precisaria para o período de um dia vai depender de vários fatores como a quantidade de variáveis a serem armazenadas, número de bytes ocupados por cada amostra e o intervalo de tempo entre cada medição.

Abraço

Comentário de erick de souza gomes em 7 julho 2012 às 18:04

 cara, os dados que foram gravados na e2prom são apagados depois que eu gravi um outro sketch qualquer ou tenho que apagalos de alguma forma diferente?

outra pergunta, ao invés de armazenar essas leituras na e2prom do atmega 328 eu posso gerar um arquivo com uma tabela para registrar leituras de um dia inteiro e este ser armazenado num sd card? ou a memoria e2pro do arduino seria suficiente para gravar este tipo de informação e de um dia inteiro?

Comentário de Sidney Alves Bastos em 5 junho 2012 às 19:02

Marcos, vc é show mesmo. Cara que fantástico. Eu tava já maquinando como poderia armazenar a informação de um horário para ligar uma bomba de irrigação. Estava maquinando milhares de coisas. Inclusive pensando em usar um leitor de SD que tenho guardado.

Mas com essa saida que vc apresentou resolvo meu problema.

Agora ta ficando lindo o projeto. Ja estou quase pronto com um sistema de irrigação e alimentação dos peixes que terá horário programado. As horas leio no RTC agora o horário que vai dispertar eu estava com dificuldades pois toda vez que desligava o arduino a coisa zerava.

Realmente a gente tem que ficar próximo das grandes mentes do mundo pois o aprendizado é fantástico.

No feriado vou trabalhar no projeto. Tenho que filmar o funcionamento pois o Adriano, nosso colega aqui do lab, está tendo um treco de curiosidade.

 

© 2024   Criado por Marcelo Rodrigues.   Ativado por

Badges  |  Relatar um incidente  |  Termos de serviço