Problema magari banale...ma non ci dormo la notte!

KKMeph: ... Ecco, io non voglio che lo esegua....

... e fin qui si era capito ... quello che vogliono sapere e', "quando" deve tornare ad eseguire il comando 1 ?

Detto in pratica:

sotto i 3V, nulla sale ... a 3V, accendi sale ancora ... a 4V, spegni (opzione 1) se invece di salire scende ... sotto i 3V deve rispegnere ? (opzione 2) scende dai 4V ... fra 3 e 4 V, NON riaccendere adesso, se scende ANCHE sotto i 3V, deve continuare a NON riaccendere (cioe', ti esegue quei comandi una sola volta in tutto), oppure se scende sotto i 3V (o una qualsiasi altra soglia minore di 3V), deve poi rieseguire l'accensione salendo di nuovo sopra i 3V ?

EDIT: perche' a me questo sembra solo una macchina a stati variabili ... ;)

typedef void (*std_fnc_ptr)(void);
std_fnc_ptr mutexRun;

void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
pinMode (13, OUTPUT);

mutexRun = ledIsOff; // prenota l’esecuzione di ledIsOff()

} // end setup

void ledIsOn() {
if (u > 4.5) {
digitalWrite (13, LOW); // spegni led
mutexRun = ledIsOff; // // prenota l’esecuzione di ledIsOff()
}
} // end ledIsOn

void ledIsOff() {
if ((u > 3) && (u < 4.5)) {
; // accendi led
mutexRun = ledIsOn; // prenota l’esecuzione di ledIsOn()
}
} // end ledIsOff

void loop() {

int sensorValue = analogRead(A0);

// Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
float u = sensorValue * (5.0 / 1023.0);
mutexRun(); // esegue ledIsOff o ledIsOn

Serial.println (u);

}

Prova così.

Ciao.

Ti ringrazio moltissimo. Dopo aver dichiarato le variabili all’interno dei vodi, succede questa cosa qui:

0-3V: stato 0, bene.
U>3V: stato 1, bene.
3 < U < 4,5: stato 1, bene.
U>4,5V: stato 0, bene.

3< U < 4,5 (dopo aver superato i 4,5): stato 1, male. Come prima.
0< U < 3V: stato 1, male. Dovrebbe ritornare allo stato 0 qui.

typedef void (*std_fnc_ptr)(void);
std_fnc_ptr mutexRun;

void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
  pinMode (13, OUTPUT);


  mutexRun = ledIsOff; // prenota l'esecuzione di ledIsOff()

}  // end setup

void ledIsOn() {
  int sensorValue = analogRead(A0);

  float u = sensorValue * (5.0 / 1023.0);
  if (u > 4.5) {
    digitalWrite (13, LOW); // spegni led
    mutexRun = ledIsOff;  // // prenota l'esecuzione di ledIsOff()
  }
} // end ledIsOn

void ledIsOff() {
  int sensorValue = analogRead(A0);

  float u = sensorValue * (5.0 / 1023.0);
  if ((u > 3) && (u < 4.5)) {
    digitalWrite (13, HIGH); // accendi led
    mutexRun = ledIsOn; // prenota l'esecuzione di ledIsOn()
  }
} // end ledIsOff

void loop() {

  int sensorValue = analogRead(A0);

  // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  float u = sensorValue * (5.0 / 1023.0);
  mutexRun();  // esegue ledIsOff o ledIsOn

  Serial.println (u);


}

Etemenanki: ... e fin qui si era capito ... quello che vogliono sapere e', "quando" deve tornare ad eseguire il comando 1 ?

Detto in pratica:

