ayuda para lectura de tarjeta microsd linea a linea funciona pero parcialmente

hola.
quisiera saber si alguien me puede ayudar con esta duda, tengo una memoria microsd con los siguientes datos
( son 300 lineas ), el codigo que uso para leer cada linea es el que adjunto.
leo desde la tarjeta de memoria y guardo en una variable string PERO solo me guarda hasta la linea 6 ( no es problema de
tarjeta de memoria , ni arduino, ya probe)

¿sera algo relacionado con el buffer del uno ?.
¿con el SPI ?.
¿ alguien tiene un codigo que algo lo mismo pero mas eficiente ?.

nunca me lee mas de 6 lineas, hasta esa cantidad todo bien.

ojala puedan ayudarme ya que mis conocimientos son pocos sobre el arduino, recien empiezo.

la lineas en la tarjeta de memoria microsd tienen el siguiente formato

leeme.txt

0:03;12345678,30
0:04;87654321,05
1:05;77777777,19

codigo usado para leer

#include <SD.h>
  String mistring[10];
  String pedido[10];
  String simcard[10];
  String fono[10];
  String estado[10];
  String valor_actual = "99";
  int j;
  int i;
  char Ruta[10] = {'l', 'e', 'e', 'm','e', '.', 't', 'x', 't', '\0'};
  void setup()
  {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
  ; // Espera para conexion puerto serie, solo necesario para leonardo
  }
  Serial.print("Iniciando SD...");
  pinMode(10, OUTPUT);
  if (!SD.begin(4)) {
  Serial.println("Error inicializar SD!");
  return;
  }
  Serial.println("SD iniciada correctamente.");
  // aqui va la ruta
  //Leemos linea de archivo en la SD
  //String Lin = ReadFile(3,Ruta);
  
  }
  void loop()
  {
    for (int i= 0; i<=10; i++)
{
mistring[i] = ReadFile(i,Ruta);
estado[i] = mistring[i].substring( 0,1);
int dcPos = mistring[i].indexOf( ":" );
simcard[i] = mistring[i].substring( dcPos+1,dcPos+3 );
int dPos = mistring[i].indexOf( ";" );
fono[i] = mistring[i].substring( dPos+1,dPos+9 );
int cPos = mistring[i].indexOf( "," );
pedido[i] = mistring[i].substring( cPos+1,cPos+4 );
delay(500);
Serial.println( fono[i] );
//if ( valor_actual == pedido[i] ) {
//Serial.println(fono[i] );
//}  
}  
  // no hacer nada
}
//String Lin = ReadFile(j,Ruta);  
  //Funcion para leer linea de un archivo de la sd
  //Primer parametro numero de linea
  //Segundo Parametro ruta del fichero

  
 String ReadFile(int Linea,char Ruta[]){
    
  int Lin=0;
  String Resultado;
  File myFile;
  byte Bin;
  myFile = SD.open(Ruta);
  if (myFile) {
  while (myFile.available()) 
  {
  Bin=myFile.read();
  if (Bin==13)
  {
  Lin++;
  myFile.read();
  }
  else
  {
  if (Lin==Linea){
  Resultado=Resultado+(char(Bin));
  
  }
  //Serial.println(Resultado);
  if (Lin>Linea)
  {
  myFile.close();
  //ProcessSms(Resultado);
  return Resultado;
  }
  }
  }
  myFile.close();
  }
  else {return"NOFILE!!";}
 }

Hola, la verdad no soy muy experto en SD, pero hace poco tuve un problema similar en otra aplicacion;

Me recomendaron que "ensamblara" el texto en un char

mis datos [] = ( 1,2,3,4, %4, %4, %4,%4, var1, var,2, var3, var4); Luego lo imprimes con prinft creo..

Lo que pasa es que el buffer no es rapido para abrir y cerrar el archivo, asi que ensamblas todo en una linea, y lo imprimes una sola vez.

otra cosa que me paso a mi es que se agotaba la memoria ram Puedes revisarla usando una librería; MemoryFree

Te dice en cada loop cuanta memoria te queda, a veces algun bug se la come.

Bueno espero te sirva de algo. Saludos.

-Alex.

