errore generato da semplice introduzione di righe di codice NON eseguito

Salve,
ho scritto un programma che usa un server per rendere disponibili dati quando ci si connette; un’altra sezione di programma funziona da client per acquisire epoch (NTP). Funziona. Se però aggiungo altro codice per la funzione client mail (già testata e funzionante per conto suo), il programma si blocca. Si può pensare ad errori vari nella subroutine, ma ho provato ad eliminare le chiamate alla subroutine di posta e l’errore c’è ugualmente ! Mi sembra impossibile che la semplice compilazione di codice NON usato possa creare problemi di esecuzione, ma è cosi : non si avvia nemmeno la fase iniziale dell’acquisizione dell’indirizzo IP (DHCP). Sono rimasto basito, ma oggi mi capita che semplicemente inserendo una variabile stringa <String mesiArray[12]= {“dic”,“nov”," …",“gen”};> in un altro programma funzionante, la SD mi dà messaggio d’errore in :
File dataFile = SD.open(“dati.txt”, FILE_WRITE);

     if (dataFile)
     {
      String linea ("Anno ");
      linea=linea+(anno);
      linea=linea+ mesiArray[indMese];
      linea=linea+(Sec1970/86400L);
      dataFile.println(linea);
      dataFile.close();
      Serial.println(linea);
     }  
     else Serial.println("errore in apertura di dati.txt");

mentre se cancello la stringa mesiArray, la stessa sub funziona senza errori:
    File dataFile = SD.open("dati.txt", FILE_WRITE);
     if (dataFile)
     {
      String linea ("Anno ");
      linea=linea+(anno);
      linea=linea+ mese;
      linea=linea+(Sec1970/86400L);
      dataFile.println(linea);
      dataFile.close();
      Serial.println(linea);
     }  
     else Serial.println("errore in apertura di dati.txt");

La cosa davvero strana è che anche in questo caso, il semplice inserimento della stringa meseArray[12], mai usata, causa l’errore.

Uso Arduino da poco, vero, ma non avrei mai pensato che il semplice inserimento di dati o codice non usato portasse a modifiche nell’esecuzione di un programma.

Qualcuno ha una spiegazione ??

Molte grazie per la pazienza di essere arrivati a a leggere tutto.
Dritan

Secondo me é un problema di RAM. Stai usando di piú di quella disponbile e sovvrascrivi delle variablil di sistema.
Non é necessario che prima fai una stringa e poi la stampi. stampa subilo e usa la macro F() se stampi dei testi.

 if (dataFile)
     {
      dataFile.print(F("Anno "));
      dataFile.print(anno);
      dataFile.print(mese);
      dataFile.print(Sec1970/86400L);
      dataFile.close();
      Serial.print(F("Anno "));
      Serial.print(anno);
      Serial.print(mese);
      Serial.print(Sec1970/86400L);
     }

USa la makro F() in tutte le stampe perché cosí il testo non viene portato in RAM prima di essere stampato.

Ciao Uwe

uwefed:
Secondo me é un problema di RAM.

Concordo.

Non hai specificato di quale arduino parli, non hai postato lo sketck completo, non ti si può suggerire dove risparmiare ram.
Non ti sei presentato, ma qui passerà presto nid69ita a fartelo notare, è il suo mestiere ormai XD

ciao

pablos:
Non ti sei presentato

Già, ma ormai è diventato di second'ordine...

pablos:
Non ti sei presentato, ma qui passerà presto nid69ita a fartelo notare, è il suo mestiere ormai XD

:grin: :grin:

Qualche link utile del forum:

dritan:
P.S. che vuol dire che non mi sono presentato ?

Questo:
Ti invitiamo a presentarti qui: http://forum.arduino.cc/index.php?topic=113640.0
e a leggere il regolamento: http://forum.arduino.cc/index.php?topic=149082.0

:grin:

dritan:
Sono un neofita, lo ripeto, ma pensavo che l’inserimento di variabili non usate finisse …

Che cosa intendi per non usate?
Se non sono usate il compilatore è intelligente e le scarta.
Nel tuo pezzo di codice (manca almeno la parte delle dichiarazioni) tu hai:

linea=linea+ mesiArray[indMese]

quindi l’array lo usi. Poi che il programma non passi mai da li il compilatore non può saperlo.
Una variabile non usata ad esempio dichiari int x; in una funzione e poi non la usi mai.

Hai letto il regolamento, ma male :grin:
Il codice devi metterlo negli appositi tag code, vedi sezione 7 spiega come fare.
Non è solo una fissazione o mania. Se il codice non è nei tag code, alcune parti del testo possono essere interpretate come parte di html e quindi una parte del codice non viene visualizzato.

Visto che ci dai solo pezzettini i consigli che posso datri sono incompleti.
Non usare goto; non serve in C.
Non usare stringhe perché vengono gestite male; usa dei array.
Stiamo usando il linguaggio C e non basic. C non ha un tipo di variabile string come altri linguaggi di programmazione. C é strutturato in modo che in 100% dei casi non serve un goto e in 99,9999% non semplifica il codice.

Ciao Uwe

... la prossima volta userò il tag "code".

dunque dunque,

ho provato a scrivere sull'SD usando la macro F() ma non cambiava niente.
Poi ho cancellato qualunque stampa di debug > COM e il programma girava
"nonostante" l'array.
Devo concludere che era un problema di RAM insufficiente come dicevate, ma forse mi aspettavo
che il compilatore mi avvertisse non solo di essere fuori Eprom ma anche fuori RAM.
Dopotutto è solo una Arduino Uno.
Avrei dovuto eseguire un controllo sulla RAM disponibile durante l'esecuzione.

