[SOLVED]Problema stranissimo if/switch case

Ciao a tutti,
stò riscontrando un problema davvero strano con l'uso dell'IF e CASE :
ho quasi ultimato un piccolo progetto di domotica per controllare via remoto il mio condizionatore, per farlo uso un arduino collegato ad un raspberry pi che uso come webserver:
Sull'arduino ho questo codice:

#include <IRremote.h>
IRsend irsend; //usare pin 3
decode_results results;
//non metto tutte le variabili dei segnali perchè sono molto lunghe
unsigned int Hita_OFF[531]={3400, 1624, 480, 1200, 480, [...] }
[...]
unsigned int Hita_HOT_23_auto_sw[534]={ [...] 
void setup()
{
 Serial.begin(9600);
}

void loop() {
if (Serial.available()) {
  char c = Serial.read();
  if (c == 'A') {
    irsend.sendRaw(Hita_OFF,531,38);
  }
  else if (c == 'B') {
    irsend.sendRaw(Hita_18_auto_sw,533,38);
  }
  else if (c == 'C') {
    irsend.sendRaw(Hita_18_max_sw,533,38);
  }
  else if (c == 'D') {
    irsend.sendRaw(Hita_20_auto_sw,541,38);
  }
  else if (c == 'E') {
    irsend.sendRaw(Hita_20_max_sw,537,38);
  }
  else if (c == 'F') {
    irsend.sendRaw(Hita_22_auto_sw,533,38);
  }
  else if (c == 'G') {
    irsend.sendRaw(Hita_22_max_sw,551,38);
  }
  else if (c == 'H') {
    irsend.sendRaw(Hita_24_auto_sw,533,38);
  }
  else if (c == 'I') {
    irsend.sendRaw(Hita_24_max_sw,531,38);
   }
  else if (c == 'L') {
    irsend.sendRaw(Hita_HOT_23_auto_sw,543,38); 
  }
} //if
} // loop

Dal raspberry, tramite pyton invio su seriale un carattere per innescare l'emettitore con un codice del tipo:

import serial
arduino = serial.Serial('/dev/tty.usbserial', 9600)
arduino.write('A') // ('B') ecc

tutto questo non funziona, o meglio funzionava in fase di test quando usavo solo due stati (solo due if) ed ecco il problema stranissimo:
se uso più di due "if" non succede nulla, difatti se cambio il codice così:

[...]
void loop() {
if (Serial.available()) {
  char c = Serial.read();
  if (c == 'A') {
    irsend.sendRaw(Hita_OFF,531,38);
  }
  else if (c == 'B') {
    irsend.sendRaw(Hita_18_auto_sw,533,38);
  }

} //if
} // loop

tutto funziona alla meraviglia, ma aggiungendo anche un solo altro IF (per la C) non va!!
A questo punto ho anche provato con ilo SWITCH CASE:

[...]

void setup() {
pinMode(LED, OUTPUT);
Serial.begin(9600);
}
void loop() {
if (Serial.available()) {
char c = Serial.read();

switch (c) {
case 'A':
  irsend.sendRaw(Hita_OFF,531,38);
  break;
case 'B':
  irsend.sendRaw(Hita_18_auto_sw,533,38);
  break;
case 'C':
  irsend.sendRaw(Hita_18_max_sw,533,38);
  break;
case 'D':
  irsend.sendRaw(Hita_20_auto_sw,541,38);
  break;
case 'E':
  irsend.sendRaw(Hita_20_max_sw,537,38);
  break;
case 'F':
  irsend.sendRaw(Hita_22_auto_sw,533,38);
  break;
case 'G':
  irsend.sendRaw(Hita_22_max_sw,551,38);
  break;
case 'H':
  irsend.sendRaw(Hita_24_auto_sw,533,38);
  break;
case 'I':
  irsend.sendRaw(Hita_24_max_sw,531,38);
  break;
case 'L':
  irsend.sendRaw(Hita_HOT_23_auto_sw,543,38);
  break;
}  
}
}

ed anche così non funziona....ma ancora se riduco a 2 le opzioni del case:

[...]

void setup() {
pinMode(LED, OUTPUT);
Serial.begin(9600);
}
void loop() {
if (Serial.available()) {
char c = Serial.read();

switch (c) {
case 'A':
  irsend.sendRaw(Hita_OFF,531,38);
  break;
case 'B':
  irsend.sendRaw(Hita_18_auto_sw,533,38);
  break;
}  
}
}

funziona tutto.
Sinceramente non so dove sbattere la testa, non mi spiego davvero un comportamento così...magari è l'ora tarda :astonished:
Qualcuno può illuminarmi??

Grazie mille!!

Non va spedendo 'C' oppure anche spedendo 'A', che prima ti faceva?

Non va con qualsiasi carattere io invii, se ci sono 3 o più IF o se lo SWITCH CASE ha 3 o più case :~
Mentre se c'è ne sono 2 funziona con entrambi i caratteri (es A o B)

Secondo me problema di memoria.
Quegli array che passi alla sendRaw sono enormi (531 elementi int circa 1K) e stanno in memoria SRAM (che su Arduino Uno è di soli 2K).
Ora quando hai solo 2 case, tu usi solo due array e il compilatore ti "ammazza" gli altri array perchè non sono usati (il compilatore ottimizza il codice superfluo).
Quando metti più case allora usi più array che "sfondano" la dimensione massima della memoria.
Prova a fare questo test, metti anche 6 case ma sempre usando gli stessi 2 array Hita_OFF e Hita_ON

Carissimo nid69ita, direi che hai proprio ragione!!
Sospettavo di qualche problem di memoria e stavo già facendo qualche prove per vederla con freeRam, poi ho letto il tuo messaggio ed il test da te suggerito ha dato esito positivo: usando solo due array tra i 7 IF/CASE funziona.
Ora però il problema permane e non ho idea di come risolverlo...qualche suggerimento?
Avevo pensato di passare l'array con il segnaleIR (i vari Hita_OFF Hita_20_ecc) via seriale dal raspberryPi, ma non ho idea bene di come modificare il codice sia su arduino, sia su raspberry per falo.

In ogni caso grazie ancora per la dritta!

ps Help :sweat_smile:

Puoi dichiarare quei buffer a stare in memoria del codice (Flash) con PROG_MEM
Però la sendRaw(), non accetta un buffer da memoria Flash.
Quindi creai un unico buffer vuoto grande 545 e prima della sendRaw con un ciclo for copi i dati dal buffer giusto in memoria flash al unico buffer in memoria SRAM

unsigned int Hita[545];       // in SRAM
PROGMEM unsigned int Hita_OFF[531]={3400, 1624, 480, 1200, 480, [...] }   // in Flash
[...]
PROGMEM unsigned int Hita_HOT_23_auto_sw[534]={ [...]
[...]
if (c == 'A')  
{ for(int i=0;i<531;i++) { Hita[i]=Hita_OFF[i]; }
  irsend.sendRaw(Hita,531,38); 
}

Grazie mille, provo con quest'ultimo metodo e ti faccio sapere!!

Ciao nid69ita, ho fatto come mi hai detto ed ora non ho più il problema di memoria e tutto "sembra" funzionare.
Ho scritto "sembra" perchè l'unico problema rimasto è che il segnale IR viene inviato non correttamente, mi spiego usando una fotocamera per vedere l'infrarosso, quando il segnale viene inviato correttamente dura meno di un secondo, ora il led IR resta acceso anche per 2-3 secondi e quindi viene inviato male.
La cosa strana è che se invio il segnale con un codice semplice come questo:

#include <IRremote.h>
IRsend irsend; //usare pin 3
decode_results results;

//non metto tutte le variabili dei segnali perchè sono molto lunghe
unsigned int Hita_OFF[531]={3400, 1624, 480, 1200, 480, [...] }
[...]
unsigned int Hita_HOT_23_auto_sw[534]={ [...] 

void setup()
{
 Serial.begin(9600);
}
void loop() 
{
  delay(4000);
 irsend.sendRaw(Hita_OFF,531,38);
  delay(1000);
 } // loop

che banalmente invia il segnale di off ogni 5 secondi, funziona.
Mentre ora col codice:

#include <IRremote.h>
IRsend irsend; //usare pin 3
decode_results results;
unsigned int Hita[551]; // in SRAM
PROGMEM unsigned int Hita_OFF[531]={3400, 1624, 4 ....
PROGMEM unsigned int Hita_18_auto_sw[533]={3400, 1624, 
PROGMEM unsigned int Hita_18_max_sw[533]={3400, 1620, 484, 1204, 480, 3 ...

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

void loop() {
if (Serial.available()) {
  char c = Serial.read();
  if (c == 'A') {
  for(int i=0;i<531;i++) { Hita[i]=Hita_OFF[i]; }
  delay(3000);
  irsend.sendRaw(Hita,531,38);
  delay(1000);
  }
  else if (c == 'B') {
    for(int i=0;i<533;i++) { Hita[i]=Hita_18_auto_sw[i]; }
    delay(3000);
    irsend.sendRaw(Hita,533,38);
    delay(1000);
  }
  else if (c == 'C') {
    for(int i=0;i<533;i++) { Hita[i]=Hita_18_max_sw[i]; }
    delay(3000);
    irsend.sendRaw(Hita,533,38);
    delay(1000);
  }
} //if
} // loop

mi da il problema del segnale IR "troppo duraturo"

Premetto che avevo riscontrato un problema analogo anche quando usavo il primo codice con i soli 2 IF/SWITCH, è come se Arduino lavorasse "rallentato".

Inoltre il comportamento è simile al caso un cui usi il codice semplice mettendo l'array nella memoria con PROGMEM:

#include <IRremote.h>
IRsend irsend; //usare pin 3
decode_results results;

//non metto tutte le variabili dei segnali perchè sono molto lunghe
PROGMEM unsigned int Hita_OFF[531]={3400, 1624, 480, 1200, 480, [...] }
[...]
unsigned int Hita_HOT_23_auto_sw[534]={ [...] 

void setup()
{
 Serial.begin(9600);
}
void loop() 
{
  delay(4000);
 irsend.sendRaw(Hita_OFF,531,38);
  delay(1000);
 } // loop

anche in questo caso non funziona ed il segnale è corrotto (troppo duraturo)

Probabile errore mio. Per leggere un dato da un vettore/array/buffer PROGMEM bisogna usare istruzioni apposite.

Usa il tipo prog_uint16 invece di unsigned int

PROGMEM prog_uint16_t Hita_OFF[531]={3400, 1624, 4 ....

e poi usare qualcosa tipo pgm_read_word (non sono esperto nell'uso della PROGMEM) :blush:

if (c == 'A') {
    for(int i=0;i<531;i++) { Hita[i]=pgm_read_word( Hita_OFF+i ); }
    delay(3000);
    irsend.sendRaw(Hita,531,38);
    delay(1000);
  }

Hurra!!!
Da una prova al volo, prima di andare a pranzo dai suoceri ( :* ), sembra essere OK!!!
Grazie mille!!
Nel pomeriggio completo il codice per tutti i segnali e ti faccio sapere ( sperando di poter mettere SOLVED nel titolo :slight_smile: )
Grazie ancora :smiley:

Ho applicato i tuoi suggerimenti su tutto il codice...funziona alla meraviglia!!

Grazie infinite!!!! XD XD

Razzo82:
Grazie infinite!!!! XD XD

Prego, di nulla :slight_smile: