Dichiarazione variabile locale

Ciao a tutti, volevo chiedervi una curiosità, è possibile dichiarare una sola volta una variabile locale nel ciclo infinito di arduino senza che mi salvi il valore quando “esco” dalla funzione? Mi spiego meglio: ho una funzione nella quale ho dichiarato “static” una variabile e fin qua tutto ok, questo mi permette di non dichiarare la variabile ad ogni ciclo rendendola come una globale ma con visibilità locale, il problema è che quando “esco” dalla funzione questa variabile conserva il valore e quando richiamo la funzione magari in un altro punto del programma il valore di quella variabile è conservato dalla chiamata di prima, ecco vorrei che quando richiamo la funzione in un altro punto del programma la variabile venisse “redichiarata” al valore “iniziale” come quando dichiari la variabile locale senza “static” che ad ogni ciclo si inizializza
Sembrerebbe un paradosso in quanto, da quel che so, nel ciclo le funzioni vengono ogni volta aperte e poi chiuse (scusate il termine poco tecnico) con la conseguente fine della vita delle variabili locali quindi alla cpu non importa in quale punto del programma richiami la funzione in quanto l’effetto è il medesimo, chiedo a voi se è possibile quanto detto prima, in alternativa potrei usare una variabile globale però volevo evitare
Comunque qua il codice per capire meglio:
Questa è una funzione che dovrei chiamare piu volte

byte LCD_GLOBAL_FUNCTION_ARROW(){
  static byte PosArrow  = 0;
  if(IRRcod(88)){
    if(PosArrow == 0) PosArrow = 3;
    else PosArrow--;
    for(int i = 0; i <= 3; i++){
      Display.setCursor(0, i);
      Display.print("  ");
    }
  }
  if(IRRcod(22)){
    if(PosArrow == 3) PosArrow = 0;
    else PosArrow++;
    for(int i = 0; i <= 3; i++){
      Display.setCursor(0, i);
      Display.print("  ");
    }
  }
  Display.setCursor(0, PosArrow);
  Display.print("->");
  return(PosArrow);
}

Questa invece è la funzione dove richiamo quella sopra

void LCD_200_MENU(){
  static bool MD = 1;
  if(MD) LCD_MESSAGE_200_0();
  MD = 0;
  byte PosArrow = LCD_GLOBAL_FUNCTION_ARROW();
  if(IRRcod(55)){
    switch(PosArrow){
      case 0: LCD_TypeProgram = 210; break;
      case 1: LCD_TypeProgram = 220; break;
      case 2: LCD_TypeProgram = 230; break;
      case 3: LCD_TypeProgram = 240; break;
    }
  }
  if(IRRcod(11)){
    LCD_TypeProgram = 100;
    MD = 1;
  }
}

In poche parole vorrei che quando esco dalla funzione “LCD_200_MENU()” la variabile “static byte PosArrow” mi ritornasse a 0, cosa “impossibile” in qaunto è static,
chiedo a voi se c’e un possibile modo senza usare le globali,
Grazie :slight_smile:
Andrea

E perché una variabile non static non va bene? Dichiari una variabile locale e la inizializzi al valore che vuoi.

Comunque la dichiarazione di una variabile static avviene una sola volta, ma le assegnazioni vengono ripetute a ogni chiamata a funzione, quindi a fine funzione puoi mettere variabileStatic=valore;

Comunque perché non va bene una semplice variabile locale??????????????

Faccio ipotesi io
Lui vorrebbe che la variabile, usata in una funzione A, chiamata dalla funzione B, conservasse il suo valore per tutto il ciclo di vita di B, non il ciclo di vita di A
La deve dichiarare nella funzione superiore e passare come parametro all inferiore

Salve, la funzione mi gestisce un cursore sul display Lcd che lo muovo tramite il telecomando e funziona tutto ok, il problema e che quando esco dal menu dove si trova il cursore e poi rientro vorrei che ritornasse alla posizione “x” come quando faccio partire la prima volta la funzione, in questo caso però quando rientro il cursore rimane nella posizione che aveva quando sono uscito, se uso una globale diventa semplice perche quando li do il comando di uscire dal menu valorizzo la variabile al valore che voglio, però adesso essendo locale non posso usarla al di fuori della funzione, se non uso la static non va perche ad ogni ciclo il valore si inizializza a quello della dichiarazione quindi il cursore rimane sempre nella stessa posizione, ho provato con il passaggio di parametro nella funzione chiamante ma ho lo stesso problema giustamente del cursore che sta nella stessa posizione, scusate ma sto imparando ancora :slight_smile:

... scusa e quale è il problema nel farla "globale" invece che "locale" ? ... quello di spostare una riga da un punto ad un altro ?

Guglielmo

AndreAndre:
Salve, la funzione .....

sì, ce lo avevi già spiegato, non è che non lo abbiamo capito...
cosa non andrebbe bene in una variabile dichiarata nella funzione superiore e passata come parametro nella inferiore?
si tratterebbe della soluzione "canonica" a problemi di questa specie

Standardoil:
sì, ce lo avevi già spiegato, non è che non lo abbiamo capito...
cosa non andrebbe bene in una variabile dichiarata nella funzione superiore e passata come parametro nella inferiore?
si tratterebbe della soluzione "canonica" a problemi di questa specie

Scusa pensavo si capisse meglio con un esempio pratico, non capisco però cosa intendi per funzione superiore e inferiore

gpb01:
... scusa e quale è il problema nel farla "globale" invece che "locale" ? ... quello di spostare una riga da un punto ad un altro ?

Guglielmo

Vorrei evitare più per sfizio che per praticità ed eseguibilità del programma, senza contare che le globali dovresti dichiararle prima della funzione utilizzante e ciò ne consegue un disordine in particolar modo se la sorgente e lunga e divisa in più file

