Consiglio upgrade per problemi memoria

Ciao a tutti, avrei bisogno di un consiglio.
Sto creando un progettino con arduino uno, gps shield, un sensore seriale, un dht22, un paio di pulsanti e un lcd 20x4. In compilazione mi dice 67% della memoria utilizzata, però accade che in esecuzione spesso ho problemi, soprattutto con la lettura di una stringa abbastanza lunga (circa 60 caratteri). Ovvero si perde pezzi per strada. Ho letto che le stringhe lunghe danno spesso questi problemi, allora sto pensando ad un upgrade. Avrei individuato arduino mega, ma ho visto che ci sono diverse versioni, quindi chiedo a voi un consiglio sul modello esatto da prendere.
Inoltre vorrei capire se con il mega potrei risolvere questi problemi e se il progetto è "trasferibile" senza complicazioni sul mega, nel senso montaggio shield, collegamento pin, programmazione con Ide... Tutto uguale?
Grazie!

Non serve a nulla cambiare board ...
... la velocità è la stessa ed il tuo problema NON è dovuto alla memoria disponibile (sei solo al 67%), ma alla dimensione del buffer che riceve i dati (scommetto che usi la SoftwareSerial) che va incrementato.

Guglielmo

P.S.: puoi prendere in considerazione il passaggio ad una MEGA se prevedi di aggiungere funzionalità che aumentano l'occupazione del codice o se necessiti di più pin di I/O, per altre cose non è necessario.

Secondo me con la macro F() nei serial print o display print puoi risparmiare molta RAM.
Dacci lo sketch.
Ciao Uwe

Uwe, NON è un problema di RAM, è un problema di dimensione del buffer della SoftwareSerial ... ho avuto lo stesso problema con la mia scheda GPS e l'ho appunto risolto portando il buffer della SoftwareSerial da 64 a 128 byte.

Guglielmo

Ragazzi grazie.
Spero domani di riuscire a postare lo sketch, sono fuori casa e non ho con me il PC.
Vi faccio sapere prima possibile, spero di risolvere!
Cmq sì, uso la SoftwareSerial, per gps e un altro Sensore, ne inizializzo 2 e le leggo alternativamente.

PS: mi piacerebbe riuscire a leggere il gps collegandolo alla seriale hw, ma ancora non vi sono riuscito... Forse in tal caso risolverei i problemi di buffer?

arduale:
Cmq sì, uso la SoftwareSerial ...

Vai nella cartella "/hardware/arduino/avr/libraries/SoftwareSerial/src", edita il file SoftwareSerial.h, alla riga 42 e correggi il 64 in 128 :

#define _SS_MAX_RX_BUFF 128 // RX buffer size

... vedrai che non avrai più quei problemi.

Guglielmo

eccomi qua!
allora, intanto grazie ancora per tutti i suggerimenti!

ecco il mio sketch, lo so che vi farà rabbrividire, ma abbiate pietà, ho iniziato da poco! devo ancora imparare il passaggio di variabili per indirizzo, quindi sono tutte o quasi variabili globali, so già che non vi piacerà!
però funziona quasi tutto!

#include <SoftwareSerial.h>
#include <LiquidCrystal_I2C.h>
#include <DHT22.h>
#include <SdFat.h>

#define DHT22_PIN 6
#define SD_CS 10

LiquidCrystal_I2C lcd(0x27, 20, 4);
DHT22 myDHT22(DHT22_PIN); // Setup a DHT22 instance
SoftwareSerial mySerial(2, 3); // RX, TX sensor
SoftwareSerial gpsSerial(8, 7);
SdFat SD;
File logFile;

double value = 0; // valore letto dal sensore
String lat, lon, data, ora;
String dataLog;
char nomeFile[] = "MMDDHHMM.txt"; 
unsigned long time_int;
String NMEA, gprmc;
int samples = 0;

struct dati_DHT22
{
  float temperatura;
  float umid;
} ;

dati_DHT22 dati;

void setup()
{
  lcd.init();// inizializza il display
  lcd.backlight();//accende la retroilluminazione
  pinMode(SD_CS, OUTPUT);

  if (!SD.begin(SD_CS)) {
    lcd.print(F("SD ... failed!"));
    return;
  }
  lcd.print(F("SD card ... OK"));

  delay(1000);

  Serial.begin(9600);                            // Start Serial connection with PC
  gpsSerial.begin(9600);              // Start Serial connection with GPS

}

