Programma si blocca a caso

Buongiorno a tutti i forummari

Ho realizzato un garduino (clone)
Il sistema oltre ad innafiare fa dataloging su scheda sd

Il problema e che dopo qualche giorno il programma si blocca e l'unica coluzione é il reboot di arduino (togliere e mettere la scheda non cambia la situazione)
Ho provato a vedere i log e il tempodi attività é variabile 5-15 giorni anche il numero di righe scritte non é fisso dunque mi viene da dire che si blocca a random.

Leggendo in giro ho letto che potrebbe essere la ram che non si svuota e va in overflow
Per scrivere sulla sd uso flush
Come posso trovare l'origine del problema?

PS
Lo sketch usa 20322 byte (66%) dello spazio disponibile per i programmi. Il massimo è 30720 byte.
Le variabili globali usano 1316 byte (64%) di memoria dinamica, lasciando altri 732 byte liberi per le variabili locali. Il massimo è 2048 byte.

Intanto potresti aggiungere nel "log" la memoria mano mano occupata ... leggi QUI per come fare a controllarla durante l'esecuzione ... così ti togli il dubbio sull'occupazione della SRAM ...

... poi, per chi non conosce l'oggetto, uno schema dei collegamenti sarebbe gradito :wink:

Guglielmo

Ecco lo schema in allegato

Ho usato delle schede cumuni sia per il sensore umidità del terreno che per il datalog

Provo ad aggiunger il log della sdram e vi faccio sapere

nid69ita:
Mah, come al solito. Senza offesa ma chiedi aiuto e non posti il codice. E nemmeno lo schema (postato in un secondo momento).
Senza tutti i dati possiamo solo fare supposizioni. Una è quella della RAM, magari usi la classe String ?
Poi, non sono un elettronico, ma dai rele possono arrivare sbalzi, lo hai collegato direttamente ? Che modulo rele usi ? Senza sapere il modello anche qui difficile dare consigli :wink:

Innanzi tutto grazie dei cosnigli

Non ho messo ne schema ne codice perché a volte puo essere frainteso in "fate il lavoro al posto mio e risolvetemi il problema".

Visto che credo sia un problema di memoria volevo semplicemente sapere come si trovare e risolvere questo tipo di problemi.
Comunque non ho nessun problema a postare il codice e a fornire informazioni.

Per i relay uso un modulo con isolamento ottico dunque la possibilita di interferenze é minima.
Ma sopratutto si uso parecchie string per scrivere i log
La libreria per scrivere sulla sd accetta solo string come input e dunque sono obbligato a convertire tutti i valori dei sensori prima di passarglieli.
COme posso ovviare al problema?
(quando torno a casa posto il codice)

olometaboy:
Per i relay uso un modulo con isolamento ottico dunque la possibilita di interferenze é minima.

Hai separato anche le alimentazioni o sono in comune, perché il problema potrebbe essere quello, in questi casi è bene avere due alimentatori completamente separati, anche il GND non deve essere in comune tra arduino e relay board

fabpolli:
Hai separato anche le alimentazioni o sono in comune, perché il problema potrebbe essere quello, in questi casi è bene avere due alimentatori completamente separati, anche il GND non deve essere in comune tra arduino e relay board

Ho un alimentatore 12v che alimenta arduino e il carico collegato tramite il relay
Il comando al relay é dato con un pin e per alimentarlo uso la 5v di arduino.
Il gnd é comune a tutto il circuito.
Provero anceh questa soluzione

olometaboy:
Ma sopratutto si uso parecchie string per scrivere i log
La libreria per scrivere sulla sd accetta solo string come input e dunque sono obbligato a convertire tutti i valori dei sensori prima di passarglieli.

Non ho capito il discorso delle String la file.print() non accetta solo String ma a me risulta tutti i tipi (char, byte, int, e long).
Attendiamo il codice e poi possiamo ragionarci sopra.

Ecco il codice

Inizializzazione

