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: 12492

Tags: EEPROM, arduino, tutorial

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 Diogo Santos Silva em 26 agosto 2013 às 13:20

Tudo bem!

Acabei de ler o seu post e ele resolve metades dos meus problemas(que estou tendo no momento)!!!

Estou trabalhando em um projeto que consiste em; controlar componentes por comandos( via teclado) no serial monitor, o qual está funcionando perfeitamente, o problema surgiu ao acrescentar um sensor de luminosidade para poder acompanhar "quantitativamente"(por meio de um gráfico) determinado evento relacionado a ação dos componentes.

O problema é a comunicação serial pela "COM" é uma via de mão única E NÃO POSSO ENVIAR E RECEBER DADOS simultaneamente! Certo!

A ideia que tive (e até me sugeriram essa mesma ideia) envio o comando ao Arduino pelo serial monitor o serialEvent() recebe o comando e reenvia para o loop() que após recebido o comando apaga o buffer da porta serial o que possibilitaria o envio de dados do sensor para o Arduino.

A outra metade do problema que me referi inicialmente é: o comando para armazenar os dados recebido do sensor teriam que ser feito em tempos diferentes. Tipo, envio comando (pelo teclado via porta serial) -> Arduino recebe e dispara a ação dos componentes (sendo efetuada a limpeza no buffer da porta serial nesse momento) -> os dados do sensor são armazenados na memória EEPROM e após serrada a determinada atividade(que envolve alguns componentes) e imprimido na porta serial assim poderia usar algum programa como o Processing ou Python para converter esses dados em um gráfico.

Isso é possível?

Há um outra forma de fazer isso sem ter que sacrificar a "simultaneidade" do processo!?

Comentário de Wiechert em 10 julho 2013 às 20:57

Para apagar um dado salvo é preciso escrever outro dado, normalmente 0 ou 255, no endereço que queira apagar.

Na IDE do arduino, procure o exemplo eeprom_clear.

Mas lembre que a eeprom tem uma expectativa de 100000 operações de escrita.  

Comentário de Murilo Lima Nogueira em 10 julho 2013 às 19:48

Como que eu faço para apagar estes dados?

Comentário de Daniel Bernardo em 10 março 2013 às 2:00

Preciso armazenar uma variável IRr na eeprom e depois do arduino reiniciado preciso mandar o armazenado de volta para a IRr.

Mas não sei como faço. Olhem só o exemplo dos valores:

IRn2= 13646
3843765582
IRr= 13646
IRn= 13646


outro exemplo:
IRn2= 13646
1825097194
IRr= -14870
IRn= 13646

ele sai daqui:

  if (irrecv.decode(&results)) {  // IR 
    Serial.println(results.value);  // IR 
    irrecv.resume(); // IR 

    IRr = (results.value * 1);  
    Serial.println(IRr );

Comentário de Jo Ca em 14 novembro 2012 às 5:28

E isso, eu nao me lembrava das memorias de cada uma,

Obrigado ;)

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?

Publicidade

Convide um amigo para o Lab!

 Loja Lab de Garagem

curso gratis de arduino

Base à vácuo

Por: R$ 163,20

Ou em até 18x de

R$ 10,88

Programador USB AVR - Pololu

Por: R$ 95,00

Ou em até 18x de

R$ 6,33

Protoboard - 1890 pinos

Por: R$ 89,00

Ou em até 18x de

R$ 5,93

GPS Receptor

Por: R$ 180,00

Ou em até 18x de

R$ 12,00

© 2014   Criado por Marcelo Rodrigues.

Badges  |  Relatar um incidente  |  Termos de serviço