sábado, 5 de enero de 2019

La Tarjeta SD

En esta entrada vamos a utilizar un componente importante para nuestros proyectos. Hasta ahora hemos hecho uso de la EEPROM para guardar o recuperar datos, aunque ésta, está muy limitada.
Con una tarjeta SD estas limitaciones pasarán a la historia. Para manejar una tarjeta SD nos conviene hacer uso de una librería adaptada para la ocasión y además debo añadir que posee métodos muy bien diseñados, que harán de su manejo algo sencillo y potente.
#include <SD.h> con esta instrucción cargamos la librería mencionada, que incorpora varios ejemplos de código.
Para el manejo de archivos y directorios será necesario hacer uso de funciones o métodos específicos que esta librería también soporta.
Tras incluir la librería SD.h debemos declarar un objeto de tipo FILE como sigue:
File dataFile
En la función setup() debemos inicializar y comprobar la conexión con la tarjeta con una instrucción mas o menos así:
if (!SD.begin(4)){
Serial.println( "SD no conectada");
}else{ Serial.println( "SD en Conexion "); }

Ya en el cuerpo principal del programa, para poder escribir un archivo antes hay que abrirlo asi:
  dataFile=SD.open("miArchivo", FILE_WRITE);

para escribir usamos la siguiente instrucción:
  dataFile.println("misDatos");

y siempre, siempre tras una escritura hay que cerrar el archivo con la instrucción:
  dataFile.close();

A continuación vamos a ver algunas de las funciones de la librería SD y de la librería File para entender mejor lo que hemos hecho hasta ahora.

Funciones de librería SD para el manejo de Archivos y directorios:
 
SD.begin(pinCS); // inicia tarjeta SD, "pin CS" es el nº de pin de la Arduino donde conectamos CS
 SD.exists(nombreArchivo); //si existe el fichero devuelve true o false en caso contrario
 SD.remove(nombreArchivo); // borra un archivo
 SD.open(nombreArchivo, modo); // abre un archivo, existen dos modos
  // modo: FILE_WRITE abre un archivo para escritura y lectura
  // modo: FILE_READ abre un archivo para sólo lectura
 SD.mkdir(directorio); // crea un directorio
 SD.rmdir(nombreDirectorio); // elimina el directorio indicado

Funciones incorporadas del objeto FILE:

 dataFile.size() // Obtiene el tamaño del archivo en Bytes
 dataFile.available() // Comprueba si quedan bytes por leer
 dataFile.read() // Lee un byte del archivo
 dataFile.write(dato) // Escribe un byte en el archivo
 dataFile.print(dato) // Escribe una variable en un fichero; por ejemplo una string
 dataFile.position() // Obtiene el punto de lectura/escritura actual
 dataFile.seek(pos) // Mueve el punto de lectura/escritura actual a la "pos" indicada
 dataFile.close() // Cierra el fichero

Cabe señalar que dataFile puede ser cualquier otro nombre que deseemos. Este nombre se lo hemos dado al declarar el objeto FILE, recordar que si indicamos otro nombre en la declaración también tendremos que cambiarlo en las funciones que vayamos a emplear.

A continuación vamos a ver como se conecta la SD a nuestra Arduino:



La conexión de los pines SCK(13), MISO(12) y MOSI(11) deben respetarse tal como se muestran en la imagen, mientras que el pin CS de la tarjeta puede ser conectado en otro pin de la Arduino(aqui el 4), eso si al iniciar la SD con la intrucción SD.begin(pinCS) el parámetro pinCS debe coincidir con el pin que hayamos elegido.

Una vez realizadas las conexiones y vistas las instrucciones básicas para su manejo ya estamos en disposición de realizar un programilla para comprobar su manejo.
Dados los ejemplos expuestos en este blog vamos crear un programa que guarde una serie de datos en la EEPROM (ver aquí Introducción a la EEPROM) y de ahí los traspasaremos a nuestra microSD.

En concreto guardaremos en cada posición de la EEPROM su valor equivalente, es decir en la posición cero guardaremos el valor 0, en la posición uno guardaremos el valor 1 y así sucesivamente. Sucederá que como tenemos 1024 posiciones y en cada posición solo podemos guardar un valor no superior a un byte (255) este valor se verá desbordado y comenzará de cero. Para ello crearemos una variable de control que almacenará el numero de desbordamientos, al traspasar los datos almacenados en la EEPROM hacia la microSD tendremos en cuenta los desbordamientos para poder escribir en la microSD el valor que nos interesa.

En fin, aquí os dejo un Sketck de ejemplo para practicar un poco:

#include <SD.h> // Incluye la libreria para la SD

//#include <SPI.h> // incluye la libreria para el protocolo de comunicacion SPI usado por la SD. ATT. ESTA COMENTADO

#include <EEPROM.h> // incluye la libreria para el manejo de la EEPROM

File dataFile;// creamos un objeto de tipo FILE

byte desbord; // variable para el control del desbordamiento

void setup() {

  Serial.begin(9600);

  if (!SD.begin(4)){ // inicia la tarjeta SD, el pin CS conectado al pin 4 de la Arduino

    Serial.println( "SD no conectada"); // si NO detecta la tarjeta imprime por consola el mensaje

  }else{ Serial.println( "SD OK");} // si la detecta la tarjeta imprime por consola el mensaje

  if (SD.exists("myFile")){ // comprueba que el archivo llamado "myFile" se encuentra en la microSD

     Serial.println( "myFile Existe"); // si existe imprime el mensaje

      dataFile=SD.open("myFile", FILE_WRITE);// Abrimos el archivo "myFile" en modo Lectura-Escritura

        Serial.println("Escribiendo en SD"); // imprime el mensaje 

        dataFile.println("PosicionEEPROM  Valor Guardado  Valor Calculado");// imprime en el archivo la cabecera

        dataFile.println("--------------  --------------  ---------------");// imprime en el archivo el subrayado de la cabecera

        for (int i=0;i<1024;i++){ // creamos un bucle de 1023 iteraciones, una por cada posicion de la EEPROM

          EEPROM.write(i,i); // escribe en la posicion de la iteracion el mismo valor

          if (i <=255){desbord=0;} // determina el  

          if (i >255){desbord=1;} // valor de la 

          if (i >511){desbord=2;} // variable "desbord" en cada rango de bytes

          if (i >767){desbord=3;}// para cada rango de bytes

          // Los siguientes condiconales imprimin en el archivo "myFile" los valores de la iteracion  

          if (desbord==0){dataFile.print(i);dataFile.print("\t\t");dataFile.print(EEPROM.read(i));dataFile.print("\t\t");dataFile.println(EEPROM.read(i));}

          if (desbord==1){dataFile.print(i);dataFile.print("\t\t");dataFile.print(EEPROM.read(i));dataFile.print("\t\t");dataFile.println(EEPROM.read(i)+256);}

          if (desbord==2){dataFile.print(i);dataFile.print("\t\t");dataFile.print(EEPROM.read(i));dataFile.print("\t\t");dataFile.println(EEPROM.read(i)+512);}

          if (desbord==3){dataFile.print(i);dataFile.print("\t\t");dataFile.print(EEPROM.read(i));dataFile.print("\t\t");dataFile.println(EEPROM.read(i)+768);}

        }

        dataFile.println("Fin del Archivo");//imprime en el archivo el mensaje de final de archivo

        if (dataFile.size()>0){Serial.println("Escritura Finalizada con exito");}// si el archivo tiene mas de cero bytes es que la escritura a sido exitosa

        Serial.print("myFile tiene un volumen de ");Serial.print(dataFile.size());Serial.println(" bytes");// imprime el volumen del nuevo archivo

        dataFile.close(); // cierra el archivo

  }else{Serial.println("El Archivo no Existe");}// si el archivo no se halla en la tarjeta imprime el mensaje, saltandose todo el codigo anterior

}

void loop() {}


El programa esta escrito en la función setup() de manera que solo se ejecutará una vez, si pulsamos el botón reset de la Arduino al finalizar la ejecución, descubriremos una grata sorpresa, y es que la función FILE no sobre escribe el archivo si no que sitúa el puntero al final del archivo (si hubiera algo) y partir de ahí comienza la nueva escritura.


Es importante conocer bien todas sus funciones por lo que insto al lector a indagar sobre ellas, 
A continuación os indico algunos links interesantes:

He comprobado que en algunas compilaciones el nombre del archivo esta limitado a ocho caracteres, si indicamos un valor superior el archivo ni se creará, ni obtendremos un mensaje de error, así que no sabremos lo que está sucediendo.
Sin embargo no he encontrado ninguna información al respecto!!!

Además, en todos los tutoriales que he visto por ahí, te hacen incluir la librería SPI (la tarjeta emplea este protocolo) sin embargo con la compilación 1.8.7 (la que uso en estos momentos) no necesito incluirla!!!. En cualquier caso yo la incluyo en el Sketch que os dejo de ejemplo aunque esta comentada.

y por último os indico que en sitios web como AliExpress o Banggood la podemos encontrar por un euro.

domingo, 9 de diciembre de 2018

Veleta con Sensores de efecto Hall 49E

Hasta ahora hemos dedicado tiempo a la preparación, y ha llegado la hora de tratar los elementos con los que construiremos nuestra estación meteorológica.
Esta publicación esta dedicada a la veleta, y debo decir que ha sido lo mas complicado de implementar, tanto para encontrar el sensor adecuado como por su programación.
Después de probar con infinidad de elementos, y tras algunas semanas de trabajo sin mayores complicaciones con el sensor de efecto Hall 49E, he decidido unánimemente que este es el más idóneo.
El sensor de efecto Hall 49E es un sensor analógico, esto significa que lanza una rango de valores que pueden ir de 0 a 1023.
Si lo conectamos a nuestra Arduino como se muestra en la imagen de más abajo, y le acercamos un imán veremos que por su patilla de salida podemos leer el rango de valores descrito anteriormente, en función de la proximidad del campo Norte magnético.


En AliExpress  compré treinta unidades de estos elementos electrónicos por unos 2 Euros.

Por otro lado un día de muchos que dediqué a buscar ideas por la RED para hacer mi veleta, me tope con un post de un Arduinero que había desmontado una veleta comercial para averiguar su sistema, Resultaba que tenia dispuestos dos sensores de efecto hall (un modelo realmente caro) en forma de L y en el centro un imán sujeto al eje de la veleta. Este Arduinero teorizaba acerca de su funcionamiento sin que ofreciera ni solución práctica ni Sketch alguno, pero eso si, me dió suficiente información como para llevarlo a cabo.

La Idea es la siguiente: el sensor dispuesto verticalmente ofrecería los valores de las coordenadas X y el sensor horizontal ofrecería las coordenadas Y. Como es de conocimiento universal en un plano cartesiano, con un valor X y un valor Y obtenemos un vector, ese vector forma un angulo respecto a la vertical y ese angulo es igual al "componente" que necesitamos para determinar la dirección del viento. ¿Es genial verdad?, pues implementarlo me ha llevado un rato.

Espero que la siguiente ilustración aclare algo un poco más lo anteriormente expuesto:



Aviso, como podéis ir imaginando esta entrada será larga de narices...

Ahora esto tenemos que convertirlo en valores útiles, así que vamos a meterle mano al map()
en el lugar apropiado (ya se verá más adelante) de nuestro Sketch; ponemos algo así:

  vectorX=map(sensorX,0,1023,-100,100);
  vectorY=map(sensorY,0,1023,-100,100);


y el map() nos arroja valores tal como se muestran en la siguiente tabla:


Cuadro 1 = 90º cuadro 2 = 180º cuadro 3 = 270º cuadro 4 = 0º
Lectura
Sensor
Valor
Mapeado
Lectura
Sensor
Valor
Mapeado
Lectura
Sensor
Valor
Mapeado
Lectura
Sensor
Valor
Mapeado
X 1023 100 512 0 0 -100 512 0
Y 512 0 0 -100 512 0 1023 100

A continuación una ilustración creada con una hoja de cálculo para las comprobaciones oportunas:
AQUI MISMO el enlace para descargarlo, si alguien tiene problemas que lo diga.



Hasta aquí muy bien, pero hay que darle las fórmulas de triangulación oportunas a nuestra Arduino para la conversión a grados, además la cosa se complica en este punto, puesto que cada cuadrante requiere una fórmula distinta (no es del todo así), para un matemático esto no será complicado, pero este campo no es mi fuerte, además la capacidad de nuestra Arduino esta bastante limitada, con todo esto no me queda otra que aplicar el siguiente principio: " Toda resolución matemática se puede adaptar a una resolución informática" esto ya lo había comentado anteriormente, un programador con una buena base matemática tiene una gran ventaja, y si no la tienes o lo aprendes o adaptas tu programa con las herramientas que te ofrece la programación.

