Libreria IRsend e NEC (comandare climatizzatori)

Rieccomi … Ho un po di problemini con l’allocazione della memoria, tutti questi array di interi mi riempiono la memoria dinamica lasciandomi solo 100 byte (in questa configurazione)
Se tolgo i commenti che ho messo… la sforo alla grande,

Secondo voi c’è un modo più smart e meno avido di risorse per fare la stessa cosa?
Ecco il codice che ho scritto.

#include <IRremote.h>
IRsend irsend;

unsigned int CALDO16[74] = {
  8950,4400,650,500,650,550,650,1650,600,1700,650,500,650,550,650,500,650,550,600,550,650,550,600,600,600,550,650,550,600,550,650,500,650,550,650,500,650,550,650,500,650,550,650,550,650,500,650,550,650,500,650,550,650,550,600,550,650,550,650,1600,650,550,650,1650,650,500,650,550,650,1650,600,550,650,};
unsigned int CALDO17[74] = {
  8900,4450,600,550,650,550,650,1600,650,1650,650,550,650,500,650,550,600,600,600,1650,650,550,650,500,650,550,650,500,650,550,650,550,650,500,650,550,650,500,650,550,650,500,650,550,600,550,650,550,650,550,600,550,650,550,600,550,650,550,600,1650,650,550,650,1650,600,550,650,450,750,1600,650,550,650,};
unsigned int CALDO18[74] = {
  8900,4400,650,550,650,500,650,1650,650,1650,650,550,600,550,650,550,600,550,650,550,600,1650,650,550,650,550,600,550,650,550,650,500,650,550,650,500,650,550,650,550,650,500,650,550,600,550,650,550,600,550,650,550,600,550,650,550,650,550,600,1650,650,550,650,1600,650,550,650,500,650,1650,650,550,650,};
unsigned int CALDO19[74] = {
  8900,4400,650,550,650,550,600,1650,650,1650,650,550,650,500,650,550,600,550,650,1650,650,1650,650,500,650,550,650,500,650,550,650,500,650,550,650,550,600,550,650,550,650,500,650,550,650,500,650,550,650,500,650,550,650,550,650,500,650,550,650,1600,650,550,650,1600,650,550,650,550,650,1600,650,550,650,};
unsigned int CALDO20[74] = {
  8900,4400,650,550,650,550,650,1600,650,1650,650,550,650,500,650,550,600,550,650,550,600,600,600,1650,650,550,650,500,650,550,650,500,650,550,650,550,600,550,650,550,650,500,650,550,600,550,650,550,600,600,600,550,600,600,600,550,650,550,600,1650,650,550,650,1600,650,550,650,550,650,1600,650,550,650,};
unsigned int CALDO21[74] = {
  8900,4400,650,550,650,550,650,1600,650,1650,650,550,650,500,650,550,600,550,650,1650,650,550,650,1600,650,550,650,500,650,550,650,500,650,550,650,550,600,550,650,550,650,500,650,550,650,500,650,550,650,550,600,550,650,550,600,550,650,550,650,1600,650,550,650,1600,650,550,650,550,650,1600,650,550,650,};
unsigned int CALDO22[74] = {
  8950,4400,650,500,650,550,650,1600,650,1700,650,500,650,550,650,500,650,550,600,550,650,1650,650,1600,650,550,650,550,650,500,650,550,650,500,650,550,650,500,650,550,650,550,600,550,650,550,650,500,650,550,650,500,650,550,650,550,600,550,650,1650,650,500,650,1650,650,500,650,550,650,1600,650,550,650,};
unsigned int CALDO23[74] = {
  8900,4400,650,550,650,550,650,1600,650,1650,650,550,650,500,650,550,600,550,650,1650,650,1650,600,1650,650,550,650,500,650,550,650,500,650,550,650,550,600,550,650,550,650,500,650,550,650,500,650,550,650,500,650,550,650,550,650,500,650,550,650,1600,650,550,650,1650,600,550,650,550,650,1650,650,500,650,};
unsigned int CALDO24[74] = {
  8900,4400,650,550,650,500,650,1650,650,1650,650,550,650,500,650,550,600,550,650,550,600,550,650,550,600,1700,650,500,650,550,650,500,650,550,650,500,650,550,650,550,600,550,650,550,600,550,650,550,600,550,650,550,600,550,650,550,600,600,600,1650,650,550,650,1600,650,550,650,500,650,1650,650,550,600,};