Grazie
Andrea

AndreAndre:
Vorrei evitare più per sfizio che per praticità ed eseguibilità del programma, senza contare che le globali dovresti dichiararle prima della funzione utilizzante ...

... ma, mi sembra un inutile spreco di tempo. Le globali le dichiari nel .ino prima del setup() e sei a posto, nulla di così complicato.

Ricorda che i vari sorgenti che dividi con l'IDE di Arduino, contrariamente ad altri ambienti, vengono comunque messi tutti assieme e compilati.

Guglielmo

Sapendo che "metti globale e tanti saluti" é soluzione io ne trovo altre 2:

  1. passa quella variabile come parametro alla funzione
byte Funzione (byte a, int b, long e..)
{
  //ora puoi usare ognuna dibqueste variabili come locali, ma prendono il loro valore iniziale da fuori
}
  1. se non sai da fuori quale é il valore corretto sempre ma sai quando deve tornare all'inizio passa un parametro o crea una funzione che ti dica quando tale condizione si verifica e usa tale informazione
#define PRIMOVALORE 42//cerca e sostituisci su tutto il testo da li in poi. cerca "PRIMOVALORE" sostituiscilo con "42"
//metodo da ricordarsi visto che può sostituire con ogni blocco di testo, incpuse intere funzioni.
// NON mettere il ; in questo caso, #define NON lo richiede e farebbe solo casino (verrebbe mezzo dopo il 42, interrompendo il comando e creando vari errori di compilazione
byte Funzione (byte devoazzerare, ...)
{
  static byte variabile;
  //funzione in cui la variabile fa le sue 
  if (deviazzerare)
    variabile=PRIMOVALORE;
}

Per fare più il figo puoi mettere "byte devoazzerare" come ultima variabile nella riga e scrivere un prototipo della funzione in cui la metti normalmente a 0, così facendo puoi chiamare la funzione senza la variabile, e funziona normale, o con e azzeri variabile

//ecco il prototipo di funzione
byte Funzione (byte a, int b,...,byte devoazzerare=0);
//devoazzerare é diventato parametro opzionale, che se assente vale 0.
//una funzione con parametri opzionali DEVE avere il prototipo acritto da te (in realtà ogni funzione deve avere un prototipo, ma spesso lo mette un meccanismo nell'IDE)
//I parametri opzionali vanno alla fine, e possono essere più d'uno
#define PRIMOVALORE 42//il valore di inizio di "variabile"
byte Funzione (..., byte devoazzerare)
{
//quì NON va messo l'=0. La funzione é come il caso sopra
}
//da qualche parte
//chiamata che NON azzera variabile
Funzione(....);//SENZA considerare devoazzerare, come se non ci fosse
//Chiamata che azzera variabile
Funzione (...,1);
//se una funzione ha più parametri opzionali e vuoi modificare il valore di uno di loro devi passare anche quello dei precedenti

Grazie ai vostri suggerimenti ho capito come fare :slight_smile: :slight_smile:
Alla fine e piu semplice di quanto pensassi, come ha suggerito l’utente soprastante ho fatto il passaggio di parametri, però questa volta il parametro passato alla funzione da chiamare e una static, per “azzerarla” quando esco dal menu la porto semplicemente a 0
Vi faccio vedere come ho modificato, posto i 2 codici postati nel mio primo post sta volta modificati

Funzione 1:

byte LCD_GLOBAL_FUNCTION_ARROW(byte A){
  byte PosArrow  = A;
  if(IRRcod(88)){
    if(PosArrow == 0) PosArrow = 3;
    else PosArrow--;
    for(int i = 0; i <= 3; i++){
      Display.setCursor(0, i);
      Display.print("  ");
    }
  }
  if(IRRcod(22)){
    if(PosArrow == 3) PosArrow = 0;
    else PosArrow++;
    for(int i = 0; i <= 3; i++){
      Display.setCursor(0, i);
      Display.print("  ");
    }
  }
  Display.setCursor(0, PosArrow);
  Display.print("->");
  return(PosArrow);
}

Funzione 2: (la chiamate)

void LCD_200_MENU(){
  static bool MD = 1;
  if(MD) LCD_MESSAGE_200_0();
  MD = 0;
  static byte PosArrow = 0;
  PosArrow = LCD_GLOBAL_FUNCTION_ARROW(PosArrow);
  if(IRRcod(55)){
    switch(PosArrow){
      case 0: LCD_TypeProgram = 210; break;
      case 1: LCD_TypeProgram = 220; break;
      case 2: LCD_TypeProgram = 230; break;
      case 3: LCD_TypeProgram = 240; break;
    }
  }
  if(IRRcod(11)){
    LCD_TypeProgram = 100;
    MD = 1;
    PosArrow = 0;
  }
}

Grazie a tutti :):slight_smile:

pos_arrow=a si può evitare. A é una variabile interna alla funzione utilizzabile come ogni altra variabile, con la differenza che il suo valore iniziale é preso da fuori
Anche

If (posArrow==3)posArrow=0;
else posArrow++;

É evitabile, e diventa agevolmente
posArrow=(posArrow+1)%4;
% é l'operazione resto di divisione

E la prima for é evitabile, diventando solo una
lcd.print(" ");
Ogni volta che fai una print su LCD il puntatore a carattere in corso, sulla stessa riga si aggiorna automaticamente (non so se cambia riga alla fine della precedente)
ho sbagliato, credevi che la rlcolonna fosse il primo parametro, invece é il secondo
Infine la switch case da 0 a 3 si può eliminare con una sola riga:
variabileinterna=210+(variabileesterna*10)
Variabjleinterna é quella il cui valore supera 200, mentre variabileesterna é quella il cui valore va da 0 a 3