sotto i 3V, nulla sale ... a 3V, accendi sale ancora ... a 4V, spegni (opzione 1) se invece di salire scende ... sotto i 3V deve rispegnere ? (opzione 2) scende dai 4V ... fra 3 e 4 V, NON riaccendere adesso, se scende ANCHE sotto i 3V, deve continuare a NON riaccendere (cioe', ti esegue quei comandi una sola volta in tutto), oppure se scende sotto i 3V (o una qualsiasi altra soglia minore di 3V), deve poi rieseguire l'accensione salendo di nuovo sopra i 3V ?

EDIT: perche' a me questo sembra solo una macchina a stati variabili ... ;)

sotto i 3V, nulla sale ... a 3V, accendi sale ancora ... a 4V, spegni (opzione 1) se invece di salire scende ... sotto i 3V deve rispegnere ? SI (opzione 2) scende dai 4V ... fra 3 e 4 V, NON riaccendere ESATTO, MA DEVE RIACCENDERE SOTTO I 3V adesso, se scende ANCHE sotto i 3V, deve continuare a NON riaccendere (cioe', ti esegue quei comandi una sola volta in tutto), oppure se scende sotto i 3V (o una qualsiasi altra soglia minore di 3V), deve poi rieseguire l'accensione salendo di nuovo sopra i 3V ? SI, ESATTO.

Detta cosi, mi da l'impressione che si possa fare con una macchina a stati ed un flag ... in fondo hai 3 possibili stati in ingresso, sotto i 3V, fra 3v e 4V, sopra i 4V, e solo alcune possibili condizioni da controllare ... con 5 3 if ed un flag dovresti poterle gestire tutte (in questo caso, il flag ha 3 possibili valori, cioe' 0 = era sotto i 3V ... 1 = e' passato da sotto a sopra 3V ... 2 = e' passato da sotto a sopra 4V) ... ovviamente e' da controllare, perche' sto ragionando "al volo" e non posso testarlo in pratica, ma secondo me potrebbe funzionare in questo modo ...

prima condizione, e' sopra i 3V ed il flag e' a 0 --> accendi e setta il flag ad 1 (qui il flag dice allo sketch che hai acceso al passaggio, quindi dovra' spegnere quando passera' sopra i 4V)

seconda condizione, e' sopra i 3V e sotto i 4V ed il flag e' ad 1 --> non fai nulla EDIT: questa condizione e' inutile controllarla, probabilmente, perche' sarebbe comunque una condizione in cui non devi fare nulla

terza seconda condizione, e' sotto i 3V ed il flag non e' a 0 --> spegni e resetta il flag a 0

quarta terza condizione, e' sopra i 4V ed il flag e' ad 1 --> spegni e setta il flag a 2 (qui il flag dice allo sketch che c'e' gia stata l'accensione del rele', quindi deve spegnerlo e cambiarne il valore per evitare che alla successiva risalita si riaccenda)

quarta condizione, e' fra 3V e 4V ed il flag e' a 2 --> non fai nulla (qui il flag a 2 dice allo sketch che il passaggio acceso-spento c'e' gia stato, quindi non deve essere ripetuto finche' non sara' passato di nuovo sotto i 3V e resettato il flag a 0) RIEDIT: a pensarci bene, anche questo controllo non ha senso :P

/* Declare global variable */
typedef void (*std_fnc_ptr)(void);   // definizione nuovo tipo std_fnc_ptr
std_fnc_ptr mutexRun;                  // puntatore a funzione generica

// Le variabili globali non devono avere nomi di un singolo carattere e almeno minimo 5
float vinAdc0;        // ex 'u'
uint16_t rawAdc0; // ex 'sensorValue'

void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
  pinMode (13, OUTPUT);

  mutexRun = ledIsOff; // prenota l'esecuzione di ledIsOff()

}  // end setup

void ledIsOn() {

  if (vinAdc0 > 4.5) {
    digitalWrite (13, LOW); // spegni led
    mutexRun = ledIsOff;  // // prenota l'esecuzione di ledIsOff()
  }

} // end ledIsOn

void ledIsOff() {

  if ( (vinAdc0 > 3) && (vinAdc0 < 4.5) ) {
    digitalWrite (13, HIGH); // accendi led
    mutexRun = ledIsOn; // prenota l'esecuzione di ledIsOn()
  }

} // end ledIsOff

void loop() {

  rawAdc0 = analogRead(A0);

  // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  vinAdc0 = rawAdc0 * (5.0 / 1023.0);

  mutexRun();  // esegue ledIsOff o ledIsOn

  Serial.println (vinAdc0);
}

Il programma non è cambiato ho solo dato una ripulita. Se si ha la certezza che al power on vinAdc0 può solo aumentare possiamo passare a risolvere il caso inverso, diversamente si devono campionare due valori e stabilire la tendenza. Puoi confermare che vinAdc0 (ex ‘u’) al power on tende a salire?