/* Connesione pins:
 
Analog  A0  INPUT   Sensore umidità terreno YL-69
Digital D8  OUTPUT  Alimentazione ensore umidità terreno YL-69
Digital D10 INPUT   Sensore Vasca piena vuota
Digital D12 OUTPUT  Led vasca vuota
Digital D11 OUTPUT  Relay pompa
Digital D9  INPUT   DHT22 sensore temperatura e umidita aria

  
  
*/
//controllo memoria
#include "MemoryFree.h"

//Time
#include <Wire.h>
#include "RTClib.h"

//SD
#include <SPI.h>
#include <SD.h>

//Umi e tem aria
#include <SimpleDHT.h>


//set up  pin
#define Soil       6  //Analogico INPUT Soil Moisture Sensor YL-69
#define pinDHT22   2  //Digitale  INPUT Sensore Temperatura e umidita 
#define Relay      4  //Digitale  OUTPUT RELAY

#define VascaPiena 5  //Digitale  INPUT Sensore Vasca piena vuota
#define Wled       6  //Digitale  OUTPUT LED Vasca vuota
#define SoilPower  7  //Digitale  OUTPUT Accensione sensore terreno
//SD setup
const int chipSelect = 53;
File dataFile;

//Time setup
RTC_DS1307 rtc;

//Umi e tem aria
//int pinDHT22 = 22; //      DATA: 2
SimpleDHT22 dht22;

//irrigazione
int irri = 0;
//Inizializzazione della varibile per eseguire le azioni ogni tot tempo
unsigned long previousMillis0 = 0;
unsigned long previousMillis1 = 0;
void setup() {

  Serial.begin(9600);

  // Assegnazione input/output

  //Umidità
  pinMode(Soil, INPUT);       //umidita terra *UMIDITA*
  pinMode(SoilPower, OUTPUT); //alimentazione terra umida (per limitare la corrosione del sensore) *UMIDITA*

  //Vasca
  pinMode(VascaPiena, INPUT); //Gallegiante vasca *VASCA*
  pinMode(Wled, OUTPUT);      //Led vasca vuota *VASCA*

  //Irrigazione
  pinMode(Relay, OUTPUT);    //Relay accensione pompa *VASCA* *IRRIGAZIONE*
  digitalWrite(Relay, LOW); // Inizalizzazione pompa spenta relay is OFF when HIGH and ON when LOW
  

  initSD();
  initTime();

}

[b]CICLO[/b]

CICLO

void loop()
{

  unsigned long currentMillis = millis();


   if (currentMillis - previousMillis0  >= 7200000) //verifica se necessario irrigare ogni 2 ora 7200000ms
  //if (currentMillis - previousMillis0  >= 20000) // per test
  {
    previousMillis0 = currentMillis;

    if ((vasca() == "PIENA") && (umidita() >= 600)) //se vasca piena e umidita terreno superore a 600 innafia
    {
      irrigazione();
      //Serial.println("*** TERENO SECCO ***");
      //Serial.println(umidita());
    }
    else if (umidita() < 370)
    {
      //Serial.println("*** TERENO UMIDO ***");
     // Serial.println(umidita());
    }

    if (vasca() == "VUOTA")
    {
      //Serial.println("*** VASCA VUOTA ***");
    }


  }



   if (currentMillis - previousMillis1 >= 3600000) // crea un log ogni 1 ora 3600000ms  (10 minuti 600000ms)
 // if (currentMillis - previousMillis1 >= 10000) //per test
  {

    //Serial.println("CREAZIONE LOG");
    //Serial.println(log());
    previousMillis1 = currentMillis;
    sdlog(); //Esegue data vasca e umidita tramite log e le scrive sulla SD
    //Serial.println("LOG CREATO");
  }

}

IRRIGAZIONE

//irrigazione

