Cambio variabili con pulsanti

Ciao a tutti,
per un progetto che ho in mente, sto tentando di modificare 4 variabili mediante la pressione di un pulsante.
La mia idea per ridurre al minimo il numero di pulsanti necessari è quella di usarne 4 (P1, P2, P3 e P4).
Attraverso la loro pressione posso aumentare di 10 il valore della variabile.
Mentre per diminuirli pensavo di usarne solo 1 (P5)così da ottenere attraverso un AND con uno dei 4 pulsanti la sottrazione della variabile collegata.
Queste sono le combinazioni dei tasti:

P1(HIGH) + P5(LOW) = variabile1 + 10
P1(HIGH) + P5(HIGH) = variabile1 - 10
P2(HIGH) + P5(LOW) = variabile2 + 10
P2(HIGH) + P5(HIGH) = variabile2 - 10
P3(HIGH) + P5(LOW) = variabile3 + 10
P3(HIGH) + P5(HIGH) = variabile3 - 10
P4(HIGH) + P5(LOW) = variabile4 + 10
P4(HIGH) + P5(HIGH) = variabile4 - 10

Ho simulato il collegamento su Tinkercad più l'esecuzione sul monitor seriale ma le variabili non cambiano e rimangono sempre 1000.
Di seguito lo sketch, vedeve dov'è l'errore?

int variabile1 = 1000;
int variabile2 = 1000;
int variabile3 = 1000;
int variabile4 = 1000;

const int P1 = 2; //Pulsante per aumentare di 10 la variabile1
const int P2 = 3; //Pulsante per aumentare di 10 la variabile2
const int P3 = 4; //Pulsante per aumentare di 10 la variabile3
const int P4 = 5; //Pulsante per aumentare di 10 la variabile4
const int P5 = 6; //Pulsante per diminuire di 10 la variabile

int button_State_1 = 0; //Controllo stato P1
int button_State_2 = 0; //Controllo stato P2
int button_State_3 = 0; //Controllo stato P3
int button_State_4 = 0; //Controllo stato P4
int button_State_5 = 0; //Controllo stato P5

void setup (){

pinMode(P1, INPUT);
pinMode(P2, INPUT);
pinMode(P3, INPUT);
pinMode(P4, INPUT);
pinMode(P5, INPUT);
Serial.begin(9600);

}

void loop (){

 if (button_State_5 == 0 && digitalRead(P5)== LOW)
 {
 if (button_State_1 == 0 && digitalRead(P1)== HIGH)
 {
 button_State_1 = 1;
 variabile1 = variabile1+ 10;
 }
 if (button_State_1 == 1 && digitalRead(P1)== LOW)
 {
 button_State_1 = 0;
 }


 if (button_State_2 == 0 && digitalRead(P2)== HIGH)
 {
 button_State_2 = 1;
 variabile2 = variabile2 + 10;
 }
 if (button_State_2 == 1 && digitalRead(P2)== LOW)
 {
 button_State_2 = 0;
 }


 if (button_State_3 == 0 && digitalRead(P3)== HIGH)
 {
 button_State_3 = 1;
 variabile3 = variabile3 + 10;
 }
 if (button_State_3 == 1 && digitalRead(P3)== LOW)
 {
 button_State_3 = 0;
 }


 if (button_State_4 == 0 && digitalRead(P4)== HIGH)
 {
 button_State_4 = 1;
 variabile4 = variabile4 + 10;
 }
 if (button_State_4 == 1 && digitalRead(P4)== LOW)
 {
 button_State_4 = 0;
 }
 }
 if (button_State_5 == 0 && digitalRead(P5)== HIGH)
 {
 button_State_5 = 1;
 }
 if (button_State_5 == 1 && digitalRead(P5)== HIGH)
 {
 if (button_State_1 == 0 && digitalRead(P1)== HIGH)
 {
 button_State_1 = 1;
 variabile1 = variabile1 - 10;
 }
 if (button_State_1 == 1 && digitalRead(P1)== LOW)
 {
 button_State_1 = 0;
 }


 if (button_State_2 == 0 && digitalRead(P2)== HIGH)
 {
 button_State_2 = 1;
 variabile2 = variabile2 - 10;
 }
 if (button_State_2 == 1 && digitalRead(P2)== LOW)
 {
 button_State_2 = 0;
 }


 if (button_State_3 == 0 && digitalRead(P3)== HIGH)
 {
 button_State_3 = 1;
 variabile3 = variabile3 - 10;
 }
 if (button_State_3 == 1 && digitalRead(P3)== LOW)
 {
 button_State_3 = 0;
 }


 if (button_State_4 == 0 && digitalRead(P4)== HIGH)
 {
 button_State_4 = 1;
 variabile4 = variabile4 - 10;
 }
 if (button_State_4 == 1 && digitalRead(P4)== LOW)
 {
 button_State_4 = 0;
 }
 }
 if (button_State_5 == 1 && digitalRead(P5)== LOW)
 {
 button_State_5 = 0;
 }
 Serial.println("INIZIO");
 Serial.println(variabile1);
 Serial.println(variabile2);
 Serial.println(variabile3);
 Serial.println(variabile4);
}