Direi che, molto probabilmente, anche il blocco del programma di mail server, NTP e mail client
va fuori RAM. Verificherò.

Grazie per avermi messo sulla strada.

Se avrò problemi di programmazione in futuro, so cosa aspettarmi.
Direi RISOLTO.
Dritan

P.S.
quel codice pieno di "go to" è orribile da vedere, ma l'ho scritto per verificare,
e il programma nell'insieme funzionava,
il codice "giusto" è quello che vedi dopo, solo poche righe con uso di array.
Potrei usare return o break, ma praticamente, dopo tanti anni, sto iniziando da zero.
Ciao Uwe

Se hai risolto buon per te, ma ci sono funzioni da 5-10 righe di codice che ricavano giorno.mese.anno da un epoch senza quel po po di roba if else goto ecc ecc a partire dal 1970

ciao

Della funzione F() c'è scritto nella doc ufficiale:

You can pass flash-memory based strings to Serial.print() by wrapping them with F(). For example :

Serial.print(F(“Hello World”))

(fonte: Serial.print() - Arduino Reference)

Per quanto riguarda il goto, più che di "esempi senza goto" va studiata la programmazione strutturata :wink:

// Sec2010 sono i secondi rimasti nell'anno in corso
// giorniMese[] è const array di secondi da scalare per ogni mese {28857600,26265600,..}
// mesiArray[] contiene il nome dei mesi  {" dicembre"," novembre" ...}
// iM e l'indice mese

 for (iM=0;;iM++)
 {
  if (Sec2010 > giorniMese[iM])
  {
   Sec2010 = Sec2010 - giorniMese[iM];
   if (iM==10 && feb29) Sec2010 = Sec2010 - SecGiorno;
   goto finm;
  }
 }
 iM=11;  
 finm:
 Serial.println(mesiArray[iM]);

Il codice é troppo breve / tagliato per poter prenderlo come esempio.
In linea di massima crei una funzione che stampa sulla seriale e la chiami al posto del goto. Dal pezzetino non risulta come prosegue lo sketch.

Ciao Uwe

dritan:
Visto che ho un problema nel far funzionare insieme un programma che fa da server e client perché,
nonostante rimanga nei 32 Kb, probabilmente va a sovrascrivere la Ram (a proposito,
esiste qualcosa tipo malloc e free per Arduino ?), mi piacerebbe vedere come compattare il codice.

Esistono, ci sono i comandi "new" e "free" ma ti sconsiglio di usarli perché su MCU ad 8 bit con limitati quantitativi di RAM puoi frammentare la memoria in pochissimo tempo ed arrivare facilmente a problemi di errori nell'esecuzione e/o crash del programma.

In qualche caso ho provato ad usare PROGMEM per gli array invariabili : risultato imprevedibile.
Invece dichiarandoli "const" tutto OK.

Se usi PROGMEM devi poi recuperare i dati in determinate maniere, perché l'architettura Harvard non permette di accedere ai dati in Flash come si farebbe con quelli in RAM.

http://www.nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html

C'è modo di ottimizzare per ridurrre non solo l'uso della RAM ma anche quello della Eprom/Flash ?

Intanto usa la funzione F() per le stringhe costanti, ad esempio:

if (!Ethernet.begin(mac))Serial.println("no Ethernet DHCP");
 else Serial.println("DHCP Ok");

diventa:

if (!Ethernet.begin(mac))Serial.println(F("no Ethernet DHCP"));
 else Serial.println(F("DHCP Ok"));

Nel programma, un pò più complesso, che fa da server per dati remoti, fa da client per associare l'orario NTP ai dati, e farebbe da client mail per trasmetterli comunque ad intervalli regolari, l'aggiunta della routine di posta, che pure funziona bene da sola, fa bloccare il programma.

Facile che sia esaurita la RAM.

dritan:
Il tuo consiglio su macro F() l'ho provato; era la prima cosa da fare se ne fossi stato a conoscenza, ed è stato anche il primo suggerimento dato alla mia domanda iniziale da Uwe.

E' vero che il Reference è stringato però queste info ci sono:

You can pass flash-memory based strings to Serial.print() by wrapping them with F(). For example :

    Serial.print(F(“Hello World”))

Una domanda per risparmiare RAM (senza macro F() ed EEprom):

tolgo gli array e gran parte delle variabili dalla dichiarazione globale,
fraziono il main() in diverse sub() dove vengono dichiarate le variabili;
ogni sub() riceve e passa solo gli argomenti che servono, liberando la RAM
all'uscita : è una cosa che funziona ?

Ciao,
Dritan

Non sempre. Spesso risparmi di più con le variabili globali.

ti ripeto, non c'è bisogno che usi quella pappardella di roba per calcolare mese, anno, giorno, bisestile ecc cè la libreria rtc o swrtc che fa tutto con pochi passaggi
In secondo luogo non chiedere al server NTP l'orario ogni 7 secondi, primo perchè è inutile, secondo perchè bannerà il tuo IP e non potrai più accedere a quel server in futuro dovrai trovartene un altro, quando lo chiedi ogni 24h è più che sufficiente.

le variabili che gestiscono le chiamate sul server NTP non sono necessarie globali, le puoi mettere dentro i void.

ciao

dritan:
@pablos per l'orario :
non pensavo che una richiesta NTP al minuto potesse portare a finire in blacklist, comunque ho seguito il consiglio e chiedo NTP solo al setup; poi uso millis().

Oppure anche allineare l'orario una volta ogni X ore.