void irrigazione()
{

  if (vasca() == "VUOTA")
  {
    irri = 0;
  }
  else
  {
    irri = irri + 1; //contatore numero di irrigazioni
  }

  //Serial.println("IRRIGAZIONE IN CORSO");
  digitalWrite(Relay, HIGH);      // Turns ON puump

  delay (15000); //annafia per 15 secondi

  digitalWrite(Relay, LOW);     // Turns OFF pump
  //Serial.print("IRRIGAZIONE ");
  //Serial.print(irri);
  //Serial.println(" EFFETUATA");

  sdlog(); //Esegue data vasca e umidita tramite log e le scrive sulla SD
  dataFile.print(log());
  dataFile.print(",IRRIGAZIONE ");
  dataFile.print(irri);
  dataFile.println(" EFFETUATA,");


  // The following line will 'save' the file to the SD card after every
  // line of data - this will use more power and slow down how much data
  // you can read but it's safer!
  // If you want to speed up the system, remove the call to flush() and it
  // will save the file only every 512 bytes - every time a sector on the
  // SD card is filled with data.
  dataFile.flush();
}

LOG

String log()
{
String datalog = "";

String Ldata = data();
String Lvasca = vasca();
String Lumidita = String (umidita());
String Lumitemp = String (umitemp());
String Lmem = String (freeMemory());
datalog = Ldata +"," + Lvasca + "," + Lumidita + "," + Lumitemp +"," + Lmem;
//Serial.println(datalog);
return datalog;
}

SD

/*SD card datalogger

  This example shows how to log data from three analog sensors
  to an SD card using the SD library.

  The circuit:
  SD card attached to SPI bus as follows:
** UNO:  MOSI - pin 11, MISO - pin 12, CLK - pin 13, CS - pin 4 (CS pin can be changed)
  and pin #10 (SS) must be an output
** Mega:  MOSI - pin 51, MISO - pin 50, CLK - pin 52, CS - pin 4 (CS pin can be changed)
  and pin #52 (SS) must be an output
** Leonardo: Connect to hardware SPI via the ICSP header
  Pin 4 used here for consistency with other Arduino examples

  created  24 Nov 2010
  modified 9 Apr 2012 by Tom Igoe

  This example code is in the public domain.



  // On the Ethernet Shield, CS is pin 4. Note that even if it's not
  // used as the CS pin, the hardware CS pin (10 on most Arduino boards,
  // 53 on the Mega) must be left as an output or the SD library
  // functions will not work.

*/


void initSD()
{
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; 
  }


  Serial.print("Initializing SD card...");

  pinMode(SS, OUTPUT);

  
  if (!SD.begin(3, 11, 12, 13)) {
    Serial.println("Card failed, or not present");
    
    while (1) ;
    return;
  }

  Serial.println("card initialized.");


  dataFile = SD.open("datalog.txt", FILE_WRITE);
  if (! dataFile) {
    Serial.println("error opening datalog.txt");

   while (1) ;
  }
}

void sdlog()
{

  dataFile.println(log());

  
  dataFile.flush();

}

TIME

void initTime()
{
  while (!Serial); // for Leonardo/Micro/Zero

  Serial.begin(9600);
  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }

  if (! rtc.isrunning()) {
    Serial.println("RTC is NOT running!");
 
    rtc.adjust(DateTime(2017,8,10,17,55,0));
  }

}

String data ()
{
  String data, anno, mese, giorno, ora, minuti;  //, secondi;
  DateTime now = rtc.now(); //recupero data e ora attuali

  anno = now.year();
  mese = now.month();
  giorno = now.day();
  ora = now.hour();
  minuti = now.minute();
  


  data = "";
  data = giorno + "/" + mese + "/" + anno + "," + ora + ":" + minuti; // + ":" + secondi;
  return data;
}

UMITEMP

String umitemp() {

  float temperature = 0;
  float humidity = 0;
  int err = SimpleDHTErrSuccess;
  if ((err = dht22.read2(pinDHT22, &temperature, &humidity, NULL)) != SimpleDHTErrSuccess) {
    Serial.print("Read DHT22 failed, err="); Serial.println(err);delay(2000);
    return;
  }
  
 

  String data = String (temperature) + "," + String (humidity) +"%";

  delay(2000);
  return data;
}

UMIDITA

//Verifica umidita