Se avete anche consigli per come migliorare lo sketch ditelo pure :slight_smile:

Grazie in anticipo.

parto dal presupposto che tu abbaia fatto il debounce hardware e seguo esattamente la logica che hai impresso al programma, io fareì così per semplificare:

variabile1 += digitalRead(P1) *10 * digitalRead(P5)?-1:1;

che messo in forma estesa e forse leggibile diventa:

byte nMul = 1;
if(digitalRead(P5))
{
  nMul = -1;
}
variabile1 += digitalRead(P1) * 10 * nMul ;

Le digital read restituiscono due valori HIGH e LOW che rispettivamente valgono 1 e 0

fabpolli:

variabile1 += digitalRead(P1) *10 * digitalRead(P5)?-1:1;

per me è arabo :smiley:

Comunque ho provato il tuo codice e funziona, l'unico problema è che se tengo premuto il pulsante continua ad aumentare finchè è premuto.
perciò l'ho modificato così:

	byte nMul = 1;
	if(digitalRead(P5))
	{
		nMul = -1;
	}
	if (button_State_1 == 0)
	{
		button_State_1 = 1;
		variabile1 += digitalRead(P1) * 10 * nMul;
	}
	else if (button_State_1 == 1 && digitalRead(P1)== LOW)
	{
		button_State_1 = 0;
	}

fabpolli:
seguo esattamente la logica che hai impresso al programma

Sapevo che avrebbe avuto quel difetto :smiley: ma non ho corretto appositamente.
Supponendo che l'operatore ternario poteva essere ostico da interpretare da chi è poco esperto ho indicato anche la soluzione "estesa" di più facile interpretazione.
Adesso che sai anche come si chiama a te la volontà di documentarti in merito :slight_smile:
P.S. = io personalmente lo uso pochissimo il ternario perché molto spesso rende il codice meno facilmente leggibile

fabpolli:
Sapevo che avrebbe avuto quel difetto :smiley: ma non ho corretto appositamente.
Supponendo che l'operatore ternario poteva essere ostico da interpretare da chi è poco esperto ho indicato anche la soluzione "estesa" di più facile interpretazione.
Adesso che sai anche come si chiama a te la volontà di documentarti in merito :slight_smile:
P.S. = io personalmente lo uso pochissimo il ternario perché molto spesso rende il codice meno facilmente leggibile

beh c'è sempre da imparare quindi mi documenterò anche se è probabile che non lo userò proprio per lasciare il codice facilmente leggibile e revisionabile.

Grazie comunque per l'aiuto

Già che c'è un codice funzionante, valuta anche queste varianti :wink:

byte nMul = 10 - (20 * digitalRead(P5));

byte in = digitalRead(P1);
variabile1 += (in && !button_State_1) * nMul;
button_State_1 = in;

PS: nel codice meglio non usare tabulazioni ma solo spazi, altrimenti a seconda di cosa si usa per vedere /modificare il file si possono avere incolonnamenti errati.

