[Solucionado] Problemas con comunicación serial y almacenamiento de datos en SD

Buenas tardes intento guardar los datos de unos sensores que obtengo en un arduino Uno y despues se los envio a un arduino Mega para guardarlos en la una memoria SD, ésta se encuentra en el SHIELD de spark fun, sin embargo al momento de guardar los datos en la SD tengo problemas no puedo guardarlos correctamente ya que pareciera que se sobre escribe los valores, utilizo la función millis para hacer un delay de la lectura, si este delay es grande guarda los datos correctamenta pero si el dalay es menor se sobre escriben y quiero tener un t_delay de 10 milisengudos.
Es posible?
Codigo para el arduino UNO, el que envía

String dataString;
unsigned long tiempo=0;
 unsigned long t_Actualizado=0;
unsigned  long t_delay = 250;
String string;
void setup()
{
  // Open serial communications and wait for port to open:
  Serial.begin(9600);

  // see if the card is present and can be initialized:

  Serial.println("card initialized.");
}

void loop()
{
dataString="";
 tiempo=millis();
   
     
  // read three sensors and append to the string:
  for (int analogPin = 0; analogPin < 3; analogPin++) {
    int sensor = analogRead(analogPin);
    dataString += String(sensor);
    if (analogPin < 2) {
      dataString += ",";
    }
  }

if (tiempo> t_Actualizado+ t_delay)
{
t_Actualizado=tiempo;

    Serial.println(dataString);          
  }
  
  }

Código en arduino MEGA

#include <SPI.h>

#include <SD.h>

char inChar;
String string;
// Chip Select pin is tied to pin 9 on the SparkFun SD Card Shield
const int chipSelect = 9;  




void setup() {
 Serial.begin(9600);
  Serial3.begin(9600);
  string.reserve(1200);
   Serial.print("Initializing SD card...");
  // make sure that the default chip select pin is set to
  // output, even if you don't use it:
  
  pinMode(chipSelect, OUTPUT);
  

  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");

}

void loop() {
    string="";
  
   if (Serial3.available()){
File dataFile = SD.open("datas2.TXT", FILE_WRITE);
//Lectura de caracteres   
   inChar = Serial3.read();
   
//Suma de caracteres en variable string
string+=inChar;

    Serial.print(string);
  
    dataFile.print(string);
       
    Serial3.flush();// 
//
     
 dataFile.close();
      
     }
    
     
}

Agradeceria que me pudiera ayudar porque

Quiza deberias adaptar el delay a lo que necesite el mega en recibir la cadena y guardarla ,los 10 ms que dices me parecen pocos ,no se que sensores tienes ,pero es necesaria tanta frecuencia de lectura? Piensa en la cantidad de datos que estas grabando a una grabacion cada 10 ms…podrias intentar que fuera el mega el que solicitara los datos al uno una vez que ha ha guardado los datos recibido.

en realidad le estas diciendo que se sobreescriba el archivo.
Debes abrir el archivo y posicionarte al final haciendo println.
Ademas que deberias recibir toda la cadena y despues guardarla, no caracter a caracter. Porque el tiempo de apertura, cierre y escritura del archivo te lleva mas tiempo de 10ms.

La frecuencia la necesito a 10 ms, y claro pero aun no comprendo, seguire investigando o si alguién más pudiera aportar algo sería de gran ayuda

crea un buffer de algunos 100 o 200 caracteres y luego los almacenas todos juntos.
abre el archivo y no lo cierres hasta almenos una 10 mas veces, y lo vuelves a abrir para seguir grabando

Hola.
Creo que tu código para el mega tiene un par de problemillas.
Tal y como lo tienes ahora, está abriendo, escribiendo y cerrando el archivo por cada carácter recibido por serial3. Esto significa una lectura y escritura en sd de (creo recordar) 512 byte cada vez. Por otra parte, cada vez que abres el archivo con la opción FILE_WRITE no estoy muy seguro, pero creo que el índice del fichero queda al principio del mismo, con lo que la subsiguiente escritura sobrescribe lo que ya pudiera existir.
Si abres el archivo en el setup y no lo cierras, tras cada escritura, se deberían escribir en SD correctamente los datos. Prueba a ver y cuenta.

Hola que tal, ya hice lo que me suguirio noter, sin embargo al abrir el archivo en el setup, y cerrarlo en el void loop ya no me guarda nada,

Y si tienen razon noter, el problema es con la escritura en la SD cuando empieza a guardar los datos se empiezan a sobrescribir o algunos datos ya no se guardan. aun no puedo solucionarlo