int umidita()
{
  int soil_hum_average = 0; // Variabile per la media di 5 misurazioni

  for (int i = 0; i < 5; i++)
  {
    unsigned long Timer = millis();
    digitalWrite(SoilPower, HIGH);     //Power ON soil sensor

    delay (500); //timer 0.5 secondi
    {
      soil_hum_average = soil_hum_average + analogRead(Soil);
      digitalWrite(SoilPower, LOW);      //Power OFF soil sensor


    }

  }

  soil_hum_average = soil_hum_average / 5; //media delle 5 misurazioni

  return soil_hum_average;
}

VASCA

//verifica vasca piena vuota

String vasca()
{

  int val = LOW; //varibile vasca piena vuota di default la vasca é vuota
  val = digitalRead(VascaPiena); //rilevamento conduttività nella vasca


  //verifica vasca vuota o piena

  if (val == HIGH ) //Se vasca é VUOTA led ON

  {
    digitalWrite(Wled, HIGH); //Red led ON
    digitalWrite(Relay, LOW); // Stop pump
    return "VUOTA";

  }

  else // Se vasca PIENA led OFF e 1
  {
    digitalWrite(Wled, LOW);//Red led OFF
    return "PIENA";
  }


}

E sopratutto GRAZIE

Beh intanto confermo, la file.println() non accetta mica solo String, ma (da documentazione) "char, byte, int, long, or string".
Quindi intanto dove possibile evita le String, e visto che ne fai un uso ampio direi che è uno dei candidati per l'anomalia che segnali.

docdoc:
Beh intanto confermo, la file.println() non accetta mica solo String, ma (da documentazione) "char, byte, int, long, or string".
Quindi intanto dove possibile evita le String, e visto che ne fai un uso ampio direi che è uno dei candidati per l'anomalia che segnali.

Nella funzione LOG recupero i valori di tutti i sensori formatto il testo e lo rendo disponibile alla funzione che li scrive sulla SD

Ma se non posso usare string che faccio converto tutto in char?

olometaboy:
Nella funzione LOG recupero i valori di tutti i sensori formatto il testo e lo rendo disponibile alla funzione che li scrive sulla SD
Ma se non posso usare string che faccio converto tutto in char?

Non necessariamente, ma comunque non char ma char* (o char).
Tu nella log() crei una sfilza di inutili variabili locali String che poi componi in un'altra temporanea da restituire: accumula invece tutto in una char che riempi con una sprintf() usando i vari valori che qui converti con String().
Essendo poi questa stringa solamente una variabile di buffer, o la passi dal chiamante (il puntatore) o te la definisci globalmente quindi la modifichi nella log() e poi nella printf() usi quella.

Tu nella log() crei una sfilza di inutili variabili locali String che poi componi in un'altra temporanea da restituire:

Le creo perché per qualche strano motivo non posso concatenare direttamente i vari output string delle funzioni senza prima rimetterli in delle variabili locali

accumula invece tutto in una char che riempi con una sprintf() usando i vari valori che qui converti con String().

I valori delle varie funzioni input sono tutti di tipo string

ho provato a modificare cosi il codice:

char* log()
{
char datalog[150];
sprintf(datalog,"%s,%s,%s,%s", data(),vasca(),umidita(),umitemp());

//Serial.println(datalog);
return datalog;
}

E ho il messagio di errore
cannot pass objects of non-trivially-copyable type 'class String' through '...'

Perché sprintf non accetta string ma solo char* allora ho convertito tutte gli output in char*

Ma possibile che nel 2017 ancora non esiste un metodo semplice per concatenare 4 pezzi di testo e metterli dentro una variabile senza far crashare arduino?

>olometaboy: Allora, chiariamo una cosa …

NON sei su un PC dove c’è un sistema operativo ed un “garbage collector”, sei su una piccola MCU con solo 2KBytes di SRAM, dove devi fare tutto tu e dove usare la classe “String”, a causa dell’allocazione e riallocazione dinamica della memoria, porta quasi sempre … a grossi problemi e sicuri mal di testa !!! :smiling_imp:

Impara invece ad usare le stringhe classiche del C … ovvero semplici array di char terminati dal carattere null (0x00) e le funzioni che trovi nella libreria standard (… che, oltretutto, è automaticamente inclusa dal IDE) AVR libc ed, in particolare, quanto è in <string.h>.