salve a tutti,
riprendo in mano il progetto dopo molto tempo (pilotare una valvola per fare foto alle gocce d'acqua che cadono)...ho cambiato un po il progetto in cui ho aggiunto un LCD 16x2 e comando tutto con 5 tasti:

puls_start -> pulsante che avvia la caduta delle gocce e con un led IR fa scattare la foto alla reflex
puls_2_gocce -> Pulsante per scegliere se far cadere 1 o 2 gocce
puls_LCD -> Pulsante per cambio pagina LCD tra le varie variabili
puls_piu -> Pulsante per aumentare la variabile della pagina attuale su LCD
puls_meno -> Pulsante per ridurre la variabile della pagina attuale su LCD

// no pulsanti per variabili
// Librerie
 #include <LiquidCrystal.h>
 LiquidCrystal lcd(12, 11, 5, 4, 6, 2);
 #include <IRremote.h>

                             //-------------------------------//
  IRsend irsend;	     //LA LIBRERIA USA IL PIN 3   //
                             //-------------------------------//

// Variabili
 int var_start = 0;
 int var_read_start_puls = 0;
 int var_ultimoStato_start = 0;
 int var_2_gocce = 1;
 int var_read_2_gocce = 0;
 int var_ultimoStato_2_gocce = 0;
 //variabili per controllo LCD
 int var_LCD_pag = 0;
 int var_read_LCD_puls = 0;
 int var_ultimoStato_LCD = 0;
 //variabili di tempo per valvola ed sony
 int var_tempo_G1 = 0;
 int var_tempo_tra_G1eG2 = 0;
 int var_tempo_scatto_G1 = 0;
 int var_tempo_scatto_G2 = 0;

// Variabili per addizione e sottrazione
 int var_read_puls_piu = 0;
 int var_ultimoStato_piu = 0;
 int var_read_puls_meno = 0;
 int var_ultimoStato_meno = 0;


// PIN
 const int puls_start = 7;
 const int puls_2_gocce = 8;
 const int led_2_gocce = 13;
 const int pin_valvola = 9;
 const int puls_LCD = 10;
 const int puls_piu = A0;
 const int puls_meno = A1;
	

void setup (){
 lcd.begin(16, 2);
 pinMode(puls_start, INPUT);
 pinMode(puls_2_gocce, INPUT);
 pinMode(led_2_gocce, OUTPUT);
 pinMode(pin_valvola, OUTPUT);
 pinMode(puls_LCD, INPUT);
 pinMode(puls_piu, INPUT);
 pinMode(puls_meno, INPUT);
 Serial.begin(9600);
}

void loop (){

// Cambio variabile LDC
 var_read_LCD_puls = digitalRead(puls_LCD);
 if ((var_read_LCD_puls == 1) && (var_ultimoStato_LCD == 0))
 {
  var_ultimoStato_LCD = 1;
  var_LCD_pag = var_LCD_pag +1;
  lcd.clear();
  if (var_LCD_pag == 4)
  {
   var_LCD_pag = 0;
  }
 }
 else if (var_read_LCD_puls == 0)
 {
  var_ultimoStato_LCD = 0;
 }
	
// Cambio variabile di start -  0 stop 1 start
 var_read_start_puls = digitalRead(puls_start);
 if ((var_read_start_puls == 1) && (var_ultimoStato_start == 0))
 {
  var_start = 1;
  var_ultimoStato_start = 1;
 }
 else if ((var_read_start_puls == 0) && (var_ultimoStato_start == 1))
 {
  var_start = 0;
  var_ultimoStato_start = 0;
 }

// Scelta 1 o 2 gocce - se 1 allora una goccia se 2 allora due gocce
 var_read_2_gocce = digitalRead(puls_2_gocce);
 if ((var_read_2_gocce == 1) && (var_2_gocce == 1) && (var_ultimoStato_2_gocce == 0))
 {
  var_2_gocce = 2;
  var_ultimoStato_2_gocce = 1;
  digitalWrite(led_2_gocce, HIGH);
 }
 if ((var_read_2_gocce == 1) && (var_2_gocce == 2) && (var_ultimoStato_2_gocce == 0))
 {
  var_2_gocce = 1;
  var_ultimoStato_2_gocce = 1;
  digitalWrite(led_2_gocce, LOW);
 }
 if (var_read_2_gocce == 0)
 {
  var_ultimoStato_2_gocce = 0;
 }

// Cambio tempi addizione

 var_read_puls_piu = digitalRead(puls_piu);
 var_read_puls_meno = digitalRead(puls_meno);
 //addizione
 if ((var_read_puls_piu == 1) && (var_ultimoStato_piu == 0))
 {
  var_ultimoStato_piu = 1;
  switch (var_LCD_pag)
  {
   case 0:
     var_tempo_G1 = var_tempo_G1+5;
     break;
   case 1:
     var_tempo_tra_G1eG2 = var_tempo_tra_G1eG2+5;
     break;
   case 2:
     var_tempo_scatto_G1 = var_tempo_scatto_G1+5;
     break;
   case 3:
     var_tempo_scatto_G2 = var_tempo_scatto_G2+5;
     break;
  }
 }
 else if (var_read_puls_piu == 0)
 {
  var_ultimoStato_piu = 0;	
 }
 //sottrazione
 if ((var_read_puls_meno == 1) && (var_ultimoStato_meno == 0))
 {
  var_ultimoStato_meno = 1;
  switch (var_LCD_pag)
  {
   case 0:
     var_tempo_G1 = var_tempo_G1-5;
     break;
   case 1:
     var_tempo_tra_G1eG2 = var_tempo_tra_G1eG2-5;
     break;
   case 2:
     var_tempo_scatto_G1 = var_tempo_scatto_G1-5;
     break;
   case 3:
     var_tempo_scatto_G2 = var_tempo_scatto_G2-5;
     break;
  }
 }
 else if (var_read_puls_meno == 0)
 {
  var_ultimoStato_meno = 0;
 }

// Riproduzione valori su LCD 16x2

//			|0123456789012345
//			|----------------
//			|T. creazione G1:
//			|ms      50      
//			|----------------


// Scrittura su LCD
 switch (var_LCD_pag)
  {
  case 0:
   //Prima pagina
    //Prima riga
     lcd.setCursor(0, 0);
     lcd.print("T. creazione G1:");
    //Seconda riga
     lcd.setCursor(0, 1);
     lcd.print("ms      ");
     lcd.setCursor(8, 1);
     lcd.print(var_tempo_G1);
    break;
  case 1:
   //Seconda pagina
    //Prima riga
     lcd.setCursor(0, 0);
     lcd.print("T. tra G1 e G2:");
    //Seconda riga
     lcd.setCursor(0, 1);
     lcd.print("ms      ");
     lcd.setCursor(8, 1);
     lcd.print(var_tempo_tra_G1eG2);
    break;
  case 2:
   //Terza pagina
    //Prima riga
     lcd.setCursor(0, 0);
     lcd.print("T. scatto G1:");
    //Seconda riga
     lcd.setCursor(0, 1);
     lcd.print("ms      ");
     lcd.setCursor(8, 1);
     lcd.print(var_tempo_scatto_G1);
    break;
  case 3:
  //Quarta pagina
    //Prima riga
     lcd.setCursor(0, 0);
     lcd.print("T. scatto G2:");
    //Seconda riga
     lcd.setCursor(0, 1);
     lcd.print("ms      ");
     lcd.setCursor(8, 1);
     lcd.print(var_tempo_scatto_G2);;
    break;
  }
Serial.println(var_2_gocce);
}

manca ancora la parte dello scatto con il led IR e l'azionamento della valvola.

Ora vengo al mio problema, il codice gira bene a parte il led 13 che continua a lampeggiare a caso, penso sia un problema di debounce per la variabile var_2_gocce ma non riesco a risolverlo, qualcuno mi può aiutare?
inoltre non so in che punto inserire un lcd.clear() per pulire lo schermo perchè se provate a cambare un valore da 0 a 5 poi 10 e tornare indietro a 5 otterremo 50 perchè resta lo 0 del 10. avete qualche consiglio?

qui trovate lo sketch su tinkercad ed è possibile simularlo:

i pulsanti sono in ordine da SX a DX: start, 1-2 gocce, pagina LCD, +, -
Nella simulazione però funziona tutto perfettamente

Grazie in anticipo

Il led ti lampeggia a caso anche sul simulatore? Se si non è un problema di debounce, il simulatore simula pulsanti ideali senza problemi di rimbalzi. In ogni caso non impazzire a fare il debounce software, fallo hardware un condensatore ed una resistenza e sei a cavallo, se vuoi una roba assolutamente affidabile ci sono anche integrati appositi per farlo, ma nella maggior parte dei casi la rete RC è già sufficiente.

Il led sul pin 13 usi quello integrato? Se no e ne hai collegato uno esterno spero tu abia messo la resistenza e non lo hai collegato diretto come nel progetto simulato altrimenti bruci il led

Concordo con @fabpolli, il debounce software di tanti pulsanti è una rottura!
Ho appena testato il chip MC14490 che gestisce fino a sei pulsanti, dacci un'occhiata.
Nel thread trovi anche il datasheet.

Federico

Grazie a tutti per le risposte,

per il debounce hardware del pulsante per le due gocce ho seguito questo schema immagine
per il momento nella simulazione funziona bene, vedrò di testarlo realmente il prima possibile ma su un arduino mega, il mio arduino uno non funziona più (è rimasto nello stato di uploading dello sketch e non riesco più a caricare nulla).

mentre riuscite a consigliarmi dove inserire lcd.clear() per pulire lo schermo perchè se cambio un valore da 0 a 5 poi 10 e tornare indietro a 5 otterremo 50 perchè resta lo 0 del 10. avete qualche consiglio?
se lo metto nel punto sbagliato lampeggia in continuazione

il clear è un operazione onerosa, normalmente quando si aggiorna solo uno/due caratteri (come nel tuo caso) è meglio evitare la clear e aggiornare tramite setCursor solo la parte che serve, nel tuo caso puoi prevedere di posizionarti sempe sopo la stringa fissa e stampare N caratteri spazio prima del vero valore, ad esempio se il range di valori ammissibili è 0-99 basta che controlli se il valore è minore di 10 stampi uno spazio e poi il valore, se il range va da 0 a 999 un paio di if per stampare uno spazio o due prima del valore e risolvi

Sì:
if(n<1000) stampi uno spazio
if(n<100) ne stampi un altro
if(n<10) ne stampi un altro ancora
poi stampi il numero.
Sono diversi passaggi, ma considera anche che la scrittura sul display non devi farla continuamente, ma solo quando sai che un valore è cambiato; in alternativa, puoi aggiornare una o due volte al secondo.

Anni fa ho avuto la stessa esigenza e l'ho risolta proprio grazie ad Arduino. Fotografare una goccia (o qualsiasi oggetto) nell'esatto momento di impatto con una superficie liquida. Non posso aiutarti sul codice, non ne ho le competenze ma il mio approccio è stato diverso e forse potrebbe darti uno spunto di riflessione.

SETUP:
Un arduino con attaccato un laser ed un sensore di luce dove questo puntava. Appena l'oggetto passava il laser, interrompendo il circuito, arduino faceva scattare il/i flash. Regolavo solo il ritardo in millesimi di secondo per beccare il momento voluto. Subito prima, durante o subito dopo l'impatto.

Questo approccio mi obbligava a lavorare a luci spente, stanza buia, con una esposizione lunga di almeno 3 secondi. Scomodo... però il risultato era eccezionale. Non avevo nessun tipo di inquinamento luminoso e mi permetteva di giocare con il/i flash per avere una luce perfetta e di effetto.

Tra l'altro lavoravo con un macro, che richiede una buna dose di luce ma restituisce immagini dettagliatissime.

lakko:
puls_start -> pulsante che avvia la caduta delle gocce e con un led IR fa scattare la foto alla reflex
puls_2_gocce -> Pulsante per scegliere se far cadere 1 o 2 gocce
puls_LCD -> Pulsante per cambio pagina LCD tra le varie variabili
puls_piu -> Pulsante per aumentare la variabile della pagina attuale su LCD
puls_meno -> Pulsante per ridurre la variabile della pagina attuale su LCD