visibilità delle variabili

Una buona giornata a tutti
come da titolo vi chiedo cortesemente se potete darmi qualche spiegazione su un problrma che o incontrato,
ho una funzione

void Taimer_1_on(){
	
	int dataOra_1[8] = {2, 8, 0, 8, 1, 3, 2, 0};
	
	int K_1;
	char J_1;
	
	int Valpb2 = 0;
	int Statpb2 = 0;
	int Valpb3 = 0;
	int Statpb3 = 0;
	
	printDataOra_1_on();
	
	
	
	Valpb2 = digitalRead(PB_2);
	if (Statpb2 && Statpb2 != Valpb2) {
		dataOra_1[J_1] = K_1;
		K_1++;
		if (K_1 > 9){
			K_1 = 0;
		}
	}
	Statpb2 = Valpb2;
	
	Valpb3 = digitalRead(PB_3);
	if (Statpb3 && Statpb3 != Valpb3) {
		J_1++;
		
		if(J_1 > 8)
		J_1 = 0;
		K_1 = 0;
	}
	
	Statpb3 = Valpb3;
	
}

ovviamente e dichiarata all’inizio,
cosi con le variabili dichiarate al suo interno non funziona,
funziona invece se le variabili le dichiarro in globale " al inizio del file"

o cercato in rete, per capire dove sbaglio ma non ho trovato risposte,

da quel poco che conosco le variabili dichiarate all’interno di una funzione sono locali e riconoscute solo all’interno della funzione,

non capisco perchè con le variabili locali gli IF non vengono eseguiti,

per cortesia qualcuno mi puo dare una semplice spiegazione?
milli grazie

ciao...per esempio tu inizializzi le tue variabili così:

    int Valpb2 = 0;
    int Statpb2 = 0;
    int Valpb3 = 0;
    int Statpb3 = 0;

