Problema Muestreo de temperatura EEPROM

Qué tal comunidad. He estado trabajando en el desarrollo de un proyecto para monitorear la temperatura de las cámaras de los camiones que transportan alimentos que deben estar a una temperatura inferior a los 0°C. El objetivo es utilizar 2 sesnsores lm355 y un arduino nano. Colocar el embebido en las cámaras y estar muestreando 64 veces cada 3 minutos y guardar el promedio de esa muestra en la EEPROM del arduino. He estado haciendo pruebas y funciona bien para medir la temperatura y monitorearla mediante el puerto serial. El problema es a la hora de querer recuperar los datos guardados en la EEPROM. El objetivo es que cuando la carga llegue a su destino poder conectar el arduino a un ordenador y abriendo un interruptor al puerto 2 del arduino y mediante el programa TeraTerm poder ver los valores de la memoria. Pero no logro hacerlo. Alguna idea?

Mi código es el siguiente:

#include <EEPROM.h>
int numeroMuestras=64;
int i=0,j=0;
float promedio=0.0; 
float temperatura[64];
int memFull = 12;
int addr = 0;
int address = 0;
byte value;



void setup(){
Serial.begin (9600); //inicia comunicacion serial
pinMode(2, INPUT);
}


void loop(){
 
//Calcula la temperatura usando como referencia 5v
for(i=0;i<=numeroMuestras;i++)
{
 temperatura[i] = (5.0 * analogRead(0)*100.0)/1023.0;
 delay ((180/64)*1000); 
}
for(j=0;j<=numeroMuestras;j++)
{
 promedio=promedio+temperatura[j];
}
promedio=promedio/numeroMuestras;

//Empezar a guardar los datos en la EEPROM
EEPROM.write(addr, promedio);
 addr = addr + 1;
 if (addr == 512)
 {
   addr = 0;
   digitalWrite(memFull, HIGH);
 }
 
 

      //Para leero los datos de la EEPROM
        if(digitalRead(2)==HIGH)
           {
   value = EEPROM.read(address);
 Serial.print(address);
 Serial.print("\t");
 Serial.print(value, DEC);
 Serial.println();
 address = address + 1;
 if (address == 512)
 {
   address = 0; 
 }
 delay(500);
           }
   
   

 
}

El switch está conectado de la siguiente manera.Una pata va a 5Vcc, la otra a una resistencia de 10K que va a Gnd y de ese mismo nodo sale un alambre al D2 del arduino.
He pensado en utilizar una estructura "Switch/Case" para comenzar a leer la EEPROM.
De tal forma que sea...

siwtch(digitalRead(2))
{
     case LOW:
      //Hacer todo el muestreo
      break;

     case HIGH:
      //Hacer rutina para leer los datos de la EEPROM
      break;
}

Antes, recordarte que debes leer las Normas del Foro y luego edita tu post insertando los tags para códigos. Se ve horrible tu código simplemente pasteado como lo has hecho.

Vamos a tu problema:
La EEPROM de un NANO/UNO solo puede escribirse 100.000 veces. Recuerdalo por si cambias esa tasa de muetreo.
Luego si haces una cuenta no pierdas tiempo haciendola todo el tiempo.
La calculas y las pegas 180/641000=2812
Simplemente pones delay(2812) y deberías compensar lo que te pierdes en 64 iteracciones 64
0.5= 32 factor de conversión.

for(i=0;i<=numeroMuestras;i++)
{
  temperatura = (5.0 * analogRead(0)*100.0)/1023.0;
  delay ((180/64)*1000); 
}

Esto debiera ser temperatura
Luego escribes
* *EEPROM.write(addr, promedio);* *
donde addr esta bien y promedio es un valor float.
Pero que dice el Playground al respecto
EEPROM.Write
Description
Write a byte to the EEPROM.
Syntax
EEPROM.write(address, value)
Parameters
address: the location to write to, starting from 0 (int)
value: the value to write, from 0 to 255 (byte)
Entonces para guardar un float necesitas modificiaciones a tu códgo.
La mejor opcion es usar esto que recomienda el Playground de Arduinio.
```
template int EEPROM_writeAnything(int ee, const T& value)
{
   const byte
p = (const byte*)(const void*)&value;
   unsigned int i;
   for (i = 0; i < sizeof(value); i++)
         EEPROM.write(ee++, *p++);
   return i;
}

template int EEPROM_readAnything(int ee, T& value)
{
   byte* p = (byte*)(void*)&value;
   unsigned int i;
   for (i = 0; i < sizeof(value); i++)
         p++ = EEPROM.read(ee++);
   return i;
}

* *Entonces la usas asi* *
EEPROM_writeAnything(addr, promedio);
* *y la lees * *
EEPROM_readAnything(addr, promedio);
```