unsigned int CALDO25[74] = {
  9150,4350,650,550,650,500,650,1650,650,1650,650,500,650,550,650,550,600,550,650,1650,650,500,650,550,650,1600,650,550,650,550,600,550,650,550,650,500,650,550,650,500,650,550,650,500,650,550,650,550,600,550,650,550,650,500,650,550,650,500,650,1650,650,550,600,1650,650,550,650,500,650,1650,650,500,650,};
unsigned int CALDO26[74] = {
  8950,4400,650,550,600,550,650,1650,650,1650,650,500,650,550,650,500,650,550,600,600,600,1650,650,550,650,1600,650,550,650,500,650,550,650,550,650,500,650,550,650,500,650,550,650,500,650,550,650,500,650,550,650,550,650,500,650,550,650,500,650,1650,650,500,650,1650,650,550,600,550,650,1650,650,500,650,};
unsigned int CALDO27[74] = {
  8900,4400,650,550,650,550,650,1600,650,1650,650,550,650,500,650,550,650,550,650,1600,700,1600,700,450,650,1650,700,450,700,500,700,450,700,500,700,500,700,450,700,500,700,450,700,500,700,450,700,500,700,500,650,500,700,500,700,450,700,500,700,1550,700,500,700,1600,700,450,700,500,700,1600,700,450,700,};
unsigned int CALDO28[74] = {
  8950,4350,700,500,700,450,700,1600,700,1600,700,500,700,450,700,500,650,500,700,500,650,500,700,1600,700,1600,700,450,700,500,700,450,700,500,700,450,700,500,700,450,700,500,700,500,700,450,700,500,700,450,700,500,700,450,750,450,700,500,700,1550,700,500,700,1550,700,500,700,450,700,1600,700,500,650,};
unsigned int CALDO29[74] = {
  8950,4400,650,550,600,550,650,1650,600,1700,650,500,650,550,650,500,650,550,600,1700,600,550,650,1650,650,1600,650,550,650,500,650,550,650,500,700,500,650,550,650,500,650,550,650,500,650,550,650,500,650,550,650,550,600,550,650,550,650,500,650,1650,650,500,650,1650,650,550,600,550,650,1650,650,550,650,};
unsigned int CALDO30[74] = {
  8900,4450,600,550,650,550,650,1600,650,1650,650,550,650,500,650,550,600,600,600,550,600,1700,650,1600,650,1650,650,500,650,550,650,500,700,500,650,550,650,500,650,550,650,500,650,550,650,500,650,550,650,550,600,550,650,550,650,500,650,550,650,1600,650,550,650,1650,600,550,650,550,650,1650,650,500,650,};

int input=0;

void setup()
{
  Serial.begin(9600);
  
}


void loop()
{ 
  if (Serial.available())
  {
   input = Serial.parseInt();  
   if (input > 0){
    command(input);
    }
    else{
    Serial.println("Errore di trasmissione") ;}
}
}

void command(int cod) {
  switch (cod) {
  /*case 118:
    irsend.sendRaw(CALDO18,74,38);
    break;
  case 119:
    irsend.sendRaw(CALDO19,74,38);
    break; 
  case 120:
    irsend.sendRaw(CALDO20,74,38);
    break;
  case 121:
    irsend.sendRaw(CALDO21,74,38);
    Serial.println("Setto : MODO CALDO, 21 gradi centigradi") ;
    break; 
  case 122:
    irsend.sendRaw(CALDO22,74,38);
    Serial.println("Setto : MODO CALDO, 22 gradi centigradi") ;
    break;*/
  case 123:
    irsend.sendRaw(CALDO23,74,38);
    Serial.println("Setto : MODO CALDO, 23 gradi centigradi") ;
    break;
  case 124:
    irsend.sendRaw(CALDO24,74,38);
    Serial.println("Setto : MODO CALDO, 24 gradi centigradi") ;
    break;
  case 125:
    irsend.sendRaw(CALDO25,74,38);
    Serial.println("Setto : MODO CALDO, 25 gradi centigradi") ;
    break;
  case 126:
    irsend.sendRaw(CALDO26,74,38);
    Serial.println("Setto : MODO CALDO, 26 gradi centigradi") ;
    break;
  case 127:
    irsend.sendRaw(CALDO27,74,38);
    Serial.println("Setto : MODO CALDO, 27 gradi centigradi") ;
    break;
  case 128:
    irsend.sendRaw(CALDO28,74,38);
    Serial.println("Setto : MODO CALDO, 28 gradi centigradi") ;
    break;
  case 129:
    irsend.sendRaw(CALDO29,74,38);
    Serial.println("Setto : MODO CALDO, 29 gradi centigradi") ;
    break;
  case 130:
    irsend.sendRaw(CALDO30,74,38);
    Serial.println("Setto : MODO CALDO, 30 gradi centigradi") ;
    break;
  default: 
      Serial.println("Comando non riconosciuto");
  }
}