In <string.h> trovi TUTTO quello che serve per la completa manipolazione delle VERE stringhe del ‘C’ :slight_smile:

Guglielmo

In <string.h> trovi TUTTO quello che serve per la completa manipolazione delle VERE stringhe del ‘C’ :slight_smile:

Trovo ironico che il nome della libreria corrisponde alla funzione che mi viene sconsigliato di usare :slight_smile:

Impara invece ad usare le stringhe classiche del C … ovvero semplici array di char terminati dal carattere null (0x00) e le funzioni che trovi nella libreria standard

Non mi sembra di avere molta scelta :slight_smile: Comunque quando si deve lavorare con del testo string é piu facile da usare di char* non a caso le hanno inventate.

olometaboy:
Trovo ironico che il nome della libreria corrisponde alla funzione che mi viene sconsigliato di usare :slight_smile:

Vedo che confondi le cose …

string : sono le stringhe classiche del ‘C’, sempre esistite e fatte da un array di char terminato dal carattere 0x00

String : Classe del ‘C++’ con i suoi metodi, i suoi oggetti, ecc. ecc.

Come vedi NON c’è alcun’che di ironico ! :smiling_imp:

Guglielmo

*P.S.: Come sempre, quando si parla di C/C++ … le maiuscole e le minuscole fanno MOLTA differenza * :smiling_imp:

olometaboy:
I valori delle varie funzioni input sono tutti di tipo string

Ma ste funzioni scusami tanto, sono nel TUO codice, no? Quindi puoi sempre cambiarne la logica non ti pare?

E come fare te l'ho suggerito, forse non mi ero spiegato bene. Quindi se vuoi fare le cose semplici (sempre considerando che non sei su un PC octa core con giga di RAM... :wink: ) definisci per ogni tuo parametro una variabile globale, più una funzione per aggiornarla. Quando devi usarla la userai in una sprintf() per comporre una stringa (non String ma stringa ossia char*) temporanea che userai solo per scrivere il log.

Quindi io farei una cosa del tipo:

char buf[64]; // Buffer per il log (max 64 caratteri)
// --- VASCA
#define VUOTA 0
#define PIENA 1
int vasca = VUOTA; // Variabile globale
//verifica vasca piena vuota
void updateVasca()
{
  int val = LOW; //varibile vasca piena vuota di default la vasca é vuota
  val = digitalRead(VascaPiena); //rilevamento conduttività nella vasca
  //verifica vasca vuota o piena
  if (val == HIGH ) //Se vasca é VUOTA led ON
  {
    digitalWrite(Wled, HIGH); //Red led ON
    digitalWrite(Relay, LOW); // Stop pump
    vasca = VUOTA;
  }
  else // Se vasca PIENA led OFF e 1
  {
    digitalWrite(Wled, LOW);//Red led OFF
    vasca = PIENA;
  }
}
...

void sdlog()
{
  updateLog();
  dataFile.println(buf);
  dataFile.flush();
}

..e poi aggiorni la buf usando sprintf nella updateLog() (es. sprintf(buf,"%s,%d,%d eccetera)) a seconda del tipo di variabile globale che hai, %d per int o "%s" per char*, eccetera.
Il codice non ti cambia di tanto, ma mantieni una logica "minimale" adatta al nostro piccolo MCU perché più "snella" non ti pare?...

Ma possibile che nel 2017 ancora non esiste un metodo semplice per concatenare 4 pezzi di testo e metterli dentro una variabile senza far crashare arduino?

Come già ti hanno detto, la classe String è solo una "comodità" per programmi non molto grandi, per via della gestione della memoria che non è ottimale su un piccolo processore come quello di Arduino.

PS: le prossime volte includi il tuo sketch tutto insieme, senza dividerlo in quel modo, che per capire com'è fatto bisogna fare tanti copia/incolla scomodi: se vuoi una mano almeno non complicare le cose a chi ci vuole provare... :wink: Se vuoi puoi sempre marcare le sezioni con un bel commento con tanti trattini, ma tutti insieme!

Innanzi tutto grazie a tutti per i consigli

Io di documentazione sulla sprintf ne ho trovata molto poca ( quella ufficiale di arduino é quasi 0)

Io ho fatto cosi
ho modificata tutti gli output in char*
e per comporre il tutto ho fatto

char* log()
{
char datalog[150];
sprintf(datalog,"%s,%s,%s,%s", data(),vasca(),umidita(),umitemp());

//Serial.println(datalog);
return datalog;
}

E il log lo mando in scrittura sulla sd
ho compilato e non da errori
Ma puo funzionare???

/* Connesione pins:
 
Analog  A0  INPUT   Sensore umidità terreno YL-69
Digital D8  OUTPUT  Alimentazione ensore umidità terreno YL-69
Digital D10 INPUT   Sensore Vasca piena vuota
Digital D12 OUTPUT  Led vasca vuota
Digital D11 OUTPUT  Relay pompa
Digital D9  INPUT   DHT22 sensore temperatura e umidita aria

  
  
*/
//controllo memoria
#include "MemoryFree.h"

//Time
#include <Wire.h>
#include "RTClib.h"

//SD
#include <SPI.h>
#include <SD.h>

//Umi e tem aria
#include <SimpleDHT.h>


//set up  pin
#define Soil       6  
#define pinDHT22   2  
#define Relay      4  

#define VascaPiena 5  
#define Wled       6  
#define SoilPower  7  
//SD setup
const int chipSelect = 53;
File dataFile;

//Time setup
RTC_DS1307 rtc;

//Umi e tem aria
//int pinDHT22 = 22; //      DATA: 2
SimpleDHT22 dht22;

//irrigazione
int irri = 0;
//Inizializzazione della varibile per eseguire le azioni ogni tot tempo
unsigned long previousMillis0 = 0;
unsigned long previousMillis1 = 0;
void setup() {

  Serial.begin(9600);



  //Umidità
  pinMode(Soil, INPUT);       
  pinMode(SoilPower, OUTPUT);  *UMIDITA*

  //Vasca
  pinMode(VascaPiena, INPUT); //Gallegiante vasca *VASCA*
  pinMode(Wled, OUTPUT);      //Led vasca vuota *VASCA*

  //Irrigazione
  pinMode(Relay, OUTPUT);    //Relay accensione pompa *VASCA* *IRRIGAZIONE*
  digitalWrite(Relay, LOW); // Inizalizzazione pompa spenta relay is OFF when HIGH and ON when LOW
  

  initSD();
  initTime();

}
=======================================
void loop()
{

  unsigned long currentMillis = millis();


   if (currentMillis - previousMillis0  >= 7200000) //verifica se necessario irrigare ogni 2 ora 7200000ms
  //if (currentMillis - previousMillis0  >= 20000) // per test
  {
    previousMillis0 = currentMillis;

    if ((vasca() == "PIENA") && (umidita() >= 600)) //se vasca piena e umidita terreno superore a 600 innafia
    {
      irrigazione();
      //Serial.println("*** TERENO SECCO ***");
      //Serial.println(umidita());
    }
    else if (umidita() < 370)
    {
      //Serial.println("*** TERENO UMIDO ***");
     // Serial.println(umidita());
    }

    if (vasca() == "VUOTA")
    {
      //Serial.println("*** VASCA VUOTA ***");
    }


  }



   if (currentMillis - previousMillis1 >= 3600000) // crea un log ogni 1 ora 3600000ms  (10 minuti 600000ms)
 // if (currentMillis - previousMillis1 >= 10000) //per test
  {

    //Serial.println("CREAZIONE LOG");
    //Serial.println(log());
    previousMillis1 = currentMillis;
    sdlog(); //Esegue data vasca e umidita tramite log e le scrive sulla SD
    //Serial.println("LOG CREATO");
  }

}

=========================================


void irrigazione()
{

  if (vasca() == "VUOTA")
  {
    irri = 0;
  }
  else
  {
    irri = irri + 1; //contatore numero di irrigazioni
  }

  //Serial.println("IRRIGAZIONE IN CORSO");
  digitalWrite(Relay, HIGH);      // Turns ON puump

  delay (15000); //annafia per 15 secondi

  digitalWrite(Relay, LOW);     // Turns OFF pump
  //Serial.print("IRRIGAZIONE ");
  //Serial.print(irri);
  //Serial.println(" EFFETUATA");

  sdlog(); //Esegue data vasca e umidita tramite log e le scrive sulla SD
  dataFile.print(log());
  dataFile.print(",IRRIGAZIONE ");
  dataFile.print(irri);
  dataFile.println(" EFFETUATA,");


.
  dataFile.flush();
}
==================================
char* log()
{
char datalog[150];
sprintf(datalog,"%s,%s,%s,%s", data(),vasca(),umidita(),umitemp());

//Serial.println(datalog);
return datalog;
}
========================================

void initSD()
{
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }


  Serial.print("Initializing SD card...");

  pinMode(SS, OUTPUT);

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

  Serial.println("card initialized.");

  // Open up the file we're going to log to!
  dataFile = SD.open("datalog.txt", FILE_WRITE);
  if (! dataFile) {
    Serial.println("error opening datalog.txt");
    // Wait forever since we cant write data
   while (1) ;
  }
}

void sdlog()
{

  dataFile.println(log());

 
  dataFile.flush();

}
========================================================

void initTime()
{
  while (!Serial); // for Leonardo/Micro/Zero

  Serial.begin(9600);
  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }

  if (! rtc.isrunning()) {
    Serial.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
    //rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    rtc.adjust(DateTime(2017,8,10,17,55,0));
  }

}