Se la tendenza a salire si inverte dopo avere superato la soglia di 4.5, basta usare una variabile di stato in cui prendere nota della inversione di tendenza.

Comunque penso che se è realmente un onda triangolare questa si ripeterà all’infinito, pertanto bisogna ricavare la tendenza (toUp o toDown).

Ciao.

MauroTec: ma non e’ piu semplice un sistema a stati ?

Voglio dire, a lui non serve sapere se la tensione sta salendo o scendendo, ma solo in che condizione si trova il sistema …

Dimmi se sbaglio … supponiamo di usare una variabile di controllo per l’ingresso analogico, chiamiamola var, e mappiamola in modo che rispecchi i millivolt (solo per comodita’ di lettura), e di usare un flag …

if ((var <= 2999) && (flag != 0))
    {
    digitalWrite(out, LOW);
    flag = 0;
    }
if ((var => 3000) && (var <= 3999) && (flag == 0))
    {
    digitalWrite(out, HIGH);
    flag = 1;
    }
if ((var => 4000) && (flag == 1))
    {
    digitalWrite(out, LOW);
    flag = 2;
    }

Questi 3 if, non sarebbero sufficenti a fare quello che vuole ?

Questi 3 if, non sarebbero sufficenti a fare quello che vuole ?

ni, penso, forse, ma non sono sicuro, che giorno è? :grin:

Comunque gli ho dato una macchina a stati superflessibile, basta aggiungere una funzione e prenotarla. Un funzione è uno 'stato' (azzoppato di degli pseudo stati, entry state, exit state, ecc).

void newState() {
   if ...
       mutexRun = newState; sta ciclando su newState
   else if ...
       mutexRun = ledIsOn;
}

Sinceramente con la poca lucidità che mi è rimasta il tuo codice mi sembra sufficiente.

Aspettiamo che dice lui.

Ringrazio tutti della partecipazione e mi scuso nuovamente della mia pochezza di conoscenza di C. Purtroppo questa sera non riesco a provare nulla, domani proverò i vostri consigli!

di flag non ne avevo mai sentito parlare...pure sul mio vecchio libro di C non c'è nulla :(

di flag non ne avevo mai sentito parlare...pure sul mio vecchio libro di C non c'è nulla :(

Non prendere fischi per fiaschi, quello di ete è un esempio, dove si capisce che 'flag' è un nome di variabile che per sintetizzare non ha dichiarato. Comunque flag (bandierina), qui intesa come segnapunto.

Quindi se vuoi provare quel codice devi dichiarare la variabile globale flag, es:

byte flag = 0; // fuori da ogni funzione

Ciao.

BUongiorno a tutti!

Ho provato il codice datomi da MauroTec: comincio a vedere la luce, nel senso che almeno ho capito il codice.

Praticamente definisco varie funzioni in base all'ingresso che ho:

ingresso A ---> fai funzione relativa all'ingresso A ingresso B ---> fai funzione relativa all'ingresso B

E fin qui ok. Il problema che si pone è che lo stato non si conserva.

Ingresso A ---> fai funzione relativa all'ingresso A Ingresso B ---> fai funzione relativa all'ingresso B Ingresso A (DOPO AVER AVUTO INGRESSO B) ---> mantieni la funzione relativa all'ingresso B

tanto per capirsi eh.

/* Declare global variable */
typedef void (*std_fnc_ptr)(void);   // definizione nuovo tipo std_fnc_ptr
std_fnc_ptr mutexRun;                  // puntatore a funzione generica

// Le variabili globali non devono avere nomi di un singolo carattere e almeno minimo 5
float vinAdc0;        // ex 'u'
uint16_t rawAdc0; // ex 'sensorValue'

void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
  pinMode (13, OUTPUT);

  mutexRun = ledIsOff; // prenota l'esecuzione di ledIsOff()

}  // end setup

void ledIsOn() {

  if (vinAdc0 > 4.5) {
    digitalWrite (13, LOW); // spegni led
    mutexRun = ledIsOff;  // // prenota l'esecuzione di ledIsOff()
  }

} // end ledIsOn

void ledIsOff() {

  if ( (vinAdc0 > 3) && (vinAdc0 < 4.5) ) {
    digitalWrite (13, HIGH); // accendi led
    mutexRun = ledIsOn; // prenota l'esecuzione di ledIsOn()
  }

} // end ledIsOff