p.s. analizzando un po il codice raw, quello che cambia sono solo i primi 12 bit, quindi i primi (3 di intestazione 1 di stop e 1 di dati x 12 volte) 27 valori dell’array, i restanti 47 sono sempre uguali e rappresentano questa codifica 0000 0000 0000 0000 101.
Stavo pensando a scrivere la parte fissa in esadecimale 0x00004 (se non erro dovrebbe essere questa) e definire la parte iniziale diversamente…
Ma dovrò modificare la libreria credo, perchè tramite raw questa cosa non la posso fare se non sbaglio…
Inizia a diventare un po complicata la cosa.

Suggerimenti?
P. P. S.
Ho visto ora questo http://www.arduino.cc/en/Reference/PROGMEM potrebbe fare al caso mio?

dr4gone: Ho visto ora questo http://www.arduino.cc/en/Reference/PROGMEM potrebbe fare al caso mio?

Si quello aiuta, anche la F() dei messaggi aiuta.

Anche i messaggi delle varie Serial.println() occupano memoria. Usa la funzione F(), queste frasi rimarranno nella memoria del codice (Flash) liberando la SRAM

Serial.println(F("Setto : MODO CALDO, 30 gradi centigradi"));

Potresti avere un solo array da 74 valori con i primi valori fissi, mentre il resto a zero. Poi in ogni case, prima della send, metti i valori appropriati nell'array (solo le parti che variano) me è incasinato

case 118:
    memset(arrCaldo,650,27);  // 650=pausa
    arrCaldo[0]=8900;
....
    arrCaldo[7]=1650;
...
    irsend.sendRaw(arrCaldo,74,38);
    break;

Ulteriore idea: A me sembra che il codice raw deve essere un valore logico 1 o 0 rappresentati da quei numeri che sono la lunghezza in microsecondi del segnale attivo. Ad esempio per il Nec: The NEC IR transmission protocol uses pulse distance encoding of the message bits: Logical '0' – a 562.5µs pulse burst followed by a 562.5µs space, with a total transmit time of 1.125ms Logical '1' – a 562.5µs pulse burst followed by a 1.6875ms space, with a total transmit time of 2.25ms Secondo me mettere dei valori 500 o 550 è lo stesso. Anche per 1650 o 1700 dovrebbe funzionare comunque se metti un solo valore. Il 650 o 600 sarà la pausa. Sostituiscilo con 560. Poi invece di avere dei 500 e dei 550 metti solo 560. Stesso per 1650/1700, metti 1680. A questo punto i valori o sono corti o sono lunghi mentre a seguire c'e' sempre la pausa. Ora C=corto, L=lungo ogni numero intero=un carattere. Intero=2 byte carattere=1 byte Questo vettore di interi messo come stringa sarebbe comunque più corto:

unsigned int CALDO16[74] = {  8950,4400,650,500,650,550,650,1650,600,1700,650,500,650,550,650,500,650,550,600,550,650,550,600,600,600,550,650,550,600,550,650,500,650,550,650,500,650,550,650,500,650,550,650,550,650,500,650,550,650,500,650,550,650,550,600,550,650,550,650,1600,650,550,650,1650,650,500,650,550,650,1650,600,550,650,};

Escludiamo i primi 3:

unsigned char CALDO16[36] = "CCLLCCCCCCCCCCCCCCCCCCCCCCCCCLCLCCLC";

Ora bisogna creare una funzione che legge questa stringa e mette nel vettore di 74 elementi il valore corto+pausa,lungo+pausa (e i primi tre) a seconda del valore trovato in vettore di caratteri.

Buone idee.. ma procediamo con ordine. :sweat_smile:

Prima cosa che ho fatto è stata aggiungere Serial.println(F("Setto : MODO CALDO, 16 gradi centigradi")) ; etc etc .. e gia ha migliorato la cosa....

poi ho agito sui vettori con PROGMEM. Qui il primo inghippo... Ho fatto così:

PROGMEM  prog_uint16_t CALDO20[74] = {
  8900,4400,650,550,650,550,650,1600,650,1650,650,550,650,500,650,550,600,550,650,550,600,600,600,1650,650,550,650,500,650,550,650,500,650,550,650,550,600,550,650,550,650,500,650,550,600,550,650,550,600,600,600,550,600,600,600,550,650,550,600,1650,650,550,650,1600,650,550,650,550,650,1600,650,550,650,};
