Riduzione memoria occupata programma

Ciao a tutti !
Ho realizzato un programma che mi permette di azionare il mio condizionatore da remoto, sfruttando la connessione di Internet di casa. Il funzionamento del programma è abbastanza semplice, tuttavia ho un problema di occupazione di memoria. Ecco il programma:

#include <Ethernet.h>
#include <SPI.h>
#include <WebServer.h> 
#include "IRremote.h"


IRsend irsend;
int khz=38; //NB Change this default value as neccessary to the correct modulation frequency
// ON and 2O C° with 1 FAN heat
unsigned heat[] = {3000,3000,3000,4400,550,1600,600,550,550,1650,550,550,550,550,550,1650,550,550,550,1650,500,550,550,1650,550,550,550,500,600,500,600,550,550,550,550,1650,500,550,550,600,500,1700,500,550,550,550,550,550,550,600,500,550,550,550,550,550,550,550,550,1650,550,1650,550,1650,500,1650,550,1650,550,550,550,550,550,550,550,550,550,1650,550,1650,550,500,550,550,550,1700,500,1650,550,550,550,500,600,550,550,550,550,550,550,550,550,550,550,1650,500,1700,500,550,550,550,550,550,550,550,550,550,550,600,500,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,1650,550,500,550,1700,500,550,550,550,550,550,550,1650,550};
// OFF the A/C
unsigned OFF[] = {3100,2900,2950,4400,700,1500,700,400,700,1500,700,400,650,450,550,1650,550,550,650,1500,600,500,600,1600,600,500,600,500,600,450,650,450,600,550,550,550,550,550,550,600,500,1600,600,500,600,500,600,550,550,500,600,500,600,550,550,550,550,1600,600,500,600,500,600,500,550,1650,550,1600,600,500,600,500,600,550,550,550,550,1600,600,1600,550,550,550,550,550,1650,550,1600,600,550,550,500,600,500,600,550,550,550,550,500,600,500,600,1600,600,1600,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,500,600,550,550,550,550,500,600,500,600,500,600,1600,600,500,600,1600,550,550,550,1600,600,550,550,550,550};
// ON and 23° with 2 FAN cold
unsigned cold[] = {3050,3000,3000,4400,550,1600,600,550,550,1650,550,550,550,550,550,1650,550,500,600,1600,550,550,550,1650,550,1650,550,1650,550,550,550,550,550,500,600,1600,550,550,550,550,550,1650,550,550,550,550,550,550,550,550,550,550,550,550,550,500,600,1650,500,550,550,600,500,1700,500,550,550,550,550,550,550,550,550,550,550,550,550,1650,550,1650,550,550,550,500,550,1650,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,1650,550,550,550,550,550,550,550,550,550,500,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,1650,550,1600,600,550,550};

 static byte mac_Add[] = {
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
WebServer webserver("", 80);
String state = "off"; 

void Start(WebServer &server, WebServer::ConnectionType type,
           char *url_param, bool param_complete)
{
  server.httpSuccess();
  if (type != WebServer::HEAD)
  {
    String s = "";
 
     if (param_complete == true)
    {
      s = url_param;
 
      if ( s == "cold")
      {
        Serial.println("cold");
        state = "cold";
        irsend.sendRaw(cold, sizeof(cold)/sizeof(int), khz); 
      }
     
 
      if ( s == "warm")
      {
        Serial.println("warm");
        state = "warm";
        irsend.sendRaw(heat, sizeof(heat)/sizeof(int), khz); 

      }
     
 
      if ( s == "off")
      {
        Serial.println("off");
        state = "off";
        irsend.sendRaw(OFF, sizeof(OFF)/sizeof(int), khz); 
      }
      
    }
 
    // web page
server.print(
"<html><head><meta name='viewport' content='width=200px'/></head><body>"
"<h1>A/C Arduino Remote Controller Page!</h1>");

if(state=="off"){
  server.print("<h2>Stato AC : off </h2>");
}
if(state=="cold"){
  server.print("<h2>Stato AC : condizionatore </h2>");
}
if(state=="warm"){
  server.print("<h2>Stato AC : pompa di calore </h2>");
}
server.println("<h1> </h1>
");
server.println("<a href='/?cold'><img src='http://ismanettoneblog.altervista.org/blog/wp-content/uploads/2014/02/cold.png'>""<a href='/?warm'><img src='http://ismanettoneblog.altervista.org/blog/wp-content/uploads/2014/02/warm.jpg'>
"
"<a href='/?off'><img src='http://ismanettoneblog.altervista.org/blog/wp-content/uploads/2014/02/off.png'>");

   
 
  }
}

 void setup()
{
  Ethernet.begin(mac_Add);
  webserver.setDefaultCommand(&Start);
  webserver.addCommand("index.htm", &Start);
  Serial.begin(9600);
  webserver.begin();
 
  delay(100);
}
 
void loop()
{
 webserver.processConnection();
}

Avete qualche consiglio per aumentare lo spazio disponibile ? Sto utilizzando Arduino Uno

Prova a mettere F() ad ogni print:

server.print( F("<h2>Stato AC : off </h2>") );

C'è poco da ridurre, stai usando librerie pesanti,
Quanto ti occupa di flash e di ram ? (Con ide 1.5 vedi entrambi i valori durante la compilazione)

Un'altra cosa per ridurre è rinunciare a oggetti String e usare le stringhe C (vettori di caratteri null terminati)

Testato:
Quanto ti occupa di flash e di ram ? (Con ide 1.5 vedi entrambi i valori durante la compilazione)

Senza scomodare la 1.5 .. che è in beta perenne e che cambia un giorno si e l'altro pure ... ]:smiley:

QUI come fare :wink:

Guglielmo

Grazie a tutti per le risposte.
Ho leggermente migliorato la situazione, facendo server.print(F(....)), ma occupo il seguente spazio:
Arduino:1.5.5 (Mac OS X), Scheda:"Arduino Uno"

Lo sketch usa 22.472 byte (69%) dello spazio disponibile per i programmi. Il massimo è 32.256 byte.
Le variabili globali usano 2.361 byte (115%) di memoria dinamica, lasciando -313 byte liberi per le variabili locali. Il massimo è 2.048 byte.
processing.app.debug.RunnerException: Memoria esaurita; guarda http://www.arduino.cc/en/Guide/Troubleshooting#size per consigli su come ridurne l'utilizzo.
at processing.app.Sketch.size(Sketch.java:1633)
at processing.app.Sketch.build(Sketch.java:1543)
at processing.app.Sketch.build(Sketch.java:1521)
at processing.app.Editor$DefaultRunHandler.run(Editor.java:1915)
at java.lang.Thread.run(Thread.java:695)

Questo report potrebbe essere più ricco
di informazioni con
"Mostra un output dettagliato durante la compilazione"
abilitato in "File > Impostazioni"

Voi dite che lo spazio è occupato maggiormente da String ? Secondo me lo spazio maggiormente occupato è per la funzione di inviare i segnali IR.

jackbell16:
Voi dite che lo spazio è occupato maggiormente da String ? Secondo me lo spazio maggiormente occupato è per la funzione di inviare i segnali IR.

Se Tu sai le cose meglio perché ci chiedi?
Ciao Uwe

jackbell16:
Voi dite che lo spazio è occupato maggiormente da String ? Secondo me lo spazio maggiormente occupato è per la funzione di inviare i segnali IR.

Non ho detto questo. La IRRemote occupa molto, ma do per scontato che non la puoi eliminare. Mentre la classe String si può ovviare usando le stringhe classiche. Poi tu stai calcolando lo spazio usato di memoria in fase di compilazione, ma la classe String alloca spazio a runtime (internamente usa malloc) e se il programma alloca/dealloca (e lo fai) delle String, è possibile che dopo un pò di tempo la memoria è frammentata e la malloc() fallisce. Il C++ non ha garbage collection come Java.

Hai tutti quei vettori di interi, all'inizio. Ogni intero occupa 2 byte in Ram.
Dovresti portare tutto in Flash con Progmem e poi recuperare i dati da lì, altrimenti non ne esci

uwefed:

jackbell16:
Voi dite che lo spazio è occupato maggiormente da String ? Secondo me lo spazio maggiormente occupato è per la funzione di inviare i segnali IR.

Se Tu sai le cose meglio perché ci chiedi?
Ciao Uwe

Ho visto che il grosso del peso, nasce dall'inclusione della libreria IRemote e sopratutto l'uso della funziona per l'invio del segnale

leo72:
Hai tutti quei vettori di interi, all'inizio. Ogni intero occupa 2 byte in Ram.
Dovresti portare tutto in Flash con Progmem e poi recuperare i dati da lì, altrimenti non ne esci

Grazie per il consiglio. In pratica tu mi suggerisci di caricare tutti i dati nella memoria Flash e recuperare di volta in volta i dati, solo quando necessari, giusto ? Potresti fare un esempio (in codice). Grazie in anticipo

Qui trovi un pò di info:

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

Potresti provare a farti una tua versione di IRRemote "dimagrita".
Forse non è necessario in quanto il compilatore ottimizza. Tu usi solo la sendRaw, mentre dentro la libreria (la classe) ci sono anche instruzioni come sendNec, e altre che non ti servono.

Nid, hai visto quegli array ad inizio sketch?

leo72:
Nid, hai visto quegli array ad inizio sketch?

Si, su quello DEVE fare come hai detto tu. Poi il mio suggerimento è un di più. :wink:

i tre array di int occupano 0,9kB di Ram, quindi spostandoli tutti in flash dovresti risolvere

Mi chiedevo, visto che nel contarli ho notato che tantissimi valori sono uguali:

  • mettiamo ad esempio che il numero 500 appare 100 volte gia' solo nel primo array, il micro, la ram, l'architettura (si nota che mi sto' arrampicando sugli specchi :)) non potrebbe essere "lazy" ed occupare solo lo spazio di un int ?
    Se nella risposta evitate parole di grilliana memoria ne sarei grato :grin:

Quindi avresti 3 array, di cui uno con 100 celle in meno perché il valore 500 compare appunto tante volte... più un altro array di 100 celle in cui metti le posizioni del valore 500 nell'altro array... :stuck_out_tongue_closed_eyes: ]:smiley:

se ho capito quindi non c'e' possibilita' di "fregare" la gestione della Ram, se un array necessita di 200 locazioni di memoria, sia che essi debbano contenere valori diversi, sia che debba contenere valori uguali, sempre quella quantita' di spazio serve.
Anche con Progmem immagino sia cosi', occupo flash rispetto a ram, ma sempre tutto lo spazio serve (se ricordo bene ne serve anche di piu' perche' progmem stesso e la sua gestione occupa flash che in ram non occuperebbe, pero' logicamente se in flash c'e' spazio che occupi di piu' non interessa)

grazie per esserti moderato :slight_smile:

Beh, io sono convinto che in quell'array, a parte i primi numeri, per il resto sono i tempi del segnale, MARK e UNMARK ovvero 1 e 0.
Quindi secondo me tutti i valori potrebbero essere "normalizzati" a soli 2 valori.
Sapendo quali sono questi valori, allora invece di un array, potresti sfruttare i bit di ogni byte o int dove 1 indica MARK e 0 UNMARK. Riduci l'array di 8 o 16 volte. Il numero di bit può essere non divisibile 8 o 16.
Naturalmente un array del genere NON lo passi alla sendRAW, bisogna farsi una propria sendRAW che accetti questo vettore in cui i bit sono significativi e 2 parametri per le 2 cifre MARK/UNMARK. Non semplice ma si potrebbe fare (avendone voglia e pazienza di provare) :grin:

Sì, sapendo cosa c'è negli array uno può provare ad otimizzarne il contenuto.

Al massimo si può anche pensare di arrivare a salvare un pò di dati in EEPROM e di leggerli da lì, sono 1024 celle che quasi nessuno usa e che stanno lì a far la muffa :wink: