Come usare tanti Switch Case (o If) [Problemi memoria?]

Ciao a tutti,
ho alcuni grossi problemi, nel caricare uno sketch su Arduino UNO / DUEMILANOVE.

il mio progetto prevede una serie di lezioni progressive, che al momento ho provato a inserire mediante vari metodi, che vanno da 0 a 139.

  switch(progress)
  {
case 0:TestRx= "U";break; 
case 1:TestRx= "A";break; 
case 2:TestRx= "UAU";break; 
case 3:TestRx= "AAU";break; 
case 4:TestRx= "AUA";break; 
case 5:TestRx= "UAA";break; 
case 6:TestRx= "V";break;
etc etc etc....fino al case 139.

Oppure ho provato con:

if (progress==1) {TestRx= "U";} 
else if (progress==1) {TestRx= "A";} 
else if (progress==2) {TestRx= "UAU";} 
else if (progress==3) {TestRx= "AAU";} 
else if (progress==4) {TestRx= "AUA";} 
else if (progress==5) {TestRx= "UAA";} 
else if (progress==6) {TestRx= "V";} 
else if (progress==7) {TestRx= "VUA";} 
etc etc...

e anche con:

  PROGMEM prog_char *strings[] ={
//"U",
//"A",
//"UAU",
//"AAU",
//"AUA",
//"UAA",
//"V",
... etc etc
 TestRx=strings[progress];

Il mio problema è che non appena assegno un valore a "progress" attivando la relativa funzione, Arduino impazzisce completamente.

Sul mega tutto funziona benissimo, ma io ho necessità di caricare questo set di 139 lezioni progressive.
Per essere precisi avrei bisogno di caricare 2 set da 139 lezioni.

Vi viene in mente qualche metodo per caricare questi 139 stati in maniera più risparmiosa possibili in termini di ram?
Utilizzando PROGMEM nel modo in cui l'ho utilizzato al momento di caricare lo sketch e farlo partire va tutto bene, ma Arduino impazzisce non appena assegno un valore a "progress".

Sarebbero ben accette ottime idee :slight_smile: per poter caricare questi set di lezioni su un Arduino Uno o Duemilanove.

grazie
Giorgio

Gestire tutte quelle variabili e stringhe differenti può saturare la memoria.
L'Arduino UNO non ha tutta la RAM che servirebbe. Sappi che ogni stringa contenuta nello sketch, prima di poter essere usata, viene copiata nella RAM, che è di soli 2 kB.

Inoltre tutti i salti degli if e degli switch..case creano anch'essi dati che vengono memorizzati nello stack di sistema per i salti di rientro dalle subroutine, e lo stack "vive" anch'esso nella RAM.

esiste un sistema per caricare le variabili in rom invece che ram.

comunque dai una letta a
http://arduino.cc/en/Reference/Volatile
e

Lui ha già detto di aver usato Progmem. Il problema sono comunque anche i vari case dello switch. Ogni salto salva nello stack l'indirizzo del PC (Program Counter) per riprendere l'esecuzione una volta terminata l'esecuzione della subroutine chiamata. Poi bisogna anche vedere il resto dello sketch cosa fa, se ad esempio vengono caricate librerie esterne, viene usata la seriale, vengono stampati dati su un LCD ecc... tutte cose che possono aumentare il consumo di memoria.

Si, ho 2-3 librerie e scrivo su LCD.
Mi ritrovo a sketch partito SENZA lezioni, con 641 bytes di memoria liberi.
Se carico un set di lezioni, parto con 120, praticamente appena introduco un carattere Arduino impazzisce...letteralmente...

E' la memoria, te lo garantisco.
Non puoi usare la MEGA?

leo72:
Lui ha già detto di aver usato Progmem. Il problema sono comunque anche i vari case dello switch. Ogni salto salva nello stack l'indirizzo del PC (Program Counter) per riprendere l'esecuzione una volta terminata l'esecuzione della subroutine chiamata. Poi bisogna anche vedere il resto dello sketch cosa fa, se ad esempio vengono caricate librerie esterne, viene usata la seriale, vengono stampati dati su un LCD ecc... tutte cose che possono aumentare il consumo di memoria.

dove le vedi le call?? :smiley: i case son delle jump,o se è furbo usa una jump table a va velocissimo..
lo so,sono un rompi****e che mette i puntini sulle i

comunque se sono librerie esterne magari prova ad ottimizzarle eliminando cose inutili (ad esempio nell'lcd la funzione per creare caratteri custom se non la usi ec...) forse riesci a recuperare quel che ti serve :smiley:

m_ri:
dove le vedi le call?? :smiley: i case son delle jump

Probabilmente hai ragione.
E vista l'ora, non ho voglia di disassemblare un firmware per vedere come il compilatore traduce gli switch..case :stuck_out_tongue:

io invece vado direttamente a dormire...
buonanotte guys!!

m_ri:
dove le vedi le call?? :smiley: i case son delle jump,o se è furbo usa una jump table a va velocissimo..
lo so,sono un rompi****e che mette i puntini sulle i

La switch case viene codificata come una serie di chiamate a subroutine, una per ogni funzione invocata, e ovviamente sono delle call, i jump sono esclusivamente per la break che salta direttamente alla fine della switch.
Ovviamente di call ne viene eseguita solo una, ovvero quella della condizione valida, e occupa nello stack solo lo spazio riservato ad una singola chiamata a subroutine, però a livello di flash viene utilizzata una word (call) per ogni funzione inserita nella switch che va a pesare sull'impiego della memoria di programma, ma non sulla ram.
Da notare che la riga "case 0:TestRx= "U";break; " viene totalmente memorizzata nella flash, la "U" viene considerata come rom constant e posta direttamente nella flash senza necessità di usare progmem.

Ottimo.

E se provassi a registrare le sigle nella Eprom o in una eprom esterna o in una SD?
Dovresti fare solo una funzione per richiamare il dato in base all'indice.

@astrobeed: solitamente,gli switch vengono tradotti in una serie di cmp/test e jump..ho provato a fare un po' di disassemblaggio adesso,ed è così...
altrimenti,come ho detto prima,in alcuni casi,e se l'ottimizzazione è buona,lo switch viene tradotta in jump table..ossia usa l'argomento dello switch come indice in un vettore di puntatori a codice(ossia la cella i-esima del vettore contiene il puntatore al codice da eseguire nel caso la variabile valesse i,più alcune ottimizzazioni)..può essere che in alcuni casi usi la call,ma non mi vengono i mente..
EDIT: anche perchè il compilatore come fa a fare le call condizionate?al massimo può usare call + branch table,ma direi che ha più overhead di una jump table ..

ma invece provare qualcosa di questo tipo:

se la prima lettera e' "U" allora
---se la seconda e' una "A" allora
------se la terza e' una "U" allora
---------azione da fare per la combinazione UAU
------else la terza e' una "A" allora
---------azione da fare per la combinazione UAA

non migliorerebbe l'occupazione di memoria? forse ancora meglio sarebbe definendo le lettere possibili come constanti (si puo'?) e poi fare le varie combinazioni con le constanti...

Sospetto che il problema siano non il numero di if o case, ma le costanti stringa.

Quando scrivi Stringa1 = "ABC" la costante viene memorizzata.
Se poi scrivi Stringa2 = "ABC" la costante non viene memorizzata poiché già presente (è un'ottimizzazione base del compilatore)

Perciò, per risolvere il tuo problema, bisogna usare un trucco.

Ho notato che le costanti che usi sono composte più o meno dalle stesse lettere: "A", "U", "V", ecc.

Anzichè scrivere TestRx = "UAU" prova a scrivere TestRx = "U" + "A" + "U"

Ettore Massimo Albani

@cyberhs: usare il + per concatenare stringhe va bene con la classe String,non col tipo char[]..
e se ha già problemi col char,figuriamoci con le string..

non puoi scegliere te che lettere assegnare in ogni case dello switch? in questo caso non ci sarebbero problemi...

@m_ri

Ma dove hai letto che sono char[]?

Comunque se sono char[] tanto meglio: si dichiara globalmente char TestRx[x + 1] ove x è la massima dimensione prevista e poi negli if/case si assegna, al posto di TestRx = "UAU", TestRx[0] = 'U'; TestRx[1] = 'A'; TestRx[2] = 'U'; TestRx[3] = '/0';

ho dato per scontato che usasse i char[]..cmq il tuo suggerimento continua a mangiarsi parecchia memoria..è quasi come dichiarare una matrice [139 o quel che è][4 o più]..altra strada è quella della compressione huffman..è facilmente implementabile sull'arduino,e penso che dimezzi la SRAM richiesta..

cmq ripeto la domanda: nei vari case,puoi assegnare la stringa che vuoi,basta che sia unica?oppure hai delle stringhe preconfezionate da inserire?
nel secondo caso,metti la lista..

@m_ri

il tuo suggerimento continua a mangiarsi parecchia memoria..è quasi come dichiarare una matrice [139 o quel che è][4 o più]

Forse non mi sono spiegato bene.

Il vettore char in questione occupa solo i byte strettamente necessari alla stringa che si vuole ottenere.
Ad esempio, supponendo che la stringa massima sia di 5 caratteri ("AUVBK"), dimensionerò globalmente char TestRx[6] e userò sempre il medesimo vettore per tutte le combinazioni:
TestRx = "UAU" ---> TestRx[0] = 'U'; TestRx[1] = 'A'; TestRx[2] = 'U'; TestRx[3] = '/0';
TestRx = "VA" ---> TestRx[0] = 'V'; TestRx[1] = 'A'; TestRx[2] = '/0';
TestRx = "VAU" ---> TestRx[0] = 'V'; TestRx[1] = 'A'; TestRx[2] = 'U'; TestRx[3] = '/0';