Mi adaptación es la siguiente, creo cuatro cuadrantes en función del valor arrojado, ya mapeado,
 de 0 a 90º Cuadrante 1(C1) En este caso tanto las X como las Y son positivas
de 91 a 180º Cuadrante 2 (C2) Aquí todas las X son positivas y las Y negativas
de 181 a 270º Cuadrante 3(C3) Ahora las X son negativas y las Y también
de 271 a 360º Cuadrante 4 (C4) y por último las X son negativas y las Y positivas

por lo que C1,C2,C3 y C4 las declaro como booleanas y las condiciono según sigue:

if (y >= 0 && x >= 0){c1=true;} // y+ x+
if (y < 0 && x >= 0){c2=true;} // y- x+
if (y < 0 && x < 0){c3=true;} // y- x-
if (y >= 0 && x < 0){c4=true;} // y+ x-


Declaro la formula para el primer cuadrante:

double formula = 180*(double)(atan((double)(x/y))/PI);


y adapto la formula para cada cuadrante:

if (c1){Serial.println(formula);}
if (c2 || c3){Serial.println(180+formula);}
if (c4){Serial.println(360+formula);}


Antes de continuar con el código debemos configurar la veleta físicamente o al menos hacer un prototipo que nos sirva de pruebas.
Los imanes deben ser cilíndricos y perforados en su interior, por donde pasaremos un eje que irá unido al eje de la veleta, deberán girar solidarios, Además los imanes deben tener sus campos magnéticos dispuestos diametralmente NO en sus caras planas.

Yo compré los que muestro en la siguiente imagen en Aliexpress del vendedor que enlazo AQUI MISMO, me costaron 100 unidades unos 13€


¡Ojo que son muy pequeños y su agujero interior es de sólo 2mm.!

Aquí debajo os muestro un prototipo para hacer las mediciones iniciales montado sobre una miniboard:


Como podéis observar la varilla que empleo como eje es de un diámetro inferior, para acabarla de ajustar le puse una funda termo-retráctil.
La distancia que existe entre el imán y los sensores es escasamente de 1 mm.


Y para las pruebas oportunas os adjunto a continuación un Sketch de pruebas, éste nos va a resultar muy útil para determinar varias cosas.



#include<math.h>
boolean c1,c2,c3,c4;
//double YValue,XValue;//si no disponemos de los sensores, descomentar esta linea y sustituir las lineas 13 y 14 por lo comentado
void setup(){
  Serial.begin(9600);
}  
 
void loop(){ 
  c1=false;
  c2=false;
  c3=false;
  c4=false;
  double YValue =analogRead(0);//YValue = random(219, 866);
  double XValue =analogRead(1);//XValue = random(231, 837);
  double y = map(YValue, 219, 866, -100, 100);
  double x = map(XValue, 231, 837, -100, 100);
  if (y >= 0 && x >= 0){c1=true;} // y+ x+
  if (y < 0 && x >= 0 ){c2=true;} // y- x+
  if (y < 0 && x < 0){c3=true;} // y- x-
  if (y >= 0 && x < 0){c4=true;} // y+ x-
   Serial.print("YValue: ");Serial.print(YValue);Serial.print("  Y: ");Serial.println(y);//descomentar estas dos lineas para ver los valores 
   Serial.print("XValue: ");Serial.print(XValue);Serial.print("  X: ");Serial.println(x);//arrojados por el sensor Hall 49E y comentar la siguiente
// descomentar la siguiente linea para ver los valores ya mapeados y comentar las dos anteriores
// Serial.print("X: ");Serial.print(x);Serial.print("  Y: ");Serial.println(y); 
   double formula = 180*(double)(atan((double)(x/y))/PI);
   if (c1){Serial.println(formula);} // imprime grados igual al componente del viento
   if (c2 || c3){Serial.println(180+formula);}// imprime grados igual al componente del viento
   if (c4){Serial.println(360+formula);}// imprime grados igual al componente del viento
   Serial.println();
  delay(200);
}