tutte a "0" quindi come se fossero "false"...poi subito un if:

    Valpb2 = digitalRead(PB_2);
    if (Statpb2 && Statpb2 != Valpb2) {

Valpb2 lo leggi ma Statpb2 è ancora a "0" e quindi la condizione NON è rispettata e nell'if non ci entri.

per come hai scritto la funzione ad ogni sua chiamata nello sketch, che non conosco, le variabili vengono create a "0"...prova ad anteporre "static" ad ogni variabile...per il suo significato vai al reference.

EDIT : anteponi "static" ma NON assegnare valori precisi..oppure solo la prima volta che chiami la funzione...altrimenti fai un assegnamento e non cambia nulla...

Le variabili dichiarate in una funzione esistono solo in quella funzione (variabili locali). Le variabili dichiarate fuori da ogni funzione sono globali e percui presenti in tutte le funzioni.

C'é un inghippo. Se dichiari una veriabile globale e dentro una funzione dichiari una variabile locale con lo stesso nome all interno della funzione esiste solo la variabile locale che é diversa da quella globale.

Nel Tuo caso la funzione "printDataOra_1_on()" non vede le variabili che hi dichiarata nella funzione "void Taimer_1_on()". Rimedio: o passi le variabili come argomenti della funzione oppure devi usare variabili globali.

int K_1;
char J_1;
....
dataOra_1[J_1] = K_1;

K_1 e J_1 non hanno un vlaore definito percui non puoi usarle come indice del array (molto grave) oppure come valore da caricare (meno grave) È facile che dataOra_1[J_1] punti a un cella di memoria fuori dal array e percui sovrascrivi alte variabili.

Ciao Uwe

Ciao ragazzi grazie di avermi risposto

@ORSO2001
ora con le variabili settate come static all’interno della funzione è OK,
ora mi rimane un altro problema,
la variabile J_1 all’uscita dalla funzione non si resetta,
o provato a settarla a 0 ma non va,
come posso fare perche si resetti all’uscita dalla funzione?

@uwefed

Le variabili dichiarate in una funzione esistono solo in quella funzione (variabili locali).
Le variabili dichiarate fuori da ogni funzione sono globali e percui presenti in tutte le funzioni.

OK questo mi conferma che avevo capito giusto,

C’é un inghippo. Se dichiari una veriabile globale e dentro una funzione dichiari una variabile locale con lo stesso nome all interno della funzione esiste solo la variabile locale che é diversa da quella globale.

OK perfetto,

ma le variabili all’interno di una funzione bisogna settarle static

nel mio caso la funzione “printDataOra_1_on()” non usa variabili della funzione “void Taimer_1_on()”.

void printDataOra_1_on(){
 static int dato;
 char pos_giorno = 3;
 char pos_mese = 6;
 char pos_ora = 9;
 char pos_minuti = 12;
 
 lcd.setCursor(5, 1);
 lcd.print("Taimer_1");
 
 lcd.setCursor(0, 2);
 lcd.print("on");
 
 lcd.setCursor(0, 3),
 lcd.print("              ");
 
 
 for(int i = 0; i < 2; i++){
 dato = dataOra_1[i];
 lcd.setCursor(pos_giorno, 2);
 lcd.print(dato);
 pos_giorno++;
 }
 lcd.setCursor(5, 2);
 lcd.print("/");
 
 for(int i = 2; i < 4; i++){
 dato = dataOra_1[i];
 lcd.setCursor(pos_mese, 2);
 lcd.print(dato);
 pos_mese++;
 }
 
 for(int i = 4; i < 6; i++){
 dato = dataOra_1[i];
 lcd.setCursor(pos_ora, 2);
 lcd.print(dato);
 pos_ora++;
 }
 lcd.setCursor(11, 2);
 lcd.print(":");
 
 for(int i = 6; i < 8; i++){
 dato = dataOra_1[i];
 lcd.setCursor(pos_minuti, 2);
 lcd.print(dato);
 pos_minuti++;
 }
}

come vedi qui ci sono altre variabili, non sono static eppure funziona,

K_1 e J_1 non hanno un vlaore definito percui non puoi usarle come indice del array (molto grave) oppure come valore da caricare (meno grave)
È facile che dataOra_1[J_1] punti a un cella di memoria fuori dal array e percui sovrascrivi alte variabili.

scusami non capisco intendi che devo
static char J_1 = 0;

milefori: ma le variabili all'interno di una funzione bisogna settarle static

... solo se vuoi che conservino il loro valore tra due chiamate successive alla stessa funzione.

Normalmente si separa in "funzioni" anche per risparmiare SRAM. Le variabili dichiarate in una funzione vengono create solo quando quella funzione viene chiamata e distrutte quando si esce da essa. In questo modo più funzioni condividono la stessa SRAM allocando e deallocando lo spazio che usano per le loro variabili.

Se tu dichiari una variabile, dentro una funzione, "static", quella variabile verrà allocata da un'altra parte della SRAM e occuperà permanentemente la memoria sia che la funzione sia attiva che non. Un po' come una variabile globale, ma visibile solo dentro la funzione.

Guglielmo

Ciao Guglielmo, ottima spiegazione

avevo il dubbio che static mi mantenesse in dato anche all’uscita della funzione,

leggendo dei documenti in rete o avuto la conferma, ora con la tua spiegazione e più chiaro,

scusami se profitto della tua gentilezza
io vorrei che all’uscita della funzione la variabile j si resettasse,

ma se setto la variabile all’interno della funzione:
char j = 0;
oppure
char j;

alla pressione del pulsante non si incrementa,
e come se non la vedesse,

non so se e importante ma sono su Atmel Studio 7

mi puoi dare qualche consiglio per risolvere la cosa?

In che senso ? :o

Se hai :

void miaFunzione(void) {
   char x = 0;
   // qui x vale 0
   x++;
   // qui x vale 1
}

... la x, che esiste SOLO fino a quando sei nella funzione, si incrementa sicuramente, poi, quando esci dalla funzione, non esiste più.

Guglielmo

Come era logico hai perfettamente ragione

ho scoperto dove sbagliavo:

quella funzione io la richiamavo all'interno del loop cosi

if(startTaimer == 3){
 for(;;){
 Taimer_1_on();
 if(startTaimer == 3 && digitalRead(PB_1) == LOW)
 break;
 }
 }

quel for ciclo continuo li e sbagliato lo spostato all'interno della funzione ed ora è tutto OK

mille grazie ancora per il vostro aiuto

de nada...

sempre bello vedere un:

for(;;)

Ciao ragazzi scusate se approfitto

@ORSO2001 ti piacefor(;;) e while() no ;)