void funprova() {

  if (vinAdc0 < 3) {
    digitalWrite (13, LOW);
    mutexRun = funprova;
  }
  else {
    mutexRun = ledIsOff;
  }

}




void loop() {

  rawAdc0 = analogRead(A0);

  // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  vinAdc0 = rawAdc0 * (5.0 / 1023.0);

  mutexRun();  // esegue ledIsOff o ledIsOn

  Serial.println (vinAdc0);
delay (2);
  
}

Per l’utente Etemenanki

Ho capito il concetto, l’avevo già provato dichiarando una variabile k esterna a tutti ed assegnando un valore di k ad ogni “stato if”.

// the setup routine runs once when you press reset:
void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);


  pinMode (13, OUTPUT);
  digitalWrite (13, LOW);
}

void loop() {
  // read the input on analog pin 0:
  int sensorValue = analogRead(A0);
  byte flag  = 0;
  // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  float u = sensorValue * (5.0 / 1023.0);


  if ((u <= 3) && (flag == 0))
  {
    digitalWrite(13, LOW);
    flag = 1;
  }
  if ((u >= 3) && (u <= 4.5) && (flag == 1))
  {
    digitalWrite(13, HIGH);
    flag = 2;
  }
  if ((u > 4.5) && (flag == 2))
  {
    digitalWrite(13, LOW);
    flag = 3;
  }
  if ((u < 4.5 ) && (u > 3) && (flag == 3)) {
    digitalWrite (13, LOW);
    flag = 0;
  }


  // ritardo in millisecondi

  delay (2);


  Serial.println(u);
}

ecco il codice (che non funzia)

Si, scusami, non ho precisato bene (do sempre per scontato che se uno usa una variabile, la dichiari per forza nel setup, e mi dimentico di specificarlo a volte) … un “flag” non e’ un comando, e’ solo una variabile che tu usi per fare in modo che lo sketch sappia cosa fare in diverse occasioni, puo avere il nome che preferisci tu (pippo, vattelapesca, mariorossi, quello che vuoi … io ho usato flag per fare l’esempio, ma se te ne servissero 10, le puoi chiamare come preferisci) … i flag sono utili quando hai sketch che devono eseguire diverse operazioni con stati diversi, oppure che devono eseguire una singola operazione una sola volta, e poi aspettare una diversa operazione prima di rieseguirla, o in altri casi simili …

Ad esempio … nel pezzo di codice che ho postato, quando flag vale 0, significa che lo stato precedente era sotto i 3V, quindi il secondo if accende l’uscita solo nel caso il valore vada fra 3V e 4V arrivando da sotto i 3V, poi mette il flag a valore 1, il che gli impedisce di accenderla di nuovo prima che flag sia stato resettato … se in questo caso scende sotto i 3V di nuovo, il primo if lo resetta a 0, se invece sale sopra i 4V, il terzo if vede dal flag ad 1 che il rele’ e’ stato acceso, lo spegne, e mette il flag a 2 … in questa condizione, il secondo if non riaccende piu il rele’ quando passi da sopra a sotto i 4V, perche’ il flag e’ a 2, ed anche il terzo if non fa piu nulla, almeno finche’ non torni sotto i 3V, quando questo succede, il primo if “vede” che il flag e’ diverso da 0 e lo resetta, consentendo di riprendere il ciclo … e dato che tutto quello che c’e’ all’interno di un ciclo if viene ignorato se l’espressione di controllo non e’ soddisfatta, in stati diversi e’ come se nemmeno ci fossero …

/* Declare global variable */
typedef void (*std_fnc_ptr)(void);   // definizione nuovo tipo std_fnc_ptr
std_fnc_ptr mutexRun;                  // puntatore a funzione generica

// Le variabili globali non devono avere nomi di un singolo carattere e almeno minimo 5
float vinAdc0;        // ex 'u'
uint16_t rawAdc0; // ex 'sensorValue'
byte k = 0;


void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
  pinMode (13, OUTPUT);

  mutexRun = ledIsOff; // prenota l'esecuzione di ledIsOff()

}  // end setup

