modulo microsd leer y escribir una linea especifica.

Hola foreros, queria consultarles cual seria la mejor forma de hacer lo sigueinte, encontre en la red un tuto con un codigo de un velocimetro para auto le hice algnas modificaciones para adaptarlo a mi gusto y ademas de medir la velocidad mide la disancia recorrida y me interesa que cuando apague el auto y vuelva a encenderlo la distancia recorrida se guarde asi funcionaria como un odometro, ahora mi duda en cuestion es como hacerlo y que en el proycto esta persona lee y almacena estos datos en la eeprom de arduino y yo quiero hacerlo en una sd, alguien podria orientarme?

a continuacion les dejo el codigo.

#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>
 
LiquidCrystal_I2C  lcd(0x3F,2,1,0,4,5,6,7);


volatile static double pulse_distance = 0.000155;

volatile double traveled_distance, display_traveled_distance;
volatile unsigned long counter, avg_speed_divider, dist_pulse_count, temp_dist_pulse_count , all_speed_values;
volatile unsigned int speed, display_speed , avg_speed, max_speed = 0, fccounter;

void setup() {
  
   lcd.begin (16,2);
   lcd.setBacklightPin(3,POSITIVE);
   lcd.setBacklight(HIGH);
   lcd.setCursor(5,0);
   lcd.print("Daewoo");
   lcd.setCursor(5,1);
   lcd.print("Espero");
   delay(2500);
   lcd.clear();
   

noInterrupts();


TCCR1A = 0;
TCCR1B |= ((1 << CS10) | (1 << CS11));
TIMSK1 |= (1 << TOIE1);
TCNT1 = 3036;

pinMode(2, INPUT);

attachInterrupt(digitalPinToInterrupt(0), distance_count, FALLING);

interrupts();

}

void loop() {

if(millis()%500 ==0){

lcd.setCursor(0,0);
lcd.print("Km:");
lcd.setCursor(4,0);
lcd.print(display_traveled_distance);

lcd.setCursor(0,1);
lcd.print("KM/H:");
lcd.setCursor(6,1);
lcd.print(display_speed);

lcd.setCursor(10,1);
lcd.print("M:");
lcd.setCursor(13,1);
lcd.print(max_speed);
}

}



ISR(TIMER1_OVF_vect) {
counter++;

if(counter>3){

  currentSpeed();

  if(speed > 3){
    avg_speed_divider++;
    avgSpeed();
    maxSpeed();    
    }
  
  dist_pulse_count = 0;  
  counter = 0;
  display_traveled_distance = traveled_distance;
  display_speed = speed;
}
TCNT1 = 3036;
}

void distance_count(){
  dist_pulse_count++;
  traveled_distance += pulse_distance;
  temp_dist_pulse_count++;
}

void currentSpeed(){
  if(speed == 0 && dist_pulse_count > 23){
    
    traveled_distance -= pulse_distance + dist_pulse_count;
    dist_pulse_count = 0;
    
    }
  
  
  speed = pulse_distance * dist_pulse_count * 3600;
  
  }

void maxSpeed(){
  if(speed > max_speed) max_speed = speed;
}

 void avgSpeed(){
  all_speed_values += speed;
  avg_speed = all_speed_values / avg_speed_divider;
 }

PD: estube probando siguiendo los ejemplos de la libreria pero no e me dio muy bien jaja.

de antemano gracias y saludos, espero sus respuestas.

A ver si entendí: la tarjeta SD es para hacer las veces de EEPROM, guardando el traveled_distance; ¿o cómo es?

Y la otra es: ¿Debe ser legible para el ser humano o es exclusivamente para guardar datos?

En el ejemplo que encontraste hay 0 llamado a la SD. El dato que mencionas y quieres guardar también podrias guardarlo en EEPROM ahorrándote la SD que me parece demasiado para algo tan simple como guardar la distancia recorrida. De todos modos tu Arduino no se apagará jamás a menos que se desconecte la batería en cuyo único caso si deberías guardar el dato que no quieres perder. Solo ahi cuando detectes que la tensión cae, tendrias que guardarlo y no permanentemente. Otra manera es solo saber si el auto esta encendido o no, y guardar cuando cambie a apagado o detenido.

Para aconsejarte sobre la SD lo dejo a Lucario.

hola, gracias por las respuestas, en mi caso preferiria que fuera legible para una persona a travez del lcd, lo que quiero que lea y guarde justamente es la variable traveled_distance, y con respecto a lo de que no hay nada referente a la eeprom es por que lo he sacado del codigo si lo quieren completo dejo adjunto el link del tutorial en youtube.

a todo esto lo de no hacerlo en la eeprom, es mas por una cuestion de aprender algo que me sirva a futuros proyectos, usar la eeprom es simplemente hacer un copy paste del codigo que ofrecen el tutorial y me parecio interesante añadir una sd para aprender a usar el modulo y una vez que le agarre la mano usarla para almacenar otro tipo de datos, sensores de temperatura de agua, aire de admision, lecturas del sensor de vacio etc.

Aparte arduino se enciende junto con el contacto del auto no esta conectado directamente a la bateria.

saludos y muchas gracias por su atencion.

Luchete: hola, gracias por las respuestas, en mi caso preferiria que fuera legible para una persona a travez del lcd

A través del LCD siempre será legible, mi pregunta era al momento de almacenar: si tenía que ser como texto (legible) o binario (ilegible). Para almacenar un dato en un archivo de SD, y que sea fácil de sobrescribir, yo optaría por la forma binaria. Míralo así: como texto, la longitud puede variar según la cantidad de dígitos; en cambio como binario, la longitud es constante sin importar el valor que represente. En AVR, double viene siendo lo mismo que float, en forma binaria siempre ocupará 4 bytes.

Asumo que no lo quieres guardar en la EEPROM porque ya sabes cómo (a pesar de que se pueda prescindir de una tarjeta SD para lograr el mismo objetivo; y que con 1024 bytes en realidad se puede almacenar bastante información); entonces para realizarlo en una tarjeta SD, se procedería a un método poco usual (de hecho, hasta el momento no he visto tutoriales que muestren lo que yo haré a continuación):

void guardarOdom() {
  File f = SD.open("Odom.dat", FILE_WRITE);
  if (f) {
    f.seek(0); // Para garantizarnos que sobrescriba el dato en vez de hacer crecer el archivo.
    f.write((byte*)&traveled_distance, sizeof(double)); // Esta es la parte interesante. Escribe a la variable como si fueran un conjunto de bytes, de ahí que se le llame "forma binaria".
    f.close();
  }
}

Este es para escribir (guardar) a la SD.

void recuperarOdom() {
  if (!SD.exists("Odom.dat")) {
    // Hacer algo en caso de que el archivo del odómetro no exista.
  } else {
    File f = SD.open("Odom.dat");
    while (!f) f = SD.open("Odom.dat"); // El programa se bloquea hasta que logre abrir el archivo

    f.readBytes((byte*)&traveled_distance, sizeof(double)); // La parte interesante. Lee como si fueran bytes, pero efectivamente recupera el valor guardado.
    f.close();
  }
}

Este es para leer (recuperar) de la SD.

Al menos así es como pienso yo que debería, no sé si así te servirá... ::)

Y la otra es: ¿Debe ser legible para el ser humano o es exclusivamente para guardar datos?

cuando decías eso no entendía a que te referías, ahora si.

ahora te consulto 3 cosas mas y creo que estoy listo para empezar tranqui:

acá lo que haces seria una conversión de datos para que escriba en forma binaria lo que lee en tipo "double"???

f.write((byte*)&traveled_distance, sizeof(double));

Lo segundo que te quería consultar en caso de que el archivo "odom.dat" estuviese vació o sea cuando lo cargo en la sd por primera vez leeria un dato tipo 0? no? o sea no habría inconveniente?

y lo ultimo si quisiera darle un punto de inicio como decir ya tiene 200km recorridos, seria posible hacerlo?

Luchete:
acá lo que haces seria una conversión de datos para que escriba en forma binaria lo que lee en tipo “double”???

f.write((byte*)&traveled_distance, sizeof(double));

Correcto. Para mayor comprensión de lo que sucede aquí, tendrías que estudiar sobre los famosos punteros de memoria y lo que documentan sobre la función que acabo de usar.
sizeof() también está documentado.

Luchete:
Lo segundo que te quería consultar en caso de que el archivo “odom.dat” estuviese vació o sea cuando lo cargo en la sd por primera vez leeria un dato tipo 0? no? o sea no habría inconveniente?

Ahora que lo mencionas: si el archivo estuviera vacío, pues simplemente no alteraría la variable; si el valor era cero antes de intentar leer, entonces en cero se quedaría.

Si te preocupa una situación como esa, la podríamos verificar de la siguiente manera:

void recuperarOdom() {
  if (!SD.exists("Odom.dat")) {
    // Hacer algo en caso de que el archivo del odómetro no exista.
  } else {
    File f = SD.open("Odom.dat");
    while (!f) f = SD.open("Odom.dat"); // El programa se bloquea hasta que logre abrir el archivo
    if (f.available() < 4) {
      // Aquí es donde se verifica. La condición se cumple si hay menos de 4 bytes en el archivo (y lógicamente también se cumple si estuviera vacío).
      // Cabe destacar que si el archivo contiene 4 bytes con el valor cero, la condición no se cumple.

      // Aquí hacer algo en caso de que el archivo no tenga el tamaño suficiente.
    } else {
    f.readBytes((byte*)&traveled_distance, sizeof(double)); // La parte interesante. Lee como si fueran bytes, pero efectivamente recupera el valor guardado.
    }
    f.close();
  }
}

Luchete:
y lo ultimo si quisiera darle un punto de inicio como decir ya tiene 200km recorridos, seria posible hacerlo?

Tendrías que crear el archivo por otro medio externo al Arduino. Como lo recupera en forma binaria, en forma binaria hay que escribirla; de manera práctica eso sería posible solo con un editor hexadecimal.
Si crees que eso no es lo tuyo, introduce a la tarjeta el archivo contenido en el zip que acabo de adjuntar (esperando que el codificado que utilicé sea compatible, y que recupere 200.0 tal y como lo pediste ::slight_smile: ).

Odom.zip (118 Bytes)

Muchas Gracias Lucario ahora me toca a mi sentarme a leer un poco, apenas termine de modificar el código y ver si no meto la pata en algo mas jaja ni bien me funcione o no vuelvo a escribir y gracias de nuevo por la explicación y el tiempo. :) :) :) :)