parlando sempre di visibilità,

un pulsante "almeno io lo dichiaro cosi"

defain PB_1 9 // ovviamente al inizio

nel loop lo faccio incrementare una variabile " sempre dichiarata globale"

poi in una funzione gli vorrei far incrementare un altra variabile "locale"

non e che ci sia qualche conflitto a fare sta cosa?

essendo il pulsante "ovviamente" dichiarato globale

… “#defain” invece di “#define”, ho il vago dubbio che sia sbagliato … :wink:

ciao...

#define PB_1 9

con l'uso del #define non crei una variabile ma dai un'istruzione/direttiva al compilatore di sostituire TUTTO quello che trova nel tuo sketch, uguale a "PB_1", con il numero "9".

come ben sai il loop() è molto veloce nel ripetersi...e se non metti altre condizioni quando premi un pulsante, la cui lettura potrebbe far fare più cose diverse, rischi che vengano eseguite tutte quando tu ne vorresti solo alcune...od una. devi inserire altre condizioni per discriminare dove vuoi eseguire la lettura di tale bottone...

una grande ciao a tutti

@Etemenanki centrato in pieno, o fatto una figuraccia :'(

@ORSO2001

OK ottima spiegazione,

per il controllo della pressione "del pulsante" o appreso qui una tecnica, che se non ricordo male me la suggerita Etemenanki

ma quando dici di inserire altre condizioni cosa intendi? variabili,

chiedo troppo due righe di esempio

mille grazie

for( ; ; ) e while() no?

perché non é la stessa cosa. semmai while(1);

Ciao Uwe

esempi…attento che io setto il pin come INPUT_PULLUP!!!

“sbagliato”:

#define PIN_1 9

int count = 0;

void setup() {
  Serial.begin(9600);
  pinMode(PIN_1, INPUT_PULLUP);

}

void loop() {
  if (!digitalRead(PIN_1)) {
    count++;
    Serial.print("countG = ");
    Serial.println(count);
  }
  func();

}

void func() {
  static int count = 0;
  if (!digitalRead(PIN_1)) {
    count++;
    Serial.print("countL = ");
    Serial.println(count);
  }
}

“giusto”…con un po’ di cose…giusto per stimolare la curiosità:

#define PIN_1 9

byte fase;
byte statoPulsante;
byte statoPulsanteCheck;

void setup() {

  Serial.begin(9600);
  pinMode(PIN_1, INPUT_PULLUP);
  fase = 0;
  statoPulsante = 0;
  statoPulsanteCheck = 0;
}

void loop() {
  static byte forCase[] = {0, 0, 0, 0};

  if (checkP(PIN_1, &statoPulsante, &statoPulsanteCheck) && fase < 2) {
    Serial.println("sono qua...");
    fase++;
  }

  if (fase >= 2) {
    if (checkP(PIN_1, &statoPulsante, &statoPulsanteCheck)) {
      Serial.println("...adesso sono qua");
      fase++;
    }
  }

  switch (fase) {

    case 0:
      if (forCase[0] == 0) {
        Serial.println("premi il pulsante");
        forCase[0] = 1;
      }
      break;
    case 1:
      if (forCase[1] == 0) {
        Serial.println("hai premuto il pulsante...fallo di nuovo");
        forCase[1] = 1;
      }
      break;
    case 2:
      if (forCase[2] == 0) {
        Serial.println("...e due....un'altra vota..");
        forCase[2] = 1;
      }
      break;
    case 3:
      if (forCase[3] == 0) {
        Serial.println("fine!");
        forCase[3] = 1;
      }
      break;
    default :
      break;
  }
}