void ledIsOn() {

  if (vinAdc0 > 4.5) {
    digitalWrite (13, LOW); // spegni led
    mutexRun = ledIsOff;  // // prenota l'esecuzione di ledIsOff()
    k = k + 1;
  }

} // end ledIsOn

void ledIsOff() {

  if ( (vinAdc0 > 3) && (vinAdc0 < 4.5) ) {
    digitalWrite (13, HIGH); // accendi led
    mutexRun = ledIsOn; // prenota l'esecuzione di ledIsOn()
  }

} // end ledIsOff


void inizio() { //funzione inziale 

  if ((vinAdc0 > 0) && (vinAdc0 < 3)) {
    digitalWrite (13, LOW);
    mutexRun = inizio;
  }
}

void manstato () {  //prova di funzione con mantenimento dello stato 
  if ((vinAdc0 > 3) && (vinAdc0 < 4.5) && (k == 1)) {
    digitalWrite (13, LOW);
    mutexRun = manstato;
    k = 0;
  }

}

void loop() {

  rawAdc0 = analogRead(A0);

  // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  vinAdc0 = rawAdc0 * (5.0 / 1023.0);

  mutexRun();  // esegue ledIsOff o ledIsOn

  Serial.println (vinAdc0);
  delay (2);

}

Sto prendendo spunto da tutti i consigli. Ho implementato due funzioni nuove (iniziali e finali), inserendo anche il controllo “flag”. Non mi funge ancora, ma sento di non essere troppo distante :slight_smile:

KKMeph:

ecco il codice (che non funzia)

Secondo me manca la dichiarazione di qualche variabile, ed inoltre i cicli if sono “strani” … ed in piu, per il poco che mi ricordo, la mappatura non funziona con i float … pero’ si puo aggirare … giusto per curiosita’, se puoi (io non ho la possibilita’ di provare qui) prova a sostituirlo con una cosa tipo questa

int ingresso = A0;
int valore = 0;
byte flag = 0;

void setup() {
  Serial.begin(9600);
  pinMode (13, OUTPUT);
  digitalWrite (13, LOW);
}

void loop() {
  ingresso = analogRead(A0);
  valore = map(ingresso, 0, 50, 0, 1023);

  if ((valore < 30) && (flag != 0))
  {
    digitalWrite(13, LOW);
    flag = 0;
  }
  if ((valore >= 30) && (valore < 45) && (flag == 0))
  {
    digitalWrite(13, HIGH);
    flag = 1;
  }
  if ((valore >= 45) && (flag == 1))
  {
    digitalWrite(13, LOW);
    flag = 2;
  }

  delay (2);
  Serial.println(valore);
}

OK, allora immettendo in valori giusti (visti dal serial) ci siamo quasi!

Ai 3, si accende Ai 4.5 si spegne Tornando giù dai 4.5 rimane spento!!!!!!! YEAH!

Ma quando si oltrepassa il 3 deve accendersi ancora!

int ingresso = A0;
int valore = 0;
byte flag = 0;

void setup() {
  Serial.begin(9600);
  pinMode (13, OUTPUT);

  //pinMode (8, OUTPUT);
}

void loop() {
  ingresso = analogRead(A0);
  valore = map(ingresso, 0, 1023, 0, 1023);

  if ((valore < 500) && (flag != 0))
  {
    digitalWrite(13, HIGH);
    flag = 0;
  }
  if ((valore >= 500) && (valore < 918) && (flag == 0))
  {
    digitalWrite(13, HIGH);
    flag = 1;
  }
  if ((valore >= 918) && (flag == 1))
  {
    digitalWrite(13, LOW);
    flag = 2;
  }
  if (flag == 2)
  {
    digitalWrite (13, LOW);
    flag = 3;
  }
  if ((flag == 3) && (valore == 500)) {
    digitalWrite (13, HIGH);
    flag = 4;


  }


  delay (500);
  Serial.println(valore * 5.000 / 1023);
  Serial.println(flag);
}

Ci siamo!

Intendi quando scende sotto il 3 e poi risale di nuovo, immagino ... quello dovrebbe farlo il primo if ... non lo fa ?

EDIT: Intendi il codice che ho postato io ? ... quello e' differente ... a proposito, "map(ingresso, 0, 1023, 0, 1023)" non ha senso ;)