Bom dia

 Tenho um código que escreve na EEPROM  valores diferentes no mesmo endereço.

  Entretanto, me deparo com  situações estranhas e gostaria de tentar entender o porque disso.
  O problema ocorre independente se escrevo como INT ou DOUBLE  ou FLOAT .

 Nesse exemplo :

 EEPROM.put(72, 232.56 );
 EEPROM.put(72,     0.89 );
 EEPROM.put(72, 655.40 );

 ou Neste :

 EEPROM.put(72, 23256 );

 EEPROM.put(72,     890   );
 EEPROM.put(72, 65540 );

  O ultimo dado gravado mostrarpa sempre  :  Se Int  =  4   , se Double = 0.04

  Porque? Alguém sabe?

  Agradeçp desde já qualquer ajuda.

Exibições: 607

Responder esta

Respostas a este tópico

olá César,

      eu sei o motivo.  Mas essa "eu passo",  porquê sua questão não está bem formulada,  e não tão clara.  E provavelmente vc precisa postar partes do seu código para serem usadas como referência pra te mostrar este motivo.

      Mas acredito que o RV (Mineirin) não seja tão chato como eu nesta questão,  e provavelmente ele irá te ajudar (mas certamente vc terá que esclarecer alguns pontos, além de mostrar pra ele mais algumas partes relevantes do seu código).

      Mas esclarecendo sobre o "float"  e o "double" :  atente que no Arduino convencional  (UNO, Mega, Nano, etc),  o tipo "double"  é o mesmo que "float",  e ambos são representados em 32 bits (4 Bytes), e tem uma precisão  de no máximo 7 dígitos decimais (isto no total: contando à direita e à esquerda do ponto decimal). Então nestes Arduinos,  não adianta usar o tipo "double",  pois não se consegue aumentar nem o alcance numérico nem a precisão além do proporcionado pelo tipo "float".

      Apenas nos Arduinos  que são "mais parrudos" em performance,  é que o "float"  e "double"  são distintos entre si.  Nestes casos,  o "float"  continua sendo de 32 bits, com uma precisão de no máximo 7 dígitos (novamente, isto no total: contando à direita e à esquerda do ponto decimal).  Mas o "double"  é normalmente de 64 bits (8 Bytes, como é o caso do ESP32, Due, STM32, etc), e por isso possuem uma precisão de no máximo 19 dígitos (novamente, isto no total: contando à direita e à esquerda do ponto decimal).

      abrçs,

      Elcids

 

   Se você pegar as 3 linhas de código de qualquer um dos exemplos, mandando escrever  na Serial  o valor obtido após cada "put" e compilar, verá que o terceiro resultado não corresponde ao valor que deveria mostrar por algum motivo.   Esse aí seria todo o código:

int a= 0;
EEPROM.put(72, 23256 );
EEPROM.get(72,a );
EEPROM.put(72, 1089 );
EEPROM.get(72,a );
EEPROM.put(72, 65540 );
EEPROM.get(72,a );
Serial.println (a );
delay(100);

Porque o resultado mostrado é 4 invés de 65540 que é o último valor colocado no endereço 72 do exemplo?
  Só essa mesmo a questão . Alguém sabe o porque?