/*FUNZIONI*/

// controllo stato pulsante
boolean checkP( byte pin, byte *adesso, byte *prima) {
  *adesso = digitalRead(pin);
  if (*adesso != *prima && *adesso == 0) {
    *prima = *adesso;
    return true;
  }
  else if (*adesso != *prima && *prima == 0) {
    *prima = 1;
    return false;
  }
  return false;
}

@ORSO2001
Certo che la curiosità me l’hai stimolata un bel po,

prima di tutto grazie per il tempo che mi dedichi

if (checkP(PIN_1, &statoPulsante, &statoPulsanteCheck) && fase < 2) {
Serial.println(“sono qua…”);
fase++;
}

questa non lo capita forse intendevi

if(digitalRead(PIN_1) && statoPulsante && statoPulsanteCheck && fase < 2){
 fase++;
}

scusatemi se spesso scrivo delle cavolate

milefori:
questa non lo capita forse intendevi

if(digitalRead(PIN_1) && statoPulsante && statoPulsanteCheck && fase < 2){

fase++;
}

Vediamo se intendeva…

Quale condizione verrebbe controllata dall’espressione logica che hai scritto?

Un AND logico tra quattro elementi… quindi tutti gli elementi devono essere uno/veri affinché l’if risulti vero e vengano eseguite le istruzioni contenute:

valore letto dall’ingresso AND l’ultimo valore letto AND il penultimo valore letto AND fase<2

È una condizione senza alcun senso, non rappresenta / controlla niente né il verificarsi di qualcosa :wink:

Io direi che non intendeva.

Invece intendeva buttare li l’argomento passaggio variabili per riferimento alle funzioni.

In questo caso il simbolo & vuol dire “indirizzo di memoria della variabile specificata”, e serve per poter modificare le variabili dall’interno della funzione anche se da essa non sono normalmente visibili.

Infatti all’interno della funzione chiamata si usa il simbolo * davanti alle variabili che non sono locali, ma sono quelle passate per riferimento (indirizzo) dal chiamante.

PS: non so se ci sia un modo più semplice per introdurre i puntatori :stuck_out_tongue:

Ciao Claudio_FF grazie del ottima spiegazione

ora e più chiaro, anche se per me e un po troppo avanzata, devo studiarmi ed esercitarmi sui puntatori,

sempre molto gentili, mille grazie

Vedi se ti tornano i valori stampati:

0
10
12
50

4
11
12
51
int a = 4;              // 'a' globale
int b = 10;             // 'b' globale


void fn1(int v, int *m) {
    int a = 0;
    Serial.println(a);  // 'a' locale inizializzata nella funzione
    Serial.println(b);  // 'b' globale inizializzata all'esterno
    Serial.println(v);  // 'v' locale copia della 'y' del chiamante
    Serial.println(*m); // 'z' del chiamante indirizzata da 'm'
    a++;                // incrementa la 'a' locale
    b++;                // incrementa la 'b' globale
    v++;                // incrementa la 'v' locale
    (*m)++;             // incrementa la 'z' del chiamante
}


void fn2() {
    int y = 12;         // 'y' locale inizializzata nella funzione
    int z = 50;         // 'z' locale inizializzata nella funzione
    fn1(y, &z);         // chiama fn1 passando copia di 'y' e indirizzo di 'z'
    Serial.println();
    Serial.println(a);  // 'a' globale immutata
    Serial.println(b);  // 'b' globale modificata dalla funzione fn1
    Serial.println(y);  // 'y' locale immutata
    Serial.println(z);  // 'z' locale modificata dalla funzione fn1
}


void setup() { Serial.begin(9600);  delay(1000);  fn2(); }


void loop() { }

Ciao Claudio_FF grazie del esempio ben spiegato

ora mi e più chiaro il puntatore *m e l'indirizzo di variabile a &z e la chiamata,

approfitto per un piccolo chiarimento, nella prima funzione fn1 le variabili a, b si incrementeranno ovviamente con opportuno software, hardware