hola , modifique programa y le agregue codigo para ver la sram libre me sale 564 ( ver imagen adjunta ) por lo tanto asumo que no es falta de memoria , incluso ahora puedo ver mas lineas de la SD (15 lineas ),

¿ se puede modificar algo del buffer para el SPI ?. gracias

analisis de lectura de microsd.png

Hola. Tiene toda la pinta de falta de memoria. Seguramente que los string consumen rápidamente la memoria disponible (muéstrala en cada ciclo de for, no sólo al principio, y casi seguro que es lo que está pasando). ¿Qué estás intentando hacer?

hola, puse el codigo para ver la sram disponible y cuando empieza a fallar la lectura marca 300, se ve en la imagen.

lo que intento hacer es leer desde la tarjeta sd todos los mensajes almacenados y colocar en array de string

por ejemplo una linea en la microsd tiene el formato

0:01;84465908,10

quiero leer y dejar asi

bool valor1 ← 0 ( primer caracter )

String valor2 ← 01 ( caracteres entre . y ; )

String valor3 ← 84465908 ( caracteres entre ; y , )

pero solo logro leer hasta la linea 15 de la microsd, si uso un arduino mega puedeo leer hasta la 51

si alguien puede darme alguna informacion para solucionar el problema lo agradezco

solo quedaria pensar que no es tan rapido como para abrir y cerrar el archivo, si uso el codigo de ejemplo que trae arduino puedo leer la memoria microsd totalmente, pero solo poniendo el codigo en el setup me funciono.

pero solo logro leer hasta la linea 15 de la microsd, si uso un arduino mega puedeo leer hasta la 51

Por lo que veo, parece casi seguro que es problema de memoria. Lamentablemente es de los recursos más escasos que tiene el arduino, así que hay que cuidar mucho su uso, y el uso de String consume bastante. ¿Es imprescindible tener todos los datos a la vez en memoria? ¿Qué deseas hacer con los datos? ¿Acaso es un proyecto top secret? (Es frustrante tener que sacar la información con pinzas :cold_sweat: )

hola NOTER.

no hay problema en contar de que se trata, en absoluto y tampoco en mostrar el codigo que uso para el SIM 900, ahi vamos.

trabajo en una minera norte de chile ( lo mio son la automatizacion con PLC), quiero ayudar a unas personas que viven en un pueblo con muy poca agua, la idea es que pidan agua por sms y les llegue a las plantaciones ( suena extraño pero hay razones tecnicas para hacerlo asi y no con medidores de uso normal de caudal ). son como 300 usuarios

entonces el sim 900 aguanta 30 sms los guardos en la microsd :

0:01;84465708,10 bool:numero_sim;numero_telefono,litros_pedidos

luego borro los mensajes del sim900 para los nuevos mensajes entrantes.

por eso debo leer los mensajes desde la microsd para saber quien y cuanto estan pidiendo de agua. debo guardar en la microsd por fallas en el suministro electrico ( es probable en areas alejadas de la ciudad). No ocupo internet porque es un pueblo de esos lejanos.

lo de la memoria como lo soluciono?. si puedes darme alguna idea lo agradezco, ya que lo hago para entretenerme en los tiempos libres y para ayudar.

Hola de nuevo. Mira; lo importante en sí es saber qué quieres conseguir con el paso que se te está atragantando. Hablas de cargar en un array los 300 registros que puedes tener en la SD, pero veo tu código y no existe tal array. Estás recorriendo un for con una función readfile que entiendo que busca y devuelve el número de línea correspondiente. Parece que cada vez que esta función devuelve un valor va dejando memoria por ahí perdida, y lo peor es que en cada línea del for sólo estás disponiendo del registro actual (no están quedando en ningún array). En resumen, se está consumiendo memoria sin almacenar nada. Por ello te preguntaba qué querías hacer, principalmente cómo vas a tratar los datos que cargas. Ahora mismo creo que tu aplicación lo único que hace es recorrer el archivo e imprimir cada registro. Eso se puede hacer con pocas líneas de código y sin necesidad apenas de memoria.

hola NOTER, primero que nada gracias por leer mi consulta