char* data ()
{
  String data, anno, mese, giorno, ora, minuti;  //, secondi;
  DateTime now = rtc.now(); //recupero data e ora attuali

  anno = now.year();
  mese = now.month();
  giorno = now.day();
  ora = now.hour();
  minuti = now.minute();
  //secondi = now.second();


  char* dataout = "";
  data = giorno + "/" + mese + "/" + anno + "," + ora + ":" + minuti; // + ":" + secondi;
  return dataout;
}
=======================================================

char* umitemp() {

// start working...

  //Serial.println("Sample DHT22...");
  
  // read without samples.
  // @remark We use read2 to get a float data, such as 10.1*C
  //    if user doesn't care about the accurate data, use read to get a byte data, such as 10*C.
  float temperature = 0;
  float humidity = 0;
  int err = SimpleDHTErrSuccess;
  if ((err = dht22.read2(pinDHT22, &temperature, &humidity, NULL)) != SimpleDHTErrSuccess) {
    Serial.print("Read DHT22 failed, err="); Serial.println(err);delay(2000);
    return;
  }
  
 // Serial.print("Sample OK: ");
 // Serial.print((float)temperature); Serial.print(" *C, ");
//  Serial.print((float)humidity); Serial.println(" RH%");

String   data = String (temperature) + "," + String (humidity) +"%";
  // DHT22 sampling rate is 0.5HZ.
  char copy[15];
  delay(2000);
  data.toCharArray(copy, 15);
  return copy; 
}
=====================================================

char* umidita()
{
  int soil_hum_average = 0; // Variabile per la media di 5 misurazioni

  for (int i = 0; i < 5; i++)
  {
    unsigned long Timer = millis();
    digitalWrite(SoilPower, HIGH);     //Power ON soil sensor

    delay (500); //timer 0.5 secondi
    {
      soil_hum_average = soil_hum_average + analogRead(Soil);
      digitalWrite(SoilPower, LOW);      //Power OFF soil sensor


    }

  }

  soil_hum_average = soil_hum_average / 5; //media delle 5 misurazioni
  //Serial.print("umidita ");
 // Serial.println(soil_hum_average);
  return soil_hum_average;
}


======================================================
//verifica vasca piena vuota

char* vasca()
{

  int val = LOW; //varibile vasca piena vuota di default la vasca é vuota
  val = digitalRead(VascaPiena); //rilevamento conduttività nella vasca


  //verifica vasca vuota o piena

  if (val == HIGH ) //Se vasca é VUOTA led ON

  {
    digitalWrite(Wled, HIGH); //Red led ON
    digitalWrite(Relay, LOW); // Stop pump
    return "VUOTA";

  }

  else // Se vasca PIENA led OFF e 1
  {
    digitalWrite(Wled, LOW);//Red led OFF
    return "PIENA";
  }

}

No. Una variabile char* è solo un PUNTATORE ad una zona di memoria dove è presente una stringa (singoli char terminati con 0x00), quindi la memoria devi allocarla per poterla usare, in genere si può fare dichiarandola ad esempio come “char miavar[50];” dove indichi la dimensione massima della stringa (compreso il 0x00 quindi puoi memorizzare fino a 49 caratteri)
Vedi il codice di esempio che ti ho scritto, con quello aggiri il problema di restituire char* usando variabili pubbliche, provalo e facci sapere.

olometaboy:
Io di documentazione sulla sprintf ne ho trovata molto poca ( quella ufficiale di arduino é quasi 0)

La sprintf() è del C/C++, di documentazione ne trovi a tonnellate dal K&R in poi... :wink:
Comunque ricorda solo che l'implementazione su Arduino non è completa, ad esempio non prevede "%f" ossia la formattazione dei float, per questi valori devi prima usare la dtostrf() per convertirli in stringa in una variabile buffer (occhio, stringa ossia char, e NON String...) e poi usare il buffer così creato dentro la sprintf() come "%s".
Spero di averti chiarito e non confuso le idee... :wink:

docdoc:
La sprintf() è del C/C++, di documentazione ne trovi a tonnellate dal K&R in poi... :wink:
Comunque ricorda solo che l'implementazione su Arduino non è completa, ad esempio non prevede "%f" ossia la formattazione dei float, per questi valori devi prima usare la dtostrf() per convertirli in stringa in una variabile buffer (occhio, stringa ossia char, e NON String...) e poi usare il buffer così creato dentro la sprintf() come "%s".
Spero di averti chiarito e non confuso le idee... :wink:

Non vorrei sbilanciarmi troppo ma mi sembra che velatamente mi stai dicendo che é un casino?

Io devo fare una cosina semplice prendere 4 variabili di diverso tipo incollarle insieme separate da una virgola e scriverle su una sd

Tralasciamo la parte di scrittura sd che funziona.

Io ho umiditaSuolo che é INT
UmiditaeTempAria String (da modificare in char)
Data String (da modificare in char)
Vasca String (da modificare in char)

Prendiamo la funzione Vasca

Tu mi consigli di "definisci per ogni tuo parametro una variabile globale, più una funzione per aggiornarla"

Ho cercato e posso semplificarmi la vita usando static char

Char* vasca()
{

static char Piena[6];

static char Vuota[6];

  if (digitalRead(VascaPiena)== HIGH ) //Se vasca é VUOTA 

  {

    return Vuota;

  }

  else // Se vasca PIENA led OFF
  {
 
    return Piena;
  }

}

Questo dovrebbe funzionare

Il problema diventa piu complesso con la data
il formato é gg/mm/aa,hh:mm sono 14 caratteri 15 con il null

Char* data ()
{

  Static Char [15] Data; //qui voglio metterci la data é l'ora corretamente formattati
  Static Char [3] anno, mese, giorno, ora, minuti;  // 
  DateTime now = rtc.now(); //recupero data e ora attuali

  anno = now.year();
  mese = now.month();
  giorno = now.day();
  ora = now.hour();
  minuti = now.minute();

VEDERE SOTTO
data = giorno + "/" + mese + "/" + anno + "," + ora + ":" + minuti; // + ":" + secondi;

  return data;
}

Per concatenare le char se non ho capito male devo usare sprintf()
Dunque una cosa cosi dovrebbe andare bene

sprintf(Data,"%s/%s/%s,%s:%s", anno, mese, giorno, ora, minuti);

Spero di averci capito qualcosa.
Grazie ancora per il sostegno
PS
non ti preoccupare di confondermi le idee perché al punto in cui sono ogni modifica alle stesse genererebbe un loro riordino