Observareis que el rango de los valores indicados en el map() no son los ideales (0,1023) que había propuesto en la idea, esto se debe a dos motivos: los valores arrojados por los sensores dependen de la intensidad del imán y de la distancia en que los coloquemos del mismo, además cada sensor arrojara valores similares pero no exactamente los mismos.
De manera que lo primero será leer el rango de valores que nos arroja cada sensor e indicar su máximo y mínimo en el map (y que no tienen por que coincidir con los que yo indico en mi Sketch)

Para ello podemos comentar de la linea 15 a la 30 (desde los map) y descomentar las líneas 21 y 22.
Serial.print("Yvalue: ");.....
Serial.print("Xvalue: ");.....

Con el programa corriendo, el sensorY conectado en A0 y el sensorX en A1, hacer girar el imán sobre su eje y anotar los valores mínimos y máximos de cada uno de ellos; casi es mejor hacerlo uno después del otro comentando la linea de un sensor, e indicar en el map de cada uno de ellos el rango obtenido.

Una vez concluida la fase de pruebas sólo nos queda montar la veleta (físicamente), ¡que rápido se dice, verdad! Bueno os mostraré una imagen de como la tengo yo montada para que os hagáis una idea:


...bueno si, al final le puse un condensador, algún datasheet muestra en el diagrama básico la puesta de un condensador pero no indica característica alguna de éste así que le puse uno de 1uF 50v (el más pequeño que tenía) lo cierto es que funciona bien con o sin él.

Y ya por último quizás nos quede crear el código para trabajar con él de manera definitiva, el broche final de este blog será un código que recoge los valores de todos los sensores, los imprime por consola, por donde Processing los captura muestra y almacena. Pero mientras tanto os dejo uno para el manejo exclusivo de la veleta.
El siguiente código incluye cosas de las que todavía no he hablado en este momento, como el control del tiempo, la impresión de datos a una LCD y el respaldo de datos a una SD, estos temas se tratarán de manera individualizada para su mayor comprensión.
Por otro lado se incluye un sistema visual del componente por cuadrantes a través de leds(¡Ojo! no confundir con los cuadrantes para los sensores).
Para la gestión de la EEPROM y de los datos desde hace bastante tiempo empleo un sistema un tanto particular (que también explicaré) y que requiere cargar un Sketch antes del programa principal, este código la incluiré después del programa principal para el que lo entienda y sepa manejar,

Ahí va el programa principal:



/*  Version con sensores Hall 49E captura la posicion cada 5 minutos y mapping para guardar en EEprom
ESQUEMA DE CONEXIONES
                                          +-----+
              ____[PWR]___________________| USB |__
             |                            +-----+  |
             |         GND/RST2  [ ][ ]            |
             |       MOSI2/SCK2  [ ][ ]  A5/SCL[ ] |<---- SCL del LCD    
             |          5V/MISO2 [ ][ ]  A4/SDA[ ] |<---- SDA del LCD       
             |                             AREF[ ] |
             |                              GND[ ] |
             | [ ]N/C                    SCK/13[ ] |<---- SCK tarjeta SD    
             | [ ]IOREF                 MISO/12[ ] |<---- MISO tarjeta SD   
             | [ ]RST                   MOSI/11[ ]~|<---- MOSI tarjeta SD   
             | [ ]3V3    +---+               10[ ]~|<----- Led Verde, cuadrante PONIENTE (P) de 226º a 315º
             | [ ]5v    -| A |-               9[ ]~|<----- Led Azul, cuadrante NORTE (N) de 316º a 45º
             | [ ]GND   -| R |-               8[ ] |   
             | [ ]GND   -| D |-                    |
             | [ ]Vin   -| U |-               7[ ] |<----- CS tarjeta SD
             |          -| I |-               6[ ]~|<----- Led Naranja, cuadrante LEVANTE (E) de 46º a 135º   
Sensor 0-->  | [ ]A0    -| N |-               5[ ]~|<----- Led rojo, cuadrante SUR (S) de 136º a 225º 
Sensor 1-->  | [ ]A1    -| O |-               4[ ] |   
             | [ ]A2     +---+           INT1/3[ ]~|  
             | [ ]A3                     INT0/2[ ] |   
             | [ ]A4/SDA  RST SCK MISO     TX>1[ ] |   
             | [ ]A5/SCL  [ ] [ ] [ ]      RX<0[ ] |   
             |            [ ] [ ] [ ]              |
             |  UNO_R3    GND MOSI 5V  ____________/
              \_______________________/
     */

#include<math.h>
#include <EEPROM.h>
#include <SD.h>
#include <SPI.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2);//0x3F
boolean c1,c2,c3,c4;
const byte ledRojSur=5;
const byte ledNarLev=6;
const byte ledAzuNor=9;
const byte ledVerPon=10;
boolean traspasado;//ErrorTarjeta, 
int componente;//Veleta
File DatComp,CSComp;
//byte errorTarjeta=EEPROM.read(8);
byte CambioDia=EEPROM.read(7);
int PosVeleta=EEPROM.read(9);
byte PosCtrl_V=EEPROM.read(10);
byte dia=EEPROM.read(2);
byte mes=EEPROM.read(3);
byte hora=EEPROM.read(4);
byte minuto=EEPROM.read(5);
byte segundo=EEPROM.read(6);
byte resto=0;
byte multiplo=5;
unsigned long newMilli;
byte Mes[12]={31,28,31,30,31,30,31,31,30,31,30,31};

void setup(){   
  Serial.begin(9600);//Inicializamos el puerto serie. Serial.begin(115200);
//  Serial.print(EEPROM.read(4));Serial.print(":");Serial.print(EEPROM.read(5));
//  Serial.print(" del " );Serial.print(EEPROM.read(2));Serial.print("/");Serial.println(EEPROM.read(3));
  if(PosCtrl_V==0){PosVeleta=EEPROM.read(9);} // recupera la 
  if(PosCtrl_V==1){PosVeleta=(EEPROM.read(9)+256);} // posicion de registros en funcion del 
  //Serial.print("PosVeleta: ");Serial.print(PosVeleta); Serial.println("...Debe ser 11");
  pinMode(ledRojSur, OUTPUT); // Pin 5 Veleta
  pinMode(ledNarLev, OUTPUT); // Pin 6 Veleta
  pinMode(ledAzuNor, OUTPUT); // Pin 9 Veleta
  pinMode(ledVerPon, OUTPUT); // Pin 10 Veleta
  //------------------------------------------------------------------------------------LCD
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0,0);lcd.print("Iniciando...");delay(300);lcd.clear();
  //------------------------------------------------------------------------------------
  InitSD();
}
void loop(){ 

  newMilli=millis()/996.5; //  con 996.2 se adelanta
  while(newMilli+1>millis()/996.5){};// se inicia  seg atrasado
  segundo++;
  
  componente=calculaGrados();
  
  if((componente >= 0 && componente <= 45) || (componente > 315 && componente <= 360)){digitalWrite(ledAzuNor,HIGH);digitalWrite(ledNarLev,LOW);digitalWrite(ledRojSur,LOW);digitalWrite(ledVerPon,LOW);}
  if(componente > 45 && componente <= 135){digitalWrite(ledAzuNor,LOW);digitalWrite(ledNarLev,HIGH);digitalWrite(ledRojSur,LOW);digitalWrite(ledVerPon,LOW);}
  if(componente > 135 && componente <= 225){digitalWrite(ledAzuNor,LOW);digitalWrite(ledNarLev,LOW);digitalWrite(ledRojSur,HIGH);digitalWrite(ledVerPon,LOW);}
  if(componente > 225 && componente <= 315){digitalWrite(ledAzuNor,LOW);digitalWrite(ledNarLev,LOW);digitalWrite(ledRojSur,LOW);digitalWrite(ledVerPon,HIGH);}
  if(componente > 360){digitalWrite(ledAzuNor,HIGH);digitalWrite(ledNarLev,HIGH);digitalWrite(ledRojSur,HIGH);digitalWrite(ledVerPon,HIGH);}//digitalWrite(alarma,HIGH); 
  
  if (segundo == 1 && resto==0){
         lcd.clear();lcd.setCursor(0,0);lcd.print("Grabando: ");lcd.print(componente);
         lcd.setCursor(0,1);lcd.print("en Posicion: ");lcd.print(PosVeleta);delay(500);lcd.clear(); 
         if (PosVeleta <= 255){EEPROM.write(10,0);EEPROM.write(9,PosVeleta);}// guarda en PosCtrl_V; EEPROM(10) el numero
         if (PosVeleta > 255 && PosVeleta <= 511){EEPROM.write(10,1);EEPROM.write(9,PosVeleta);}// en giro de bytes que dara       
         byte x = map(componente, 1, 360, 1, 255);// convierte el valor(componente)a un byte para poder guardarlo en la EEprom
         EEPROM.write(PosVeleta,x);PosVeleta++;
  }
  
  if (segundo > 59){segundo=0;EEPROM.write(6,segundo);minuto++;EEPROM.write(5,minuto);}
  if (minuto > 59){minuto=0;EEPROM.write(5,minuto);
      if (hora < 23){hora++;EEPROM.write(4,hora);
        }else{CambioDia=2;EEPROM.write(7,2);hora=0;EEPROM.write(4,hora);dia++;EEPROM.write(2,dia); 
            for(int i=11;i<=299;i++){EEPROM.write(i+289,EEPROM.read(i));delay(2);} // hace CS de los registros del dia en la misma EEprom    
            InitSD();
            if (CambioDia==2){ 
               traspasado=Traspas_SD();
               EEPROM.write(1023,traspasado);                 
               CSComp=SD.open("CSComp", FILE_WRITE);
               for(int i=300;i<=588;i++){CSComp.println(EEPROM.read(i));delay(2);}
               CSComp.close(); 
               PosVeleta=11;EEPROM.write(9,PosVeleta);
               PosCtrl_V=0;EEPROM.write(10,PosCtrl_V);   
               CambioDia=1;EEPROM.write(7,1);
           }         
      }
  }
 resto=minuto%multiplo;
//---------------------------------------IMPRESION LCD    
 lcd.setCursor(0,0);lcd.clear();if (hora<10){lcd.print("0");}lcd.print(hora);lcd.print(":");if(minuto<10){lcd.print("0");}lcd.print(minuto);lcd.print(":");
 if (segundo<10){lcd.print("0");}lcd.print(segundo);lcd.print(" ");
 lcd.setCursor(11,0);if(dia<10){lcd.print("0");}lcd.print(dia);lcd.print("/");if(mes<10){lcd.print("0");}lcd.print(mes);
 lcd.setCursor(0,1);lcd.print("Componente: ");lcd.print(componente);
//---------------------------------------------

Serial.println(componente);

 if (mes!=EEPROM.read(3)){EEPROM.write(3,mes);}
 if (dia > Mes[mes-1]){dia=1;mes++;EEPROM.write(2,dia);EEPROM.write(3,mes);}
 if (mes > 12 ){mes=1;EEPROM.write(3, mes);}   
}//------------------------------------------------------------------------------------------------------------ cierra LOOP

