Presentación y ayuda con código GPS+SD

Hola a todos mi nombre es Badel y estoy empezando con arduino ya que le veo muuuchas aplicaciones, estoy jugueteando con la integración de datos de diferentes sensores y dispositivos que tengo para que una vez sepa controlarlos, aplicarlos en diferentes proyectos... Ahora mismo me encuentro estancado en la integración de sensor de temperatura + humedad (am2301) con datos que extraigo de un GPS (adafruit v3) en un módulo SD (waveshare), el caso es que tengo diferentes códigos que funcionan correctamente de escritura y lectura de datos del sensor de temperatura sobre la sd, además tengo otro código donde muestro por puerto serie los datos del gps+ los datos de temperatura, pero cuando incluyo código para escribir sobre la sd... DEBACLE jajaj

Adjunto el código siguiente (en otro post porque excedo el límite de caracteres) donde he dejado comentado todo lo que tiene que ver con la sd (que es lo que me causa el problema), además muestro a continuación que los datos salen por puerto serie como los quiero

a continuación una imagen funcionando

cuando descomento el código

Muchas gracias por la ayuda

// Código para sensor de temperatura+humedad+humedad de tierra+GPS+time

#include "DHT.h"
#include <Adafruit_GPS.h>
#include <SoftwareSerial.h>
#include <SD.h>
/*Sd2Card card;
SdVolume volume;
SdFile root;
const int chipSelect = 10;  
File myFile;*/
SoftwareSerial mySerial(3, 2);
Adafruit_GPS GPS(&mySerial);
#define GPSECHO  false
#define DHTPIN 4   
#define DHTTYPE DHT21   // DHT 21 (AM2301)
DHT dht(DHTPIN, DHTTYPE);
boolean usingInterrupt = false;
void useInterrupt(boolean); // Func prototype keeps Arduino 0023 happy
void setup() {
  Serial.begin(9600); //aqui el software de test de gps usa 115200 cuidado
  Serial.println("Badel testea sensores temperatura + humedad + tierra + GPS!");
  GPS.begin(9600); 
  dht.begin();
  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);//bajar la frequencia para poder visualizar bien 
  GPS.sendCommand(PGCMD_ANTENNA); //por si metemos antena
  useInterrupt(true);
  /*Serial.print("Iniciando SD...");
  pinMode(10, OUTPUT);
  if (!card.init(SPI_HALF_SPEED, chipSelect)) {
    Serial.println("initializacion fallida. comprobar SD");
    return;
  } else {
   Serial.println("SD ok"); 
  }  
  // print the type of card
  Serial.print("\nTipo de tarjeta: ");
  switch(card.type()) {
    case SD_CARD_TYPE_SD1:
      Serial.println("SD1");
      break;
    case SD_CARD_TYPE_SD2:
      Serial.println("SD2");
      break;
    case SD_CARD_TYPE_SDHC:
      Serial.println("SDHC");
      break;
    default:
      Serial.println("Unknown");
  }
  // Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32
  if (!volume.init(card)) {
    Serial.println("No se puede encontrar FAT16/FAT32 particion.\nFormatear la SD");
    return;
  }
  // print the type and size of the first FAT-type volume
  uint32_t volumesize;
  Serial.print("\nTipo de volumen FAT");
  Serial.println(volume.fatType(), DEC);
  Serial.println();
  
  volumesize = volume.blocksPerCluster();    // clusters are collections of blocks
  volumesize *= volume.clusterCount();       // we'll have a lot of clusters
  volumesize *= 512;                            // SD card blocks are always 512 bytes
  Serial.print("Tamano (bytes): ");
  Serial.println(volumesize);
  Serial.print("Tamano(Kbytes): ");
  volumesize /= 1024;
  Serial.println(volumesize);
  Serial.print("Tamano (Mbytes): ");
  volumesize /= 1024;
  Serial.println(volumesize);  
  Serial.println("\nArchivos de la SD (nombre, fecha y tamano en bytes): ");
  root.openRoot(volume);
  
  // list all files in the card with date and size
  root.ls(LS_R | LS_DATE | LS_SIZE);
 if (!SD.begin(10)) {
    Serial.println("inicio SD fallido!");
    return;
  }
  Serial.println("initializacion ok.");
  myFile = SD.open("test.txt", FILE_WRITE);*/
}

// Interrupt is called once a millisecond, looks for any new GPS data, and stores it
SIGNAL(TIMER0_COMPA_vect) {
  char c = GPS.read();
  // if you want to debug, this is a good time to do it!
#ifdef UDR0
  if (GPSECHO)
    if (c) UDR0 = c;  
    // writing direct to UDR0 is much much faster than Serial.print 
    // but only one character can be written at a time. 
#endif
}