void loop()
{
  read_gps();

  if (lat != "" && lon != "")  // creo il nome del file solo se il GPS è in fix
  {
    creaNomeFile();
  }

  if (millis() > time_int + 3000) // ogni 3 secondi leggo i sensori
  {
    read_sensor(); // legge il sensore e recupera la variabile "value"
    dati = read_DHT22();

    // se utilizzo le due linee seguenti, la variabile dataLog è incompleta (si perde la parte relativa al GPS)
    // dataLog = (data + "; " + ora + "; " + lat + "; " + lon + "; " + value + "; " + dati.temperatura + "; " + dati.umid);
    // Serial.println(dataLog);
    // quindi devo scrivere un pezzo alla volta, sia sul monitor seriale, sia sulla SD
    
    Serial.print(gprmc); Serial.print(","); Serial.print(value) ; Serial.print(",");
    Serial.print( dati.temperatura) ; Serial.print( "," ) ; Serial.println(dati.umid);
    print_lcd();
    samples++;

    logFile = SD.open(nomeFile, FILE_WRITE);
    if (logFile) {
      logFile.println( dataLog );  
      logFile.close();
    }
    time_int = millis ();
  }
}

void read_gps() {
  int posizione_delimitatore = 0;
  int index = 0;
  int campo = 0;

  if (gpsSerial.available()) {
    //leggo la prima riga
    char c = gpsSerial.read();
    if (c != '\n') {
      NMEA += c;
    }
    else {
      posizione_delimitatore = 0;
      index = 0;
      campo = 0;  //questa variabile viene usata per contare tutti i campi trovati
      if (NMEA.substring(0, 6) == "$GPRMC")  //printo solo la stringa che mi interessa
      {
        gprmc = NMEA;
        while (posizione_delimitatore != -1)
        {
          posizione_delimitatore = NMEA.indexOf(",", index);
          //in funzione del campo invio al serial monitor
          //solo i dati che mi interessano
          switch (campo)
          {
            case 1:
              ora = NMEA.substring(index, posizione_delimitatore); break;
            case 3:
              lat = NMEA.substring(index, posizione_delimitatore); break;
            case 5:
              lon = NMEA.substring(index, posizione_delimitatore);  break;
            case 9:
              data = NMEA.substring(index, posizione_delimitatore); break;
          }
          index = posizione_delimitatore;
          index++;
          campo++; //incrementa il campo trovato
        }
      }
      NMEA = "";
    }
  }
}

void creaNomeFile()
{
  // funzione per creare il nome del file
}

void read_sensor()
{
  gpsSerial.end();          // fermo la SoftwareSerial del GPS
  mySerial.begin(9600);     // avvio la SoftwareSerialdel sensore
  // codice fornito dal produttore del sensore
  mySerial.end();
  gpsSerial.begin(9600);
}

dati_DHT22 read_DHT22()
{

  DHT22_ERROR_t errorCode;
  errorCode = myDHT22.readData();
  switch (errorCode)
  {
    case DHT_ERROR_NONE:
      dati.temperatura = myDHT22.getTemperatureC();
      dati.umid = myDHT22.getHumidity();
      break;
    default:  dati.temperatura = 1000 ;  // se c'è qualche errore, scrivo "1000" nelle variabili
      dati.umid = 1000 ;                 // umid e temperatura
  }
  return dati;
}

void print_lcd()
{
  // funzione per scrivere sul LCD
}

ho omesso la funzione di lettura del sensore, perché quella deve rimanere così com'è. me l'ha fornita il produttore.
quello che ho fatto, è interrompere la SoftwareSerial del gps e far partire quella del sensore, per poi spegnerla e far ripartire il gps. altrimenti non funzionava.

anche dopo la modifica consigliata da guglielmo, rimangono problemi, se tento di usare la variabile dataLog, quindi non credo il problema sia il buffer, bensì la lunghezza della stringa dataLog.
devo quindi scriverla "un pezzo alla volta", come si vede nelle due linee successive.

quindi ogni consiglio per migliorare lo sketch è bene accetto, specialmente per la funzione creaNomeFile, che non sono ancora riuscito a scrivere correttamente, quindi il nome file al momento è sempre MMDDHHMM.txt, mentre ovviamente vorrei cambiasse ogni volta che avvio arduino. la mia idea è di lanciare la funzione all'interno di un ciclo if, che prevede il controllo del fix gps, ovvero se lat e lon sono diversi da "", allora crea il nome usando data e ora. ma non ci riesco...

grazie a tutti!

arduale:
quello che ho fatto, è interrompere la SoftwareSerial del gps e far partire quella del sensore, per poi spegnerla e far ripartire il gps. altrimenti non funzionava.

... ed è normale ... se studi il reference della SoftwareSerial specifica chiaramente che UNA sola istanza può essere attiva in ricezione alla volta, tanto è vero che c'è l'apposito metodo listen() per selezionare la seriale attiva !

arduale:
anche dopo la modifica consigliata da guglielmo, rimangono problemi, se tento di usare la variabile dataLog, quindi non credo il problema sia il buffer, bensì la lunghezza della stringa dataLog.
devo quindi scriverla "un pezzo alla volta", come si vede nelle due linee successive.

La mia modifica è per la ricezione di stringhe lunghe NON per la trasmissione !!!
Guglielmo

Ragazzi, funziona quasi tutto!
La stringa l'ho divisa in 2 e la scrivo in 2 volte. Per il nome del file ho trovato un metodo direi molto semplice, domani posto lo sketch!