void InitSD(){
   if (!SD.begin(7)){
      lcd.setCursor(0,0);lcd.print("SD NO conectada");delay(300);lcd.clear();
   }else{lcd.setCursor(0,0);lcd.print("SD en Conexion");delay(300);lcd.clear();} 
  if(!SD.exists("DtComp")){ 
      lcd.setCursor(0,0);lcd.print("Error Lectura SD");delay(400);lcd.clear();
  }else{lcd.setCursor(0,0);lcd.print("Componente existe ");delay(700);lcd.clear();} //   Serial.println("Componente existe ");
}//cierra funcion InitSD

boolean Traspas_SD(){
   InitSD();
   DatComp = SD.open("DtComp",FILE_WRITE);
   for(int i=11;i<=299;i++){
      int x = map(EEPROM.read(i), 1, 255, 1, 360);// convierte el valor(componente) guardado en la EEprom(como Byte) a Int
      DatComp.println(x);delay(2);
   }
   boolean z=SD.exists("DtComp");
   DatComp.close();
   return z;
}//cierra funcion Traspas_SD

int calculaGrados (){ // funcion denominada calculaGrados(), esta funcion determina que potenciometro debe emplear y devuelve su valor.
   c1=false;
   c2=false;
   c3=false;
   c4=false;
   
   double YValue =analogRead(0);
   double XValue =analogRead(1);

   double x = map(XValue, 231, 837, -100, 100);//XValue, 250, 766, -100, 100
   double y = map(YValue, 219, 866, -100, 100);//YValue, 197, 866, -100, 100
  
   if (y >= 0 &&  x >= 0){c1=true;} // y+ x+
   if (y < 0  &&  x >= 0){c2=true;} // y- x+
   if (y < 0  &&  x < 0 ){c3=true;} // y- x-
   if (y >= 0 &&  x < 0) {c4=true;} // y+ x-
  
   double formula = 180*(double)(atan((double)(x/y))/PI);
   
   if (c1){return formula;}
   if (c2 || c3){return (180+formula);
   } else { return (360+formula);}
} // Cierra funcion 

