Como gravar dados na memória EEPROM do Arduino
Um recurso nem sempre utilizado no Arduino é a gravação de dados na memória EEPROM do microcontrolador. Com esse método de armazenamento, você grava os dados em uma parte, digamos, “protegida” da memória, de forma que eles não se perdem quando acontece uma queda de energia, ou mesmo em casos de travamento do Arduino.
EEPROM significa Electrically-Erasable Programmable Read-Only Memory (ou, Memória Somente de Leitura Programável Apagável Eletricamente) e é uma memória que pode ser apagada e reprogramada várias vezes, apesar de possuir um limite no número de ciclos de leitura/escrita.
Gravando na EEPROM no Arduino
A quantidade de memória EEPROM varia conforme o modelo da placa. O Arduino Uno(microcontrolador ATMega328), tem 1 KB de memória EEPROM. Já o Arduino Mega (microcontrolador ATMega2560) tem 4 KB. No Arduino Nano com microcontrolador ATMega168, esse valor cai para 512 bytes.
O comando para escrever na memória EEPROM é o EEPROM.write(endereço, valor), e exige o uso da biblioteca EEPROM , que já faz parte da IDE do Arduino.
O endereço tem o valor inicial em 0, e vai até a capacidade total da memória EEPROM. Assim, se você estiver trabalhando com um Arduino Uno, você tem 1024 posições de memória pra gravar os dados, um byte (8 bits) de cada vez, ou seja, o maior valor que você consegue gravar em uma posição de memória é 255:
A leitura é feita pelo comando EEPROM.read(endereço). Veja neste programa de exemplo:
//Programa: Escrita e leitura EEPROM //Autor: Arduino e Cia //Carrega a biblioteca #include <EEPROM.h> //Numero a ser armazenado int numero = 123; int endereco = 0; void setup() { Serial.begin(9600); } void loop() { //Escrita Serial.print("Gravando numero na memoria EEPROM : "); Serial.println(numero); EEPROM.write(endereco, numero); delay(2000); //Leitura Serial.print("Lendo numero da memoria EEPROM : "); Serial.println(EEPROM.read(endereco)); while(1) {} }
Mas se cada posição armazena apenas um byte, como eu vou armazenar um número inteiro (2 bytes) na EEPROM?
Gravando um número inteiro na memória EEPROM
Um INT (inteiro) no Arduino Uno e em outras placas baseadas no ATMega, é um número entre -32.768 e 32.767, que ocupa 2 bytes (16 bits) de memória.
Uma das maneiras de gravar um número inteiro na EEPROM é separar esse número em duas partes, e gravar cada uma separadamente.
Digo “uma das maneiras”, porque você pode utilizar as próprias funções da biblioteca para gravar dados na EEPROM, usando os comandos abaixo:
void eeprom_write_word (uint16_t *__p, uint16_t __value)
void eeprom_write_float (float *__p, float __value)
void eeprom_write_block (const void *__src, void *__dst, size_t __n)
A primeira opção, por exemplo, utiliza o uint16_t, que é um unsigned int de 16 bits, cujo valor vai de 0 a 65.535.
No meu método mais arcaico, eu armazeno o INT dividindo-o em duas partes : primeiro divido o número que desejo armazenar por 256, obtendo a primeira parte, e depois uso a função % (modulo), para obter a segunda parte. Posteriormente, coloco cada uma delas em um endereço de memória diferente.
Eu faço isso no programa abaixo, gravando o número 23767 na memória separando-o assim:
Primeira parte : 23767 / 256 = 92 (apenas a parte inteira do número)
Segunda parte : 23767 % 256 = 215 (resto da divisão)
Depois de ler o valor em memória, preciso montar novamente o valor original, juntando as 2 partes. Para isso uso:
Valor original = (parte1 * 256) + parte2
//Programa: Escrita e leitura EEPROM - INT //Autor: Arduino e Cia //Carrega a biblioteca #include <EEPROM.h> //Numero a ser armazenado int numero = 23767; //Endereco onde sera armazenada a parte1 (primeiro byte) int endereco1 = 0; //Endereco onde sera armazenada a parte2 (segundo byte) int endereco2 = 1; void setup() { Serial.begin(9600); } void loop() { Serial.print("Gravando numero na memoria EEPROM : "); Serial.println(numero); //Grava a primeira parte do numero em endereco1 EEPROM.write(0, numero/256); Serial.print("Parte 1 : "); Serial.println(numero/256); //Grava a segunda parte do numero em endereco2 EEPROM.write(1, numero%256); Serial.print("Parte 2 : "); Serial.println(numero%256); delay(2000); //Leitura Serial.println("nLendo numero da memoria EEPROM... "); Serial.print("Lendo parte 1 : "); int parte1 = EEPROM.read(0); Serial.println(parte1); Serial.print("Lendo parte 2 : "); int parte2 = EEPROM.read(1); Serial.println(parte2); Serial.print("Valor original : "); int valor_original = (parte1 * 256) + parte2; Serial.println(valor_original); while(1) {} }
Isso quer dizer que a partir de agora você pode gravar todos os dados na memória EEPROM do Arduino? Infelizmente não.
Segundo o datasheet do ATMega328P , temos um limite de ciclos de leitura e escrita na memória EEPROM. Esse número é de aproximadamente 100.000 ciclos.
Apesar de ser um número relativamente grande, procure usar um intervalo maior para gravação, ou utilize-o apenas para valores essenciais, como por exemplo os valores máximo e mínimo de um sensor de temperatura.
Gostou? Então confira outros posts utilizando Arduino aqui mesmo no Arduino e Cia!
Prezados senhores, apliquei o seu principio para um hidrometro que eu estou desenvolvendo, porem os valores estão na casa dos 56179 litros e da erro ao aplicar a formula. Tem como altera-la par a que possa trabalhar com 7 digitos ? Agradeço o retorno pelo e-mail [email protected] .
Boa tarde,
Entendi… tente este artigo, creio que tem o que você precisa :
http://playground.arduino.cc/Code/EEPROMWriteAnything
Abraço !
Boa tarde,
Sou novo no mundo arduino, alias em eletrônica.
Tenho um citcuto q acenfe 16 leds d forma sequencial, com intervalos programados e apresentados no lcd.
Acontece q quando desligo tenho q programar tudo d novo.
Gostaria d gravar na eeprom, tentei gravar e da sempre umnúmero diferente, ex: deixo programado 10000ms qdo ligo ta em 9994ms.
O q pode ser?
Obrigado.
ps. Nao queria comentar como anônimo, mas nao consegui pela conta do Google
[email protected]
Boa noite Carlos,
Você está usando o método de gravar um número inteiro ou o método "simples", que grava apenas até 255 ? Pode ser esse o problema.
Abraço !
Cara, é porque a eeprom so grava numeros inteiros e quando voce divide 10000/256 da 39.0625 e o arduino só vai gravar o numero 39 que é o inteiro e o restante se perdera, por isso quando voce vai ler esta estara menor. Para nao acontecer isso temos que gravar a nivel de bit. neste momento estou vendo uma maneira facil de se fazer isso.
boa noite , tenho um gerador de sinal ajustável controlado pelo arduino que gera um sinal de 1 a 30mhz , quando ele é desligado e eu religo volta sempre na mesma frequência inicial , gostaria defase-lo voltar na ultima frequência ajustada antes do desligamento , pode me ajudar ? parabéns pelo blog ..sempre estou lendo seus artigos
Boa noite,
Obrigado. Você vai gravar um número entre 0 e 255 ? Vc pode usar este exemplo do artigo mesmo.
Abraço !
Boa tarde. Utilizando o exemplo acima como gravar por exemplo o nr 65.535. Muito obrigado. Abraço.
Boa noite,
Utilize o segundo programa deste post, ou então a função void eeprom_write_word (uint16_t *__p, uint16_t __value).
Abraço!
olá boa noite amigo gostaria de lhe pedir ajuda:
é seguinte amigo é que eu tou usando um projetinho arduino +bluetooth eu uso este código:
void setup()
{
pinMode(13,OUTPUT);
pinMode(12, OUTPUT);
pinMode(11, OUTPUT);
pinMode(10, OUTPUT);
pinMode(9, OUTPUT);
Serial.begin(9600);
}
void loop()
{delay(1000);
if (Serial.available())
{int c=Serial.read();
if(c=='y')
{
digitalWrite(13,HIGH);
Serial.println("Ok, Moto ligada!");
}
else if(c=='w')
{
digitalWrite(13,LOW);
Serial.println("Ok, Moto desligada!");
}
if(c=='b')
{
digitalWrite(12,HIGH);
Serial.println("Ok, Partida ligada!");
}
else if(c=='v')
{
digitalWrite(12,LOW);
Serial.println("Ok, led desligado!");
}
if(c=='c')
{
digitalWrite(11,HIGH);
Serial.println("Ok, led ligado!");
}
else if(c=='x')
{
digitalWrite(11,LOW);
Serial.println("Ok, led desligado!");
}
if(c=='d')
{
digitalWrite(10,HIGH);
Serial.println("Ok, led ligado!");
}
else if(c=='z')
{
digitalWrite(10,LOW);
Serial.println("Ok, led desligado!");
}
if(c=='e')
{
digitalWrite(9,HIGH);
Serial.println("Ok, led ligado!");
}
else if(c=='t')
{
digitalWrite(9,LOW);
Serial.println("Ok, led desligado!");
}}} como é visto no código eu ligo e desligo as portas configuradas enviando caracteres. Eu quero quando eu enviar por ex: o "y" que liga a porta 13, quando eu desligar o Arduino e ligar novamente esta porta continue ligada, entende amigo, ou seja eu quero memorizar o ultimo estado da porta. porem não sei como fazer isso. por favor me ajude amigo
Olá Amigo !!! Será que você pode me ajudar ? Eu utilizei esse segundo código mas que usa um numero conhecido: int numero = 23767; E se eu quisesse armazenar um numero que veio pela serial e que fica armazenado numa variável: Fiz esse código que eu mostro abaixo mas sempre retorna valor original 49. O que eu estou fazendo de errado ? Grande Abraço !!! Michel Ferrari.
#include
// Numero a ser armazenado
int numero;
int contador;
// Endereco onde sera armazenada a parte1 (primeiro byte)
int endereco1 = 0;
// Endereco onde sera armazenada a parte2 (segundo byte)
int endereco2 = 1;
void setup()
{
Serial.begin(9600);
}
void loop()
{
if (Serial.available()){
contador = Serial.read();
numero = contador;
}
if (numero != 0){
Serial.print("Gravando numero na memoria EEPROM : ");
Serial.println(numero);
// Grava a primeira parte do numero em endereco1
EEPROM.write(0, numero/256);
Serial.print("Parte 1 : ");
Serial.println(numero/256);
// Grava a segunda parte do numero em endereco2
EEPROM.write(1, numero%256);
Serial.print("Parte 2 : ");
Serial.println(numero%256);
delay(2000);
// Leitura
Serial.println("nLendo numero da memoria EEPROM… ");
Serial.print("Lendo parte 1 : ");
int parte1 = EEPROM.read(0);
Serial.println(parte1);
Serial.print("Lendo parte 2 : ");
int parte2 = EEPROM.read(1);
Serial.println(parte2);
Serial.print("Valor original : ");
int valor_original = (parte1 * 256) + parte2;
Serial.println(valor_original,DEC);
while(1);
{}
}
}
pessoal,,, sou novo no assunto então vou direto ao meu ponto
preciso acionar um botão fisico (entrada) que saia na saida como audio
minha pergunta é,,, como estocar esse audio na memoria dele, e qual formato é aceito
Bom dia Fernando,
Dependendo do formato de áudio, vai ser mais fácil vc armazenar isso em um cartão SD, ou se quiser mesmo armazenar na memória, adquirir uma "expansão de memória EEPROM" para Arduino, já que a memória embutida no microcontrolador geralmente é pequena (1 ou 2K, por exemplo).
Abraço!
ola, boa noite, gostaria de saber como posso fazer pra gravar esse dado em hexa 03 A5 CE F7 ?
Olá.
Alguem teria um sketch referencia para gravar valores do teclado 4×3 pra gravar senha de 4 digitos. Somente preciso da parte da senha na EEPROM, o resto ja tenho tudo.
Obrigaado
Olá,
estou precisando trabalhar com hexadecimal preciso gravar o valor diretamente na memoria, EX: gravar o valor "02 em hexadecimal" no endereço "0" da memoria eeprom. Existe alguma solução para isso?
Olá, o que acontece após atingir os 100.000 ciclos da memória EEPROM?
Mesmo, se eu inserir um valor zero na memória, é contada como um ciclo?
Se eu apertar no botão Reset do arduino, eu vou a ter os 100.000 ciclos novamente?
Obrigado.
Boa noite,
Não, quando ele atingir 100.000 ciclos, ele simplesmente não vai gravar nada naquela posição de memória. O botão de reset não tem efeito sobre esse contador.
Abraço!
olá pessoal, sou inciante ainda, e gostaria de saber se é possível gravar um valor lido no sensor apenas a primeira vez na eeprom e depois ele ler novamente o sensor e apenas comparar ? se for possível possuem algum código de exemplo ?
O senhor pode nos dar um exemplo de como escrever um dado float na EEPROM?
Olá amigo, tem como fazer um exemplo de como salvar um valor float e depois fazer leitura dele. tipo um valor de duas casas decimais, tipo 99,99
byte addresstempMaxima = 0;
byte addresstempMinima = 2;
void gravar(float x,byte p) //X valor a ser salvo P posição na memoria
{
EEPROM.write (p,int(x));
EEPROM.write (p+1,int((x-int(x))*100));
}
float ler(byte p)
{
return float(EEPROM.read(p))+ float(EEPROM.read(p+1))/100;
}
é isso ai
tem uma livraria que grava qualquer tipo de dados na eeprom, ele EEPROMEx.
para gravar um numero flaot " EEPROM.writeFloat(enderço, numerosergravado)
para ler EEPROM.readFloat(endereço)
Boa tarde! Estou começando agora com arduino e gostaria de saber se tem como usar dois projetos (comandos) no mesmo arduino? Tipo: fiz um circuito pra um sensor pir,usa asportas 3 e 5, mas queria usar simutâneamente o módulo bluethooth onde uso as portas 11,12 e 13. Consigo fazer cada um individualmente, mas queria usar os dois, sendo circuitos independentes. Desde já agradeço pela atenção.
Boa tarde! Estou começando agora com arduino e gostaria de saber se tem como usar dois projetos (comandos) no mesmo arduino? Tipo: fiz um circuito pra um sensor pir,usa asportas 3 e 5, mas queria usar simutâneamente o módulo bluethooth onde uso as portas 11,12 e 13. Consigo fazer cada um individualmente, mas queria usar os dois, sendo circuitos independentes. Desde já agradeço pela atenção.
Funcionou perfeitamente, fiz umas pequenas adaptação e implementei ao meu projeto e ficou show, parabéns!
Oi Fernando!
Show! Obrigado pelo retorno. Abraços! 🙂
Adilson
Olá! Estou projetando um exaustor na escola e gostaria de marcar as horas que um motor esteve ligado em um display lcd com arduino. Quando atingir 5000 horas pretendo aplicar algum tipo de aviso de troca de filtro. É possivel? Necessito usar a eeprom? O código é muito complexo? Desde já agradeço!
Gostaria de salvar na eeprom a hora em que ocorre um evento ( tipo sinal de um sensor) e depois descarregar esses dados para comparação ..como seria?
boa tarde.
estou precisando de um projeto para o arduino due.
que leia todo o conteudo de uma memoria st 95320.
depois regrava-la.
contato,[email protected]
ola, estou começando com arduino.
quero fazer uma leitura em uma memoria 95040.
endereço 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
01 01 02 … 0E 0F
02
03
.
.
.
FF 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
COMO FAZER UM PROJETO PARA LER TODO O CONTEUDO.
desde ja agradeço.
[email protected]
Estou usando 4 servo motores e 4 poteciomentors. Eu quero gravar movimentos que faço com os servos e que fique gravado no eeprom, pra quando aberta um botão ele repita o movimento que gravei sozinho No loop. Se mim ajudar vou agradecer muito!!!
[…] evitar isso, uma alternativa é você usar a EEPROM do Arduino para guardar esses dados. No post Como gravar dados na memória EEPROM do Arduino eu mostro como você pode fazer isso de um jeito relativamente […]
Olá, gostaria de saber se tem como colocar um contador que incremente na variavel numero da memoria EEPROM do arduino.
O problema é o seguinte: sempre que reseto o arduino o numero 123 que foi colocado vai aparecer pois foi salvo na EEPROM, o problema maior é que se eu coloco um contador que incremente e o numero fique 124, se o arduino for resetado o numero volta para o 123.
Se puder me responder o mais rapido possivel, ficarei muito grato.
Muito boa sua explicação , pois não ficou apenas em códigos prontos (bibliotecas), vc foi alem .Isso é muito bom pois quando apenas fazemos ctrl C e ctrl V não aprendemos muito e se der errado abandonamos o projetos não temos o que fazer
Utilizar uma estrutura UNION não seria mais fácil para gravar o número na EEPROM? Seria um código assim:
Declaração:
union eeprom_value {
uint16_t input;
char[2] output;
};
typedef eeprom_value value_t;
Para gravar na memória:
value_t v;
v.input = 1456 // Valor a ser armazenado
int end = 0; // Endereço
for (int i = 0; i < 2; ++i) {
EEPROM.write(end+i, v.output[i]);
}
Para ler da memória:
value_t v;
int end = 0;
for (int i=0; i < 2; ++i) {
v.output[i] = EEPROM.read(end+i);
}
uint16_t x;
x = v.input;
NOTA: Não testei nenhum destes códigos.
O código acima vale para números uint16_t (2 bytes). Se quiser armazenar valores maiores, Modifique o tipo da variável input e o tamanho do vetor output, para continuarem coincidindo o tamanho (se input for uint32_t, utilize output char[4], por exemplo), e altere o i < 2 dos laços for para o novo tamanho.
É importante ressaltar a escolha dos números de endereço, para evitar sobreposição. Para gravar valores uint16_t, utilize sempre múltiplos de 2. Para valores uint32_t utilize múltiplos de 4. Assim não há risco nunca de haver sobreposição de escrita de valores na EEPROM
Deve fazer uma revisão: Para funcionar precisa adicionar:
void setup()
{
EEPROM.begin(EEPROM_SIZE);
}
e ao final, para validar os comando de gravar adicionar: EEPROM.commit();
Oi Daniel!
Obrigado. Pra mim aqui funcionou sem essas duas linhas. Pra vc deu erro?
Abraço!
Adilson
Excelente artigo! estou fazendo um código onde preciso de uma média de resistencia pois estou trabalhando com resistencias variáveis, a principio o codigo funciona muito bem, porém para cada projeto implantado eu preciso inserir os dados toda vez e cada máquina apresenta valores de resistencia variáveis distintas, o que eu queria ( não sei se seria possivel) é uma maneira de inserir os dados atraves de botões externos ja que no projeto eu uso um display lcd 16×2. exemplo: quando o arduino for ligado pela primeira vez ele vai pedir os valores máximo e mínimol, após serem inseridos ela irá gravar os valores e a partir de então eliminar essa edição no código. ( não sei se consegui explicar)
Oi Davidson,
É possível sim. Você pode implementar uma rotina que vai ser executada uma única vez, quando a posição de memória “XYZ” estiver vazia ou tiver, por exemplo, o valor 0.
Nessa rotina você coloca o processo de ler os botões e ao gravar o dado na memória na posição XYZ ele não vai executar a rotina na próxima vez que você ligar o Arduino.
Abraço!
Adilson