Gracias por responder. Lo siento, no vuelve a pasar lo de los tags para el código.

He hecho las modificaciones al programa, pero me manda mensajes de error a la hora de compilar; es la primera vez que lo utilizo y no se si lo estoy haciendo bien. Las modificaciones que hice son las siguientes:

switch(digitalRead(2))
  {
    case LOW:
  
//Calcula la temperatura usando como referencia 5v
for(i=0;i<=numeroMuestras;i++)
{
  temperatura[i] = (5.0 * analogRead(0)*100.0)/1023.0;
  delay ((180/64)*1000); 
}
for(j=0;j<=numeroMuestras;j++)
{
  promedio=promedio+temperatura[j];
}
promedio=promedio/numeroMuestras;

//Empezar a guardar los datos en la EEPROM
template <class T> int EEPROM_writeAnything(addr, promedio)
{
    const byte* p = (const byte*)(const void*)&value;
    unsigned int i;
    for (i = 0; i < sizeof(value); i++)
          EEPROM.write(ee++, *p++);
    return i;
}
  break;

Y para leer datos de la EEPROM, tengo lo siguiente:

case HIGH:
       //Para leero los datos de la EEPROM        
    template <class T> int EEPROM_readAnything(addr, promedio)
{
    byte* p = (byte*)(void*)&value;
    unsigned int i;
    for (i = 0; i < sizeof(value); i++)
          *p++ = EEPROM.read(ee++);
    return i;
}       
   break;

Y me aparece el siguiente mensaje de error:

Arduino:1.6.3 (Windows 7), Placa:"Arduino Nano, ATmega328"

Opciones de compilación cambiadas, reconstruyendo todo

TermometroGuardaDatos2.ino: In function 'void loop()':

TermometroGuardaDatos2.ino:40:1: error: a template declaration cannot appear at block scope

TermometroGuardaDatos2.ino:48:3: error: expected ';' before 'break'

TermometroGuardaDatos2.ino:52:5: error: a template declaration cannot appear at block scope

TermometroGuardaDatos2.ino:60:4: error: expected ';' before 'break'

Error de compilación

  This report would have more information with
  "Show verbose output during compilation"
  activala desde Archivo > Preferencias

Vamos a hacer como que el anterior mensaje jamas ha existido jRider y te voy a explicar lo que deberías hacer

tienes que crear un fichero con este contenido

#include <EEPROM.h>
#include <Arduino.h>  // for type definitions

template <class T> int EEPROM_writeAnything(int ee, const T& value)
{
    const byte* p = (const byte*)(const void*)&value;
    unsigned int i;
    for (i = 0; i < sizeof(value); i++)
          EEPROM.write(ee++, *p++);
    return i;
}

template <class T> int EEPROM_readAnything(int ee, T& value)
{
    byte* p = (byte*)(void*)&value;
    unsigned int i;
    for (i = 0; i < sizeof(value); i++)
          *p++ = EEPROM.read(ee++);
    return i;
}

Y guardarlo como EEPROMAnything.h

Luego al principio de tu codigo añadir

#include "EEPROMAnything.h"

Y por ultimo donde hacias EEPROM.write(addr, promedio); hacer

EEPROM_writeAnything(addr, promedio);

si olvidar que donde hacias address = address + 1;

ahora tienes que hacer:

address = address + 4;

GO_zalo, hice lo que me dijiste, guardé el siguiente código con el nombre EEPROMAnything.h en la misma carpeta que está el programa del termómetro. Pero al código al momento de compilarlo sigue marcando erroes. El código es:

#include <EEPROM.h>
#include <Arduino.h>  // for type definitions
void setup() {
  // put your setup code here, to run once:

}

void loop() {
  template <class T> int EEPROM_writeAnything(int ee, const T& value)
{
    const byte* p = (const byte*)(const void*)&value;
    unsigned int i;
    for (i = 0; i < sizeof(value); i++)
          EEPROM.write(ee++, *p++);
    return i;
}

template <class T> int EEPROM_readAnything(int ee, T& value)
{
    byte* p = (byte*)(void*)&value;
    unsigned int i;
    for (i = 0; i < sizeof(value); i++)
          *p++ = EEPROM.read(ee++);
    return i;
}

}

Y en mi código solo hice las modificaciones:

<U+202A>#‎include<U+202C> <EEPROM.h>
#include "EEPROMAnything.h"
EEPROM.writeAnything(addr, promedio);
addr = addr + 1;
if (addr == 512)
{
addr = 0;
digitalWrite(memFull, HIGH);
}
break;
case HIGH:

//Para leero los datos de la EEPROM
value = EEPROM.read(address);
Serial.print(address);
Serial.print("\t");
Serial.print(value, DEC);
Serial.println();
address = address + 4;
if (address == 512)
{
address = 0; 
}
delay(500);

Pero me manda este mensaje:

Arduino:1.6.3 (Windows 7), Placa:"Arduino Nano, ATmega328"

Opciones de compilación cambiadas, reconstruyendo todo

TermometroGuardaDatos2.ino:1:1: error: stray '\' in program

TermometroGuardaDatos2.ino:1:7: error: stray '#' in program

TermometroGuardaDatos2.ino:1:1: error: stray '\' in program

TermometroGuardaDatos2.ino:1:1: error: stray '\' in program

TermometroGuardaDatos2.ino:2:28: fatal error: EEPROMAnything.h: No such file or directory

compilation terminated.

Error de compilación

  This report would have more information with
  "Show verbose output during compilation"
  activala desde Archivo > Preferencias

no pegues partes del codigo pega el codigo entreo

dentro del loop no va eso de template int EEPROM_writeAnything(int ee, const T& value)... va en el archivo aparte que te explique

Vale, el código entero:

#‎include<U+202C> <EEPROM.h>
#include "EEPROMAnything.h"
int numeroMuestras=64;
int i=0,j=0;
float promedio=0.0; 
float temperatura[64];
int memFull = 12;
int addr = 0;
int address = 0;
byte value;

void setup(){
Serial.begin (9600); //inicia comunicacion serial
pinMode(2, INPUT);
}

void loop(){
switch(digitalRead(2))
{
case LOW:
//Calcula la temperatura usando como referencia 5v
for(i=0;i<=numeroMuestras;i++)
{
temperatura[i] = (5.0 * analogRead(0)*100.0)/1023.0;
delay ((180/64)*1000); 
}
for(j=0;j<=numeroMuestras;j++)
{
promedio=promedio+temperatura[j];
}
promedio=promedio/numeroMuestras;
//Empezar a guardar los datos en la EEPROM
EEPROM.writeAnything(addr, promedio);
addr = addr + 1;
if (addr == 512)
{
addr = 0;
digitalWrite(memFull, HIGH);
}
break;
case HIGH:

//Para leero los datos de la EEPROM
value = EEPROM.read(address);
Serial.print(address);
Serial.print("\t");
Serial.print(value, DEC);
Serial.println();
address = address + 4;
if (address == 512)
{
address = 0; 
}
delay(500);
break;
default:
break; 
}
}

Lo del fichero no lo entiendo. Cómo se crea el archivo aparte?

Hola:

Veo que usas poca memoria para guardar datos, de toda maneras puedes verlas externas con protocolo I2C y SPI que es más rápida.

Ver enlace.

Preferiblemente se suele usar tarjetas Micro-SD para hacer ese tipos de tareas. Las EEPROM, sobre tod interna, está bien para guardar y recuperer datos de configuraciones. Por ejemplo, los canales de la TV, el volumen, contraste, todo eso en la EEPROM tipo 24LCxx. Eso si, otros TV le dan por guardarla dentro de la EEPROM principal del firmware, cosa rara pero cada vez se ven más. Normalemente van fuera.

Fuente:

Un cordial saludo.

Aca la solución.
MIra los archivos que adjunto.

EEPROM.zip (1.1 KB)

Metaconta:
Hola:

Veo que usas poca memoria para guardar datos, de toda maneras puedes verlas externas con protocolo I2C y SPI que es más rápida.

Ver enlace.

Preferiblemente se suele usar tarjetas Micro-SD para hacer ese tipos de tareas. Las EEPROM, sobre tod interna, está bien para guardar y recuperer datos de configuraciones. Por ejemplo, los canales de la TV, el volumen, contraste, todo eso en la EEPROM tipo 24LCxx. Eso si, otros TV le dan por guardarla dentro de la EEPROM principal del firmware, cosa rara pero cada vez se ven más. Normalemente van fuera.

Fuente:
Registrador de temperatura con Arduino [DIY]

Un cordial saludo.

Metaconta, es una muy buena opción también. En el futuro la pondré en práctica, muchas gracias por la información.

surbyte:
Aca la solución.
MIra los archivos que adjunto.

Surbyte, definitivamente esta es la solución que buscaba. Muy agradecido de verdad.
Saludos!

Buenas:

La ventaja que tiene, puedes guardar los datos con extensiones conocidas como text o el de excell, después lo pasas al PC y lo entiende, la EEPROM interna no. ejjejej.

Saludos.

surbyte:
Aca la solución.
MIra los archivos que adjunto.

Solo una pregunta mas. Cómo puedo hacer para que al momento de pasar los datos a la pc, sólo me muestre las temperaturas que ha guardado y no todo lo que tiene la memoria? Hice un programa que guarda 0s en la memoria, entonces las temperaturas las sobre escribe. Pero al momento de pasar los datos, si solo ha guardado 2 temperaturas, me muestra todos los ceros que tiene la memoria. Intente hacerlo con un ciclo. Pero no resultó.

case HIGH:
    //Para leer los datos de la EEPROM
        for(k=0;k<=cont;k++)
        {
      	value = EEPROM_readAnything(address, promedio);
        Serial.print(promedio, 2);
        Serial.print("\t");
      	Serial.println();
      	address = address + 4;
      	if (address == 512) {
      		address = 0; 
      	}
      	delay(250);
        }
      break;

Y bueno descarta todo lo que es 0
Pregunta si distinto de 0, y si lo es lo envías.

  for(k=0;k<=cont;k++)
        {
      	value = EEPROM_readAnything(address, promedio);
        if (value > 0.0) {
           Serial.print(promedio, 2);
           Serial.print("\t");
           Serial.println();
        }
       	address = address + 4;
      	if (address == 512) {
      		address = 0; 
      	}

porque escaneas de este modo y no asi

    for(address=0;k<=512;address=address+4) {
      	value = EEPROM_readAnything(address, promedio); // lees el valor
        if (value > 0.0) {       // si es mayor que 0 lo presentas
           Serial.print(promedio, 2);
           Serial.print("\t");
           Serial.println();
        }
       // else break; // usa esta linea si quieres interrumpir la lectura cuando lees un 0.
   }

ahora en cuanto lees un 0 no deberías interrumpir el for? para que seguir si no se ha llenado?
Si guardaste dos datos leerás address 0 y 4 y luego cuando intentes leer 8 dará un 0, entonces sales del for.

Sigue sin parar. Lo he dejado que muestree solamente una temperatura. Pero al momento de pasar los datos al ordenador, me escribe la misma temperatura 512 veces. No sé que tengo mal en los ciclos, o qué pueda estar mal al momento de leer la memoria :frowning: Esta fue la modificación al código. Lo intente tanto con (;address<=512;) y (;k<=512;)

    //Para leer los datos de la EEPROM

        
        for(address=0;address<=512;address=address+4)
          {
      value = EEPROM_readAnything(address, promedio);
      if(value!=0.0)
      {
        Serial.print(promedio, 2);
        Serial.print("\t");
      	Serial.println();
       }
       
          }

¿Donde dices

if(value!=0.0)

No debería ser

if(promedio!=0.0)

?

Tiene razón noter, valor no devuelve mas que la dirección de la EEPROM, el valor es transferido a la variable promedio y por ende se debe comparar con el.

ahora veo que hay las funciones https://www.arduino.cc/en/Reference/EEPROMPut para leer y escribir cualquier tipo de dato en la eeprom sin necesidad del eepromAnything

Buena observación, GO_zalo. Supongo que sean funciones (más bien sospecho macros) de las últimas versiones del IDE, o sencillamente se me escaparon cuando ojeé la referencia de EEPROM. Tomo nota de las tres que aparecen.