unsigned int CALDO21[74] = {
  8900,4400,650,550,650,550,650,1600,650,1650,650,550,650,500,650,550,600,550,650,1650,650,550,650,1600,650,550,650,500,650,550,650,500,650,550,650,550,600,550,650,550,650,500,650,550,650,500,650,550,650,550,600,550,650,550,600,550,650,550,650,1600,650,550,650,1600,650,550,650,550,650,1600,650,550,650,};

Quando compilo tutto ok, mi ha liberato la sram ed è andato sulla flash. Ma quando vado a provare il 20 non funziona e il 21 si.... Quindi c'è qualche cosa che non va. Credo che quando richiamo il vettore CALDO20 nell'irsend sbaglio.. perchè qua http://arduino.cc/en/Reference/PROGMEM dice che per richiamare i valori da progmem bisogna fare qualcosa con "pgm_read_word_near" , ma non ho capito bene come adattarlo al mio codice.

Passando alle tue idee...., sono interessanti, avevo pensato anche io a una cosa del genere, ma c'è un problema.... Dalle prove che ho effettuato i vettori di int, devono essere dichiarati prima, staticamente, perchè dichiarandoli nel case, non funzionano.... se non ho capito male e se non sto dicendo una fesseria, quello che proponi tu è di creare , tramite una funzione generale, un array dinamico a runtime in base al comando che mando.... Ma questo non equivale a fare quello che ho scritto su che non funziona? Dovrei applicarmi a scrivere quella funzione che proponi per testare tutto, ma prima di dedicare tanto tempo a questa funzione, vorrei capire se potrebbe funzionare , ma soprattutto prima vorrei vedere bene come usare progmem per ottimizzare ancora di più il tutto.

Sì, una volta detto al compilatore di salvare un dato in Flash non puoi leggerlo normalmente, devi recuperarlo con un'istruzione apposita. Le istruzioni supportate dal compilatore sono qui: http://www.nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html

Con pgm_read_word_near leggi una word, ossia un intero a 2 byte, ciò che ti serve. Però di tipo unsigned. Quindi devi cambiare il secondo vettore CALDO21 in unsigned int, se vuoi salvare anche quello.

Per leggere i tuoi dati, devi passargli il vettore e la posizione dell'elemento da leggere. Quindi nel tuo caso:

PROGMEM  prog_uint16_t CALDO20[74] = {.....};
unsigned int lettura = pgm_read_word_near(CALDO20 + posizione);

dr4gone: Passando alle tue idee...., sono interessanti, avevo pensato anche io a una cosa del genere, ma c'è un problema.... Dalle prove che ho effettuato i vettori di int, devono essere dichiarati prima, staticamente, perchè dichiarandoli nel case, non funzionano.... se non ho capito male e se non sto dicendo una fesseria, quello che proponi tu è di creare , tramite una funzione generale, un array dinamico a runtime in base al comando che mando.... Ma questo non equivale a fare quello che ho scritto su che non funziona? Dovrei applicarmi a scrivere quella funzione che proponi per testare tutto, ma prima di dedicare tanto tempo a questa funzione, vorrei capire se potrebbe funzionare , ma soprattutto prima vorrei vedere bene come usare progmem per ottimizzare ancora di più il tutto.

No, solo 1 vettore globale inizializzato con 74 valori a 0. Lo si popola nella maniera opportuna solo prima di richiamare la irsend.

leo72:
Per leggere i tuoi dati, devi passargli il vettore e la posizione dell’elemento da leggere.
Quindi nel tuo caso:

PROGMEM  prog_uint16_t CALDO20[74] = {.....};

unsigned int lettura = pgm_read_word_near(CALDO20 + posizione);

Si, non era questo il problema a cui mi riferivo…, avevo gia scritto questo codice…

int pos=0

.......

for (int pos ; pos<73 ; pos++){
   unsigned int lettura = pgm_read_word_near(CALDO16 + pos);
   buf[pos]=lettura;
    }

E qui ok… ma come faccio a passare il mio buffer alla funzione sendRaw?

irsend.sendRaw( buf[?] ,74,38);

inserisco tutto il codice per spiegarmi meglio:

#include <IRremote.h>
IRsend irsend;

PROGMEM  prog_uint16_t CALDO16[74] = {
  8950,4400,650,500,650,550,650,1650,600,1700,650,500,650,550,650,500,650,550,600,550,650,550,600,600,600,550,650,550,600,550,650,500,650,550,650,500,650,550,650,500,650,550,650,550,650,500,650,550,650,500,650,550,650,550,600,550,650,550,650,1600,650,550,650,1650,650,500,650,550,650,1650,600,550,650,};

unsigned int buf[74];
int pos=0;

int input=0;