aqui va el codigo que uso , lo que quiero es leer cada linea de la microsd y dejarla en cada elemento del array mistring ( es un String mistring[30] ), el print solo es para ir testeando si el array se va llenando , ese print lo sacare cuando vea que mistring se ha llenado correctamente, despues usare ese array para otras operaciones, pero ni siquiera he logrado leer el archivo en la microsd.

#include <SD.h>
   String mistring[30];
   int j;
   int i;
   char Ruta[10] = {'l', 'e', 'e', 'm','e', '.', 't', 'x', 't', '\0'};
   int freeRam()
{
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
   void setup()
   {
   // Open serial communications and wait for port to open:
   Serial.begin(9600);
   delay(2000);
   Serial.print("  SRAM Libre: "); Serial.println(freeRam());
   while (!Serial) {
   ; // Espera para conexion puerto serie, solo necesario para leonardo
   }
   Serial.print("Iniciando SD...");
   pinMode(10, OUTPUT);
   if (!SD.begin(4)) {
   Serial.println("Error inicializar SD!");
   return;
   }
   Serial.println("SD iniciada correctamente.");
   // aqui va la ruta
   //Leemos linea de archivo en la SD
   //String Lin = ReadFile(3,Ruta);
   
   }
   void loop()
   {
     for (int i= 0; i<=30; i++)
{
mistring[i] = ReadFile(i,Ruta);


Serial.println( mistring[i] );
delay(2000);
//if ( valor_actual == pedido[i] ) {
//Serial.println(fono[i] );
//}  
}  
   // no hacer nada
}
 //String Lin = ReadFile(j,Ruta);  
   //Funcion para leer linea de un archivo de la sd
   //Primer parametro numero de linea
   //Segundo Parametro ruta del fichero

   
  String ReadFile(int Linea,char Ruta[]){
     
   int Lin=0;
   String Resultado;
   File myFile;
   byte Bin;
   myFile = SD.open(Ruta);
   if (myFile) {
   while (myFile.available()) 
   {
   Bin=myFile.read();
   if (Bin==13)
   {
   Lin++;
   myFile.read();
   }
   else
   {
   if (Lin==Linea){
   Resultado=Resultado+(char(Bin));
   
   }
   //Serial.println(Resultado);
   if (Lin>Linea)
   {
   myFile.close();
   //ProcessSms(Resultado);
   return Resultado;
   }
   }
   }
   myFile.close();
   }
   else {return"NOFILE!!";}
  }

el valor 30 en el indice de mistring, es solo prueba , de hecho solo llega a lenar los 15 primeros elementos.

aca puse el codigo para la memoria fuera del for pero si coloco el codigo dentro cuando falla llega
a sram 300.

adjunto pantalla de la lectura y de la microsd , cualquier codigo es…bienvenido. no se me ocurre nada mas.

analisis de lectura de microsd.png

Saludos. Ante todo lee las normas del foro y deja de colgar códigos sin los tag.

Segundo cuando solo tienes 596 bytes libre de RAM y lees cada linea 18 bytes, los que si el Arduino no usase mas para variables en sus librerías te daría solo para cargar 33 lineas.

Tienes un problema de RAM no pelees mas con eso, usa un arreglo de char para la cantidad de bytes por linea, algo como char line[18]; cargas una linea de tu archivo verificas lo que quieres y luego destruyes esta variable para cargarla de nuevo con otra linea. Usando solo la cantidad de RAM estrictamente necesaria y dejando para otras opciones.

Sigues sin responder a mi pregunta. ¿Por qué necesitas cargar en un array todos esos datos? Puedes accederlos en cualquier momento desde la propia SD. Puedo apuntarte un código para introducir esos datos en un array de forma más eficiente, pero dudo que te lleguen a caber los 300 registros. En tu lugar yo me centraría en buscar una forma trabajar los datos eficientemente sobre la propia SD. De todas formas cuando pueda te envío un código para cargar en array tus datos; lo que no sé es cuántos te cabrán (más que ahora, seguro; pero no creo que todo). Saludos.

Ahí va un código hecho al vuelo. Tal vez tenga errores y haya que hacer alguna modificación dependiendo de cómo estén guardados tus datos en el archivo. No obstante sería la forma “más ahorrativa” de almacenarlos en RAM. Si funciona, puedes ir cambiando el define arraySize para ver hasta cuántos podría llegar a almacenar, pero como te dije antes, creo que no es el camino: debes centrarte en tratar registros uno a uno y volver a guardar en SD los cambios.
Saludos

#include <SD.h>
#define arraySize 100 // cambiar para probar número de elementos que vamos a intentar almacenar

struct MisDatos{
      bool a;
      byte numero_sim;
      unsigned long telefono;
      byte litros_pedidos;
} 
miArray[arraySize];

char Ruta[10] = "leeme.txt";
void setup()
{
      // Open serial communications and wait for port to open:
      Serial.begin(9600);
      while (!Serial) {
            ; // Espera para conexion puerto serie, solo necesario para leonardo
      }
      Serial.print("Iniciando SD...");
      pinMode(10, OUTPUT);
      if (!SD.begin(4)) {
            Serial.println("Error inicializar SD!");
            return;
      }
      Serial.println("SD iniciada correctamente.");
      // aqui va la ruta
      //Leemos linea de archivo en la SD
      //char *Lin = ReadFile(3,Ruta);
      File myFile =SD.open(Ruta);
      if (myFile) {
            for (int i = 0; i < arraySize; i++){
                  MisDatos &datoActual = miArray[i];
                  datoActual.a = myFile.parseInt();
                  datoActual.numero_sim = myFile.parseInt();
                  datoActual.telefono = myFile.parseInt();
                  datoActual.litros_pedidos = myFile.parseInt();
            }
            myFile.close();
      }

      for (int i = 0; i < arraySize; i++){
            MisDatos &datoActual = miArray[i];
            Serial.print(datoActual.a);
            Serial.print(F("-"));
            Serial.print(datoActual.numero_sim);
            Serial.print(F("-"));
            Serial.print(datoActual.telefono);
            Serial.print(F("-"));
            Serial.println(datoActual.litros_pedidos);
      }

}
void loop()
{
      // no hacer nada
}

Hola

Mira lo que hay en el loop():

    void loop()
    {
      for (int i= 0; i<=10; i++)
 {
 mistring = ReadFile(i,Ruta);
 estado = mistring.substring( 0,1);
 int dcPos = mistring.indexOf( ":" );
 simcard = mistring.substring( dcPos+1,dcPos+3 );
 int dPos = mistring.indexOf( ";" );
 fono = mistring.substring( dPos+1,dPos+9 );
 int cPos = mistring.indexOf( "," );
 pedido = mistring.substring( cPos+1,cPos+4 );
 delay(500);
 Serial.println( fono );
 //if ( valor_actual == pedido ) {
 //Serial.println(fono );
 //}  
 }  
    // no hacer nada
}

Puntualmente te faltaron los corchetes del indice en el array

for (int i= 0; i<=10; i++)
{
mistring**[ i ]** = ReadFile(i,Ruta);
estado** [ i ]** = mistring.substring( 0,1);


.

hola, gracias a su ayuda he logrado leer el archivo desde la microsd y de una mejor manera ( sin gastar mucha ram ).

alguien se le ocurre como podria hacer para SOBRE ESCRIBIR una linea cualquiera.

por ejemplo si quiero leer la linea 10, con Readline(i,Ruta) puedo leer la linea 10 eso esta terminado

¿ pero como podria sobre escribirir la linea 10 despues de leerla y usarla ?, he buscado pero no he encontrado nada parecido.

necesito pasar de 0:04;87654321,05 a 1:04;87654321,05 , es decir una vez usada la linea cambiarle el primer caracter.

Creo que sí se puede, pero debes ser estricto en cuanto a la longitud de los datos. Debes situar el punto de escritura en la posición de inicio del registro a modificar y escribir los nuevos datos. Lo que escribas se irá superponiendo a lo existente, así que si escribes más de lo debido estarás pisando otros registros. Por ello te digo lo de ser estricto. Imagínate que trabajas un archivo de texto en modo sobrescribir. Cuando pueda te doy más Info, que ahora estoy con el teléfono.

Como íbamos diciendo... Para manejar un archivo como si fuera una tabla de base de datos, deberías tener muy clara la longitud del registro. Ojo, que no sólo cuentan los caracteres visibles. Los saltos de línea, por ejemplo, pueden tener uno o dos caracteres. El editar el archivo a mano suele ser fuente de problemas si no se hace con cuidado exquisito. Si miras en la referencia de SD, a la derecha, en la parte inferior, verás un listado de los métodos de la clase File, que es la que nos interesa. Cuando abrimos un archivo, el objeto File va a crear un puntero (podemos llamarle cursor, por similitud con lo que te comentaba antes del editor de texto en modo sobrescribir). Dependiendo de cómo abramos ese cursor va a apuntar al principio del archivo (si abro en modo lectura, por ejemplo) o al final (si abro en modo agregar), y nos va a permitir leer/escribir en la posición donde se encuentre ese cursor. Ten en cuenta que la mayoría de las funciones de lectura o escritura (salvo peek), avanzan ese cursor después.

Ahora, aplicando a tu caso. Supongamos que acabamos de leer un registro que vamos a querer modificar.

Primeramente obtenemos la posición del cursor:

unsigned long cursor=myFile.position();

Como hemos dicho, tras leer el registro actual, el cursor se hallará justo después, por lo que tendremos que calcular la posición donde comenzaba nuestro registro:

cursor-=longitud_registro;

También podríamos haber guardado directamente la posición del cursor antes de leer nuestro registro, con lo que no tendríamos que hacer la resta. En todo caso, lo siguiente sería colocar el cursor en esa posición y escribir nuestro dato modificado: if (myFile.seek(cursor)) myFile.print(registro_modificado); He puesto print, pero puede ser la función de escritura más adecuada para nuestro tipo de datos (print, println o write).

Espero haberte aclarado, en lugar de liarte más. No obstante, creo que debes retroceder y rediseñar o asentar perfectamente la estructura que va a tener tu archivo (longitud de los campos, texto o binario, separadores de campo/registro...) previendo todo el rango de posibilidades de los datos que vaya a contener. Saludos.

hola, coloco el codigo para recibir desde el modem y escribir en la sd, el problema es que no puedo enviar

alguien sabe como me puedo dar cuenta si el modo espera en que esta el modem en el codigo me estuviera bloqueando el envio?.

como saber si quizas el escribir y leer en las sd este haciendo conflicto.

espero entiendas la pregunta al ver el codigo pero explico.

  1. esta esperando a que llegue un sms ( available en el loop)
  2. si llega un sms va a la funcion processgprs y escribir en la sd
  3. si no llega un mensaje debiera seguir en el loop y llamar a buscarsd()
    4.si encuentra algo debiera enviar un sms.

los puntos 1 y 2 estan funcionando bien , el punto 3 y 4 no veo el problema, cualquiera sugerencia es welcome

#include <SoftwareSerial.h>
#include <SD.h>
#include <SPI.h>
SoftwareSerial mySerial(7,8);
const int chipSelect = 4;
String msg = String("");
String Datoentrada;
char Ruta[10] = {'l', 'e', 'e', 'm','e', '.', 't', 'x', 't', '\0'};
int j= 69;
boolean enviado[30]= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
String mistring;
String fono;
String pedido;
int convertido;
char charBuf[9];
int SmsContentFlag = 0;
void setup()
{
  mySerial.begin(9600);        
  Serial.begin(9600);               
 
  pinMode( 10, OUTPUT);
  digitalWrite( 10, HIGH );
  
  if (!SD.begin(chipSelect)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");
}
 
void loop()
{
    char SerialInByte;
 
    if(Serial.available())
    {
       mySerial.print((unsigned char)Serial.read());
     }  
    else  if(mySerial.available())
    {
        char SerialInByte;
        SerialInByte = (unsigned char)mySerial.read();
 
        Serial.print( SerialInByte );
       
        if( SerialInByte == 13 ){
          
          ProcessGprsMsg();
         }
         if( SerialInByte == 10 ){
            
         }
         else {
           
           msg += String(SerialInByte);
         }
     }
 delay(3000);    
 buscarsd ();
}
 
void ProcessSms( String sms ){
  Serial.print( "ProcessSms for [" );
  Serial.print( sms );
  Serial.println( "]" );
  File myFile = SD.open("leeme.txt", FILE_WRITE);
  if (myFile) {
    myFile.print(sms);
    myFile.close();
  } else {
    Serial.println("error opening leeme.txt");
  }
   return;
}

void ProcessFin( String sms ){
  Serial.print( "ProcessSms for [" );
  Serial.print( sms );
  Serial.println( "]" );
  File myFile = SD.open("leeme.txt", FILE_WRITE);
  if (myFile) {
    myFile.println(sms);
    myFile.close();
  } else {
    Serial.println("error opening leeme.txt");
  }
   return;
}
 

void GprsTextModeSMS(){
  mySerial.println( "AT+CMGF=1" );
}
 
void GprsReadSmsStore( String SmsStorePos ){
  mySerial.print( "AT+CMGR=" );
  mySerial.println( SmsStorePos );
  String Posicion = String("0")+String(":")+SmsStorePos+String(";");
  ProcessSms(Posicion );
}
 
void ClearGprsMsg(){
  msg = "";
}
 
void ProcessGprsMsg() {
  Serial.println("");
  Serial.print( "GPRS Message: [" );
  Serial.print( msg );
  Serial.println( "]" );
 
  if( msg.indexOf( "Call Ready" ) >= 0 ){
     Serial.println( "*** GPRS Shield registered on Mobile Network ***" );
     GprsTextModeSMS();
  }
 
  if( msg.indexOf( "+CMTI" ) >= 0 ){
     Serial.println( "*** SMS Received ***" );
     int iPos = msg.indexOf( "," );
     String SmsStorePos = msg.substring( iPos+1 );
     Serial.print( "SMS stored at " );
     Serial.println( SmsStorePos );
 
     // EN: Ask to read the SMS store
     GprsReadSmsStore( SmsStorePos );
  }
 
  if( msg.indexOf( "+CMGR:" ) >= 0 ){
     int tPos = msg.indexOf( "," );
     String Telefono = msg.substring( tPos+6,tPos+14 ); // aca ya tengo el telefono
     Serial.print( "telefono que llama " );
     Serial.println( Telefono );
     String Telefo = Telefono+String(",");
     ProcessSms(Telefo);
    SmsContentFlag = 1;
    ClearGprsMsg();
    return;
  }
 
  if( SmsContentFlag == 1 ){
    
    Serial.println( "*** SMS MESSAGE CONTENT ***" );
    Serial.println( msg );
    Serial.println( "*** END OF SMS MESSAGE ***" );
    String pedido = msg;
    ProcessFin(pedido);
  }
  
  ClearGprsMsg();

  SmsContentFlag = 0; 
}
   
  void enviosms(){             
  mySerial.print("AT+CMGS=\"+56984465908\"\r"); 
  delay(1000);
  mySerial.print("carga de agua terminada");  
  delay(1000);
  mySerial.write(0x1A);
  delay(1000);
  return; 
  }  
  
  void buscarsd(){
  for (int i= 0; i<=40; i++)
      {
  mistring= ReadFile(i,Ruta);
  int cPos = mistring.indexOf( "," );
  pedido= mistring.substring( cPos+1,cPos+4 );
  convertido= pedido.toInt();
  if ( j == convertido && enviado[0] == 0){
  enviado[0] = 1;
  enviosms();  
  int fPos = mistring.indexOf( ";" );
  fono = mistring.substring( fPos+1,fPos+9 );
  fono.toCharArray(charBuf, 9) ;
 delay(1000);
 
   }
  }
 }
 
 String ReadFile(int Linea,char Ruta[]){
      
    int Lin=0;
    String Resultado;
    File myFile;
    byte Bin;
    myFile = SD.open(Ruta);
    if (myFile) {
    while (myFile.available()) 
    {
    Bin=myFile.read();
    if (Bin==13)
    {
    Lin++;
    myFile.read();
    }
    else
    {
    if (Lin==Linea){
    Resultado=Resultado+(char(Bin));
    
    }
    if (Lin>Linea)
    {
    myFile.close();
    return Resultado;
    }
    }
    }
    myFile.close();
    }
    else {return"NOFILE!!";}
   }