void useInterrupt(boolean v) {
  if (v) {
    // Timer0 is already used for millis() - we'll just interrupt somewhere
    // in the middle and call the "Compare A" function above
    OCR0A = 0xAF;
    TIMSK0 |= _BV(OCIE0A);
    usingInterrupt = true;
  } else {
    // do not call the interrupt function COMPA anymore
    TIMSK0 &= ~_BV(OCIE0A);
    usingInterrupt = false;
  }
}

uint32_t timer = millis();
void loop() {
  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  float y = analogRead(0);
  
  if (! usingInterrupt) {
    // read data from the GPS in the 'main loop'
    char c = GPS.read();
    // if you want to debug, this is a good time to do it!
    if (GPSECHO)
      if (c) Serial.print(c);
  }
  
  // if a sentence is received, we can check the checksum, parse it...
  if (GPS.newNMEAreceived()) {
    // a tricky thing here is if we print the NMEA sentence, or data
    // we end up not listening and catching other sentences! 
    // so be very wary if using OUTPUT_ALLDATA and trytng to print out data
    //Serial.println(GPS.lastNMEA());   // this also sets the newNMEAreceived() flag to false
  
    if (!GPS.parse(GPS.lastNMEA()))   // this also sets the newNMEAreceived() flag to false
      return;  // we can fail to parse a sentence in which case we should just wait for another
  }

  // if millis() or timer wraps around, we'll just reset it
  if (timer > millis())  timer = millis();

  // approximately every 2 seconds or so, print out the current stats
  if (millis() - timer > 2000) { 
    timer = millis(); // reset the timer
    
    Serial.print("\nHora: ");
    Serial.print(GPS.hour, DEC); Serial.print(':');
    Serial.print(GPS.minute, DEC); Serial.print(':');
    Serial.print(GPS.seconds, DEC); Serial.print('.');
    Serial.println(GPS.milliseconds);
    Serial.print("Fecha: ");
    Serial.print(GPS.day, DEC); Serial.print('/');
    Serial.print(GPS.month, DEC); Serial.print("/20");
    Serial.println(GPS.year, DEC);
    Serial.print("Fix: "); Serial.print((int)GPS.fix);
    Serial.print(" Calidad: "); Serial.println((int)GPS.fixquality);
     /*if (myFile) {
    myFile.print("escribiendo en txt...");
    myFile.print("\nHora: ");
    myFile.print(GPS.hour, DEC); myFile.print(':');
    myFile.print(GPS.minute, DEC); myFile.print(':');
    myFile.print(GPS.seconds, DEC); myFile.print('.');
    myFile.println(GPS.milliseconds);
    myFile.print("Fecha: ");
    myFile.print(GPS.day, DEC); myFile.print('/');
    myFile.print(GPS.month, DEC); myFile.print("/20");
    myFile.println(GPS.year, DEC);
    myFile.print("Fix: "); myFile.print((int)GPS.fix);
    myFile.print(" Calidad: "); myFile.println((int)GPS.fixquality);
	// close the file:
    myFile.close();
    Serial.println("archivo cerrado");
  } else {
    // if the file didn't open, print an error:
    Serial.println("No se pudo abrir archivo.txt");
  } */
    if (GPS.fix) {
      Serial.print("Localizacion (lat,long): ");
      Serial.print(GPS.latitude, 4); Serial.print(GPS.lat);
      Serial.print(", "); 
      Serial.print(GPS.longitude, 4); Serial.println(GPS.lon);
      Serial.print("velocidad (knots): "); Serial.println(GPS.speed);
      Serial.print("Angulo: "); Serial.println(GPS.angle);
      Serial.print("Altitud: "); Serial.println(GPS.altitude);
      Serial.print("Satelites: "); Serial.println((int)GPS.satellites);
       /*if (myFile) {
    myFile.print("escribiendo en txt...");
    myFile.print("\nHora: ");
    myFile.print(GPS.hour, DEC); myFile.print(':');
    myFile.print(GPS.minute, DEC); myFile.print(':');
    myFile.print(GPS.seconds, DEC); myFile.print('.');
    myFile.println(GPS.milliseconds);
    myFile.print("Fecha: ");
    myFile.print(GPS.day, DEC); myFile.print('/');
    myFile.print(GPS.month, DEC); myFile.print("/20");
    myFile.println(GPS.year, DEC);
    myFile.print("Fix: "); myFile.print((int)GPS.fix);
    myFile.print(" Calidad: "); myFile.println((int)GPS.fixquality);
	// close the file:
    myFile.close();
    Serial.println("archivo cerrado");
  } else {
    // if the file didn't open, print an error:
    Serial.println("No se pudo abrir archivo.txt");
  } */
    }
      if (isnan(t) || isnan(h)|| isnan(y)) {
    Serial.println("Algo falla en la lectura del DHT o humedad de tierra");
  } else {
    Serial.print("Humedad aire: "); 
    Serial.print(h);
    Serial.print(" %\t");
    Serial.print("Temperatura aire: "); 
    Serial.print(t);
    Serial.print(" *C\t");
    Serial.print("Humedad tierra lectura: "); 
    Serial.print(y);
    Serial.print("\t");
    if (y < 300) {
    Serial.println(" --> Seco");
  } else if (300 < y < 700) {
    Serial.println(" --> Humedad ligera");
  } else if (700 < y < 950) {
    Serial.println(" --> Humedo");
    }
    /*if (myFile) {
    Serial.print("escribiendo en txt...");
    myFile.print("Humedad aire: "); 
    myFile.print(h);
    myFile.print(" %\t");
    myFile.print("Temperatura aire: "); 
    myFile.print(t);
    myFile.print(" *C\t");
    myFile.print("Humedad tierra lectura: "); 
    myFile.print(y);
    myFile.print("\t");
    if (y < 300) {
    myFile.println(" --> Seco");
  } else if (300 < y < 700) {
    myFile.println(" --> Humedad ligera");
  } else if (700 < y < 950) {
    myFile.println(" --> Humedo");
    }
	// close the file:
    myFile.close();
    Serial.println("archivo cerrado");
  } else {
    // if the file didn't open, print an error:
    Serial.println("No se pudo abrir archivo.txt");
  }*/
  }
}
delay(2000);
  }