Abre en el setup, pero no cierres en loop, sino que puedes hacer un flush al final del mismo para que escriba en la Sd el contenido del buffer.
Cuando abras el archivo en setup, a continuación mueve el puntero al final, para que agregue datos, en lugar de sobreescribir desde el principio.

datafile.seek(datafile.size());

Le hice la siguiente modificación al código.

#include <SPI.h>

#include <SD.h>

char inChar;
String string;
// Chip Select pin is tied to pin 9 on the SparkFun SD Card Shield
const int chipSelect = 9; 




void setup() {
 Serial.begin(9600);
  Serial3.begin(9600);
  string.reserve(1200);
   Serial.print("Initializing SD card...");
  // make sure that the default chip select pin is set to
  // output, even if you don't use it:
 
  pinMode(chipSelect, OUTPUT);
 

  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");
File dataFile = SD.open("datas2.TXT", FILE_WRITE);
dataFile.seek(dataFile.size());


}

void loop() {
    string="";
 
   if (Serial3.available()){
//Lectura de caracteres   
   inChar = Serial3.read();
   
//Suma de caracteres en variable string
string+=inChar;

    Serial.print(string);
 
    dataFile.print(string);
    Serial.Flush();
       
    Serial3.flush();//
//
     

     
     }
   
     
}

Pero no guarda nada en la SD, noter podrías decirme que error hay en el código o alguien más.

Gracias

Hola.
Declaras dataFile como variable local en setup, con lo que cuando llegas al loop ya no existe. Debes declararla como global e inicializarla en el setup.
Por otro lado, con lo de flush, me refería, no al Serial, sino al dataFile. Normalmente, cuando escribimos en un File, no se hace inmediatamente a la tarjeta, sino a un buffer. Cuando cerramos el archivo, llenamos el buffer, o éste necesita cargar datos de otro archivo u otra parte de archivo, es cuando se escribe el bloque completo (creo que eran 512 bytes). Por ello, si apagamos el arduino sin haber cerrado el archivo, existe el riesgo de que las escrituras no se hayan hecho a la tarjeta. Creo recordar, sin embargo, que dataFile.print también fuerza la escritura inmediata en SD. Compruébalo con este código a ver:

#include <SPI.h>

#include <SD.h>

char inChar;
File dataFile;
const int chipSelect = 9;




void setup() {
	Serial.begin(9600);
	Serial3.begin(9600);
	Serial.print("Initializing SD card...");
  // make sure that the default chip select pin is set to
  // output, even if you don't use it:

  pinMode(chipSelect, OUTPUT);


  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
  	Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
}
Serial.println("card initialized.");
dataFile = SD.open("datas2.TXT", FILE_WRITE);
dataFile.seek(dataFile.size());


}

void loop() {
	if (Serial3.available()){
		inChar = Serial3.read();
		Serial.print(inChar);
		dataFile.print(inChar);
	}
}

La pega es que si realmente print hace volcado a sd, este código sería ineficiente, porque por cada carácter se escribiría el bloque de 512 bytes completo. En tu código anterior usabas un string, intuyo que para recibir varios caracteres y escribirlos en un solo print, aunque tal como lo tenías también hacía print carácter a carácter.

Utilizando file.write en vez de file.print, creo que no se escribe inmediatamente al archivo, pero sería conveniente que “en los ratos libres” forcemos esa escritura para evitar que un apagado de arduino mande los datos del buffer por el sumidero. Para ello usamos File.flush().
Prueba a ver este otro código y me dices si funcionan ambos y si uno va mejor que el otro.

#include <SPI.h>

#include <SD.h>

char inChar;
File dataFile;
int charsToWrite=0;
// Chip Select pin is tied to pin 9 on the SparkFun SD Card Shield
const int chipSelect = 9;




void setup() {
	Serial.begin(9600);
	Serial3.begin(9600);
	Serial.print("Initializing SD card...");
  // make sure that the default chip select pin is set to
  // output, even if you don't use it:

  pinMode(chipSelect, OUTPUT);


  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
  	Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
}
Serial.println("card initialized.");
dataFile = SD.open("datas2.TXT", FILE_WRITE);
dataFile.seek(dataFile.size());


}

void loop() {
	if (Serial3.available()){
		inChar = Serial3.read();
		Serial.write(inChar);
		dataFile.write(inChar);
		charsToWrite++;
	}
	else if (charsToWrite>0) {
		dataFile.flush();
		charsToWrite=0;
	}
}

En este último código, en teoría, mientras se reciben datos por Serial3 consecutivamente se escriben en buffer, y si dejan de llegar, aprovechamos para ver si hay datos por escribir y hacemos un flush.

Gracias Noter, funciona tu código