void setup()
{
  Serial.begin(9600);

}

void loop()
{ 
  if (Serial.available())
  {
    input = Serial.parseInt();  
    if (input > 0){
      command(input);
    }
    else{
      Serial.println("Errore di trasmissione") ;
    }
  }
}



void command(int cod) {
  switch (cod) {
  case 116:
    for (int pos ; pos<73 ; pos++){
      unsigned int lettura = pgm_read_word_near(CALDO16 + pos);
      buf[pos]=lettura;
    }
    irsend.sendRaw(qui che cosa metto?? buf[???],74,38);
    Serial.println(F("Setto : MODO CALDO, 16 gradi centigradi")) ;
    break;

  default: 
    Serial.println(F("Comando non riconosciuto"));
  }
}

avevo inoltre pensato di fare tutto un po più leggibile , ma ho un secondo dubbio… ho provato a fare una funzione del genere

unsigned int ReadFromFlash(*prog_uint16_t data)
{ 
   for (int pos ; pos<73 ; pos++){
   unsigned int lettura = pgm_read_word_near(data + pos);
   buf[pos]=lettura;
    }
  return buf;
  
}

che vorrei riachiamare all’occorrenza come ReadFromFlash(CALDO16); o quello che sarà…
ma mi ritorna questo errore

Arduino: 1.5.4 (Windows 7), Board: "Arduino Duemilanove or Diecimila, ATmega328"

sketch_dec24b:6: error: expected primary-expression before 'data'
sketch_dec24b:37: error: redefinition of 'unsigned int ReadFromFlash'
sketch_dec24b:6: error: 'unsigned int ReadFromFlash' previously defined here
sketch_dec24b:37: error: expected primary-expression before 'data'

sono un po scarso in programmazione avanzata :sweat_smile: .

nid69ita:
No, solo 1 vettore globale inizializzato con 74 valori a 0.
Lo si popola nella maniera opportuna solo prima di richiamare la irsend.

Spero di risolvere con PROGMEM e poi mi dedicherò a questo codice.

Grazie a tutti intanto dei suggerimenti

dr4gone:

nid69ita: No, solo 1 vettore globale inizializzato con 74 valori a 0. Lo si popola nella maniera opportuna solo prima di richiamare la irsend.

Spero di risolvere con PROGMEM e poi mi dedicherò a questo codice.

Prima però bisognerebbe vedere se si possono usare solo i 2 valori MARK_ON/MARK_OFF. Sarebbe da verificare sul campo. La cosa interessante di un codice del genere è che il valore da spedire (il vettore risultante) sarebbe abbastanza leggibile, invece di quella serie interminabile di numeri. Non sò però se si rallenta troppo, dovendo fare questa conversione.

dr4gone: E qui ok.. ma come faccio a passare il mio buffer alla funzione sendRaw?

irsend.sendRaw( buf[?] ,74,38);

Ho guardato il codice, vuole un array. Passagli solo il nome.

irsend.sendRaw(buf, 74, 38);

Probabilmente una graffa in più rimasta aperta, controlla.

devo aver cancellato per errore il post di prima… comunque il codice della funzione è questo.

unsigned int ReadFromFlash(*prog_uint16_t data)
{ 
   for (int pos ; pos<73 ; pos++){
   unsigned int lettura = pgm_read_word_near(data + pos);
   buf[pos]=lettura;
    }
  return buf;  
}

Non mi sembra che manchi niente.

riscrivo l’errore

CONDIZIONATORE_TEST:26: error: expected primary-expression before 'data'
CONDIZIONATORE_TEST:230: error: redefinition of 'unsigned int ReadFromFlash'
CONDIZIONATORE_TEST:26: error: 'unsigned int ReadFromFlash' previously defined here
CONDIZIONATORE_TEST:230: error: expected primary-expression before 'data'

La funzione la metto alla fine di tutto il codice… quando la aggiungo così com’è mi da l’errore, la elimino e compila perfettamente.
L’errore potrebbe essere dovuto al fatto che richiamo un tipo prog_uint16_t per la variabile “data” passata alla funzione?
Magari non è un tipo riconosciuto perchè fa parte di PROGMEM?

prog_uint16_t *data

leo72:
prog_uint16_t *data

ho dovuto aggiungere anche unsigned int* ReadFromFlash

unsigned int* ReadFromFlash(prog_uint16_t *data)
{ 
   for (int pos ; pos<73 ; pos++){
   unsigned int lettura = pgm_read_word_near(data + pos);
   buf[pos]=lettura;
    }
  return buf;  
}

Grazie ora compila!
Grazie mille dei tuoi suggerimenti! :grin: