quarta-feira, 14 de maio de 2014

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á 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.

Nenhum comentário:

Postar um comentário