y a continuación os dejo el código para que el programa principal gestione correctamente los datos y la EEPROM.
Recuerdo que el siguiente código debe cargarse antes que el programa principal, en definitiva hay que indicarle hora, fecha y el día juliano, que es 0 para el 1 de enero y 365 para el 31 de diciembre.
PosVeleta, es la variable que almacena la posición de la EEPROM donde debe guardarse el siguiente registro.
PosCtrl_V, es una variable auxiliar para PosVeleta, ésta última se guarda en la EEPROM, cuando el valor de PosVeleta supera el byte,  PosCtrl_V suma uno, y el programa principal determina la posición donde guardar el siguiente registro sumando 255 al valor de PosVeleta.
Si la Arduino se reinicia por algún motivo la posición queda guardada en la EEPROM, pero si el tiempo de parada es elevado habrá que actualizar la hora o minuto y en consecuencia los valores de PosVeleta y PosCtrl_V en su caso, lógicamente cada minuto del día esta asociado a una posición concreta de PosVeleta, este dato será necesario conocerlo para indicárselo.

Sketch previo al programa principal:



// PROGRAMA PREVIO AL PRINCIPAL PARA LA VELETA CON SENSOR HALL 49E
#include <EEPROM.h> // sentecia para EEPROM
int PosVeleta=0;
int PosAnem=0;
void setup() {
Serial.begin(9600);
// *********************************************** BORRADO/ESCRITURA DE DATOS
//  EEPROM.write(0,220);// Jul0
//  EEPROM.write(1,0);// Jul1
  EEPROM.write(2,29);// dia
  EEPROM.write(3,7);// mes
  EEPROM.write(4,10);// hora
  EEPROM.write(5,38);// minuto
  EEPROM.write(6,0);// seg
  EEPROM.write(7,1);// cambioDia
//  EEPROM.write(9,138);// PosVeleta
//  EEPROM.write(10,0);// PosCtrl_V
/*
 for (int i=11;i<=299;i++){ // registro veleta
   EEPROM.write(i,0);
 }
  for (int i=300;i<=588;i++){ // CS registros
   EEPROM.write(i,0);
 }
*/
// *****************************************************************
// ----------------------------------------------------------------- LECTURA
Serial.print("Ultimo Registro a las " );Serial.print(EEPROM.read(4));Serial.print(":");Serial.print(EEPROM.read(5));
Serial.print(" del " );Serial.print(EEPROM.read(2));Serial.print("/");Serial.println(EEPROM.read(3));
//Serial.print("Juliano: " );Serial.println(EEPROM.read(0)+EEPROM.read(1));
Serial.print("CambioDia: "  );Serial.println(EEPROM.read(7));
Serial.print("Error Tarjeta: " );Serial.println(EEPROM.read(8));
Serial.print("Pos Eprom: " );Serial.println(EEPROM.read(9));
Serial.print("PosCtrl: " );Serial.println(EEPROM.read(10));
if(!EEPROM.read(10)){PosVeleta=EEPROM.read(9);} // recupera la posicion del ultimo 
if(EEPROM.read(10)){PosVeleta=(EEPROM.read(9)+255);} //  registro en funcion del valor de PosCtrl (EEPROM (10))
Serial.print("Pos_Veleta: " );Serial.println(EEPROM.read(9));
Serial.print("Valor CambioDia: " );Serial.println(EEPROM.read(1024));
Serial.print("Valor Traspasado: " );Serial.println(EEPROM.read(1023));
/*
Serial.println("Lectura registros Veleta:");
for(int i=11;i<=299;i++){
  Serial.println(EEPROM.read(i));
}
Serial.println("Lectura registros CopiaSeguridad:");
for(int i=300;i<=588;i++){
  Serial.println(EEPROM.read(i));
}
Serial.println("Lectura Indiscriminada:");
for (int i=0;i<=1024;i++){
  Serial.println (EEPROM.read(i));
}
*/
// -------------------------------------------------------

}// CIERRA VOID

void loop() {
}


y con esto y un bizcocho ayer fue día veintiocho.