Hola badel.

Se me ocurre que puede ser que no te quede memoria RAM, y se te queda bloqueado. Si es un arduino uno puede ser eso.

mira la memoria SRAM que te queda con esta función que la colocarás antes del inicio del setup junto con tu código

..........
 int freeRam () {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
} 
Void setup(){
............

llama a la función antes de iniciar el loop para que te muestre la memoria SRAM libre en bytes

................
Serial,print(F("Memoria libre en SRAM  ---> "));Serial.print(freeRam ());Serial.println(F(" bytes"));
} //fin del setup
void loop(){
...........................

Arduino uno ------>2000 bytes SRAM
Arduino mega----->8000 bytes SRAM

Si fuese eso el problema, sustituye todos los Serial.print("TEXTO") que tienes por Serial.print(F("TEXTO")) y no consumirás tanta memoria.
Hazlo también en myFile.println(F("TEXTO"))

Espero que te sea de ayuda.

Saludos.

muchas gracias compañero, no conocía esta función para gestionar la RAM, haz arrojado bastante luz :), al ejecutarla sin descomentar nada ya dice que sólo me quedan 250 bytes de RAM así que... voy a intentar cambiar lo que me comentaste y adelgazar el código en la medida de lo posible y os digo algo. muchas gracias de nuevo.

Edito para comentar que aunque tengo que pulir el código ya funciona, cosa que agradezco :wink: además he leído por ahí acerca de aumentar las capacidades de memoria de nuestro arduino, comparto a continuación para el que quiera seguir investigando:

Parece ser que podemos usar una EEPROM externa, serie 24LC256 que tiene una capacidad de 256 Kbit (32K x 8 bytes).
La comunicación entre Arduino y la EEPROM se realiza mediante el bus I2C , que se trata de un bus de comunicaciones serie formado por dos lineas: una para los datos y otra para el reloj.
La librería Wire permite manejar un bus I2C desde nuestro Arduino, y en este artículo del wiki encontramos 4 funciones que usando la librería anterior implementan la lectura/escritura en la EEPROM.

Por otro lado si necesitas más espacio de almacenamiento y sólo tendrás que conservar los datos, mientras que el Arduino se alimenta, solo faltaría añadir memoria RAM. El 23K256 es un chip de SRAM de 32K, que utiliza una interfaz SPI. XD

Hola:

Se puede ahorrar la escasa memora SRAM usando la macro F en los llamados Serial.println .

Pasa de Serial.println("blah blah") a Serial.println(F("blah blah")) . Ahora el almacenamiento es en la Flash, que es un poco mas abundante.

Esto esta explicado mejor en algún lado de arduino.cc

Saludos

Hola badel.

cierto perrociego, cuando utilices la macro F() en Serial.println() se verá incrementada la memoria flash.
BAdel si tu proyecto no va mas lejos de lo que tienes echo, para que una eeprom externa?

Aun no as utilizado la eeprom de arduino, y aparte tienes una sd(supongo con mucha capacidad) de la cual podrías recuperar los texto que luego mandarías por el serial o a la sd otra vez con los textos y variables que te interesen así no consumirías tanta memoria flash si la tienes a tope también.

Saludos

A ver compañeros... mi problema se resolvió en el post numero 3 utilizando el serial.print f (gracias pacoooh) XD el resto es un extra para los que se encuentren en complicaciones con la RAM en el futuro supieran que se podía "ampliar" jajaj pero gracias
No obstante me parece interesante lo que comentas... me será útil en el futuro.
Un saludo