ok Cesar,

      agora melhorou.

      Vc declarou "a" como tipo "int", que é de 16 bits "sinalizados", e que pode representar valores entre -32768 e +32767.

      Então vc tenta salvar o valor 65540,  que é um valor de 17 bits (em Hexa 0x10004).  Ou seja, infelizmente para seu azar,  este valor tem um bit a mais que o número de bits da variável "a".

      Quando vc usa a função "put",  o compilador percebe que seu valor 65540  tem mais de 16 bits,  e por isso ele salva como sendo do tipo "long" (que é de 32 bits "sinalizados"). Então o valor é salvo corretamente na EEPROM, com todos os bits necessários para representar esse valor.

      Mas quando vc tenta ler a informação via "get",  vc especifica a variável "a", a qual comporta apenas 16 bits, e por isso são lidos apenas os 16 primeiros bits dos 32 que foram salvos na EEPROM,  ou seja é lido o valor "0x0004".  Aí está o motivo do seu "4" (já que "4" em Hexa e Decimal tem a mesma representação).

      Para comprovar,  faça um teste mudando o valor de 65540 para 74565.  Este valor (o 74565) é representado como 0x12345 que também tem 17 bits.  Então leia para a variável "a" usando o "get" como vc já estava fazendo, mas na hora de printar faça assim:

               Serial.println( a );

               Serial.println( a, HEX );

      Os valores printados serão:  "9029" (decimal)  e  "2345"  (valor de "a" em Hexa).

      Para resolver   a parte do 65540,  declare "a" como tipo "long",  ou seja, faça isso:

               long a = 0;

      Com isso,  a função "get" irá ler um valor "long" e o valor 65540 será lido corretamente.

      Mas ao fazer isso, como "a" agora é de 32 bits,  a função "get" irá ler bits adicionais errados para os valores 23256 e 1089  já que estes valores são de 16 bits e os demais bits deveriam ser "0",  o que não ocorrerá porque o "get" irá ler bits "sujos" que estão na EEPROM (tecnicamente chamados de "sticky bits").  Printe "a" após cada leitura da EEPROM  e vc irá ver isto (o 23256 e 1089 serão printados com valores errados).  Então pra evitar esse "problema",  faça assim:

               int a = 0;

               long b = 0;

               EEPROM.put( 72, 23256 );
               EEPROM.get( 72, a );

               Serial.println( a );
               EEPROM.put( 72, 1089 );
               EEPROM.get( 72, a );

               Serial.println( a );
               EEPROM.put( 72, 65540 );
               EEPROM.get( 72, b );
               Serial.println( b );
               delay(100);

      Resumindo:  atente aos tipos de dados  que vc está gravando na EEPROM,  e aos tipos que vc está usando para ler da EEPROM.

      Estude um pouco mais sobre estes tipos no site do Arduino:  "tipos de dados"

      Lá vc encontra o "tamanho" de cada tipo e informações relevantes sobre os mesmos.  O entendimento do que é "não sinalizado"  e "sinalizado",  pode te dar um pouco mais de trabalho pra entender,  mas nada que seja o fim do mundo. 

      abrçs,

      Elcids

Entendi perfeitamente.

Muito grato.

 Se você rodar o código que enviou, ele vai colocar os valores certinhos e você verá eles normalmente na Serial enquanto estiver com o cṕdigo rodando RunTime.

Entretanto, se você literalmente desligar a energia do atmega , voltar a ligá-lo e rodar o código apenas para ler aquilo que foi colocado pelo código anterior, verá que o 4 aparecerá da mesma forma ...   o porque disso?

Alguém sabe?

* Pensei até em um problema do Atmega mas já coloquei outros 2 novos e dá o mesmo problema ...

Poste os códigos que você está utilizando, principalmente o que definiu como "apenas para ler aquilo que foi colocado pelo código anterior".

Poste os sketchs completos, como anexos, caso contrário a análise fica muito difícil.

O código que me refiro é o que o Alcides postou :

 int a = 0;

               long b = 0;

               EEPROM.put( 72, 23256 );
               EEPROM.get( 72, a );

               Serial.println( a );
               EEPROM.put( 72, 1089 );
               EEPROM.get( 72, a );

               Serial.println( a );
               EEPROM.put( 72, 65540 );
               EEPROM.get( 72, b );
               Serial.println( b );
               delay(100);

Esse código escreve e lê tudo certinho ... Mas se após escrever, vc desligar a energia do  o atmega , voltar a energizar e rodar o código somente lendo o que foi escrito ( tirar os "puts"), verá que 65540  vira 4 ...  Mas após escrever, enquanto o atmega estiver energizado, o 65540 aparece normal ... Só não pode desligar a energia ...  quando voltar a ligar e for ler, já era ..lá tá o danado do 4 de volta ...:-)

olá novamente César.

      Acho que já sei a "bobagem" que vc está fazendo.  Inclusive eu já suspeitava que vc pudesse estar fazendo isso (que tem implicações "severas" em termos da performance da EEPROM).  Mas falarei sobre isso num post seguinte (e aí talvez finalmente vc entenda porquê é importante postar o código de teste por completo).

      Faça um teste com o código que irei postar aqui.  Mas  não  altere  nada no código!!!

      Mais à frente neste mesmo post,  te explico como fazer o teste.

      O código está aqui:   "teste_put_get_EEPROM_01.zip"

      Detalhe:  eu testei este código, e funcionou perfeitamente (e mesmo após desligar e religar o Arduino, não ocorreu o problema do "4").

      Para facilitar a visualização aqui do que está sendo feito neste código,  capturei todo ele em uma imagem, que vc pode ver a seguir:

(clique na figura para "zoom")

      Observe que marquei algumas regiões com cores,  pra facilitar o entendimento.

      Primeiro,  na região na cor cinza,  há a leitura de um "Comando"  via Serial (ou "Terminal do Arduino").  Este comando pode ser "p" (de "put"),  ou "g" (de "get").

      Na região na cor roxa, é executado o Comando "p".  Em outras palavras:  se vc digitar a letra "p" (sem as aspas!!!) no Terminal do Arduino  e clicar no botão "Enviar" (ou "Send"  se sua IDE estiver em inglês),  será executada a sequência de gravações e leitura da EEPROM  que vc estava fazendo, e a cada leitura o valor lido é printado no Terminal do Arduino.

      Na região na cor verde, é executado o Comando "g".  Ou seja, se vc digitar a letra "g" (sem as aspas!!!),  será executada uma leitura do endereço "72" da EEPROM,  e o valor lido (do tipo "long")  é printado no Terminal do Arduino.

      Então como fazer o teste ?

      Simplesmente execute o código no Arduino.  Na primeira vez  que vc executar,  não sabemos o que já estava gravado na EEPROM,  então não tem sentido  vc enviar de cara o Comando "g".  Por isso,  quando rodar o código pela primeira vez,  envie primeiro o Comando "p",  e confira os valores printados.

      Em seguida, envie o Comando "g",  para ver o que está no Endereço "72" da EEPROM.  Deverá ser o 65540  (já que sempre é o último dado gravado na sequência de gravações).

      Depois disso, vc pode enviar os Comandos "p" e "g" quantas vezes quiser,  e na ordem que vc quiser.

      Agora, desligue o Arduino,  aguarde uns 10 segundos,  e ligue o Arduino novamente.  Então envie primeiro  o Comando "g",  para ver se o valor 65540  ficou na EEPROM  mesmo após o Arduino ter sido desligado (deve ter ficado,  porque aqui nos meus testes de insanidade ficou).

      Faça o teste que descrevi,  e após isso, pense bastante, analise, e faça um esforço pra ver se vc sozinho consegue entender o que aconteceu naquele seu teste liga/desliga/liga que aparecia o "4".

      Mas de qualquer forma, depois eu irei explicar porque ocorreu a "anomalia" do número "4" naquele seu teste quando vc desligou e religou o Arduino.  Na verdade não é uma anomalia,  é uma "bobagem" que vc estava fazendo.

      Não se esqueça de configurar o Terminal do Arduino  de forma a poder ver os dados nele.  A figura a seguir ilustra isso:

(clique na figura para "zoom")

      Faça o teste direitinho, seguindo as instruções que coloquei.  Depois,  ao reportar o resultado aqui,  faça isso com calma,  explicando claramente seus resultados e eventuais conclusões.

      abrçs.

      Elcids

A diferença que percebi é "zerar" a variável antes de ler o dado via get, é isso?

.

    sério que vc acha que é isso?   Só que não é.

     Aquilo de zerar a variável,  tecnicamente se chama "teste de insanidade",  o que não tem relação alguma com a questão da EEPROM.

     E sobre o teste que te solicitei?  Vc fez ?

     abrçs,

     Elcids

Amigo, agradeço de verdade a boa vontade, mas quem vai passar sou eu ...

Resolvo de outra forma, grato.

Ok,  se vc decidiu assim,  ficamos por aqui.

Boa sorte no seu caminho.

RSS

© 2024   Criado por Marcelo Rodrigues.   Ativado por

Badges  |  Relatar um incidente  |  Termos de serviço