Switching colore LED RGB con pulsanti

'Giorno a tutti, torno ancora qui per l'ultimo grande ostacolo di un progetto semplicissimo.

Ho costruito un progetto costituito da un Arduino Nano che pilota un LED RGB attraverso due pulsanti. In particolare, uno dovrebbe switchare il colore del LED in questione, l'altro dovrebbe accendere e spegnere il LED, facendo in modo che, riaccendendolo, il colore resti lo stesso precedentemente impostato con l'altro pulsante.

Per quanto riguarda lo switching colore ho scritto questo codice, estremamente semplice.

int RED=11;
int GREEN=10;
int BLUE=9;
int P1=2; //primo pulsante
int P2=3; //secondo pulsante
int val1=0;
int val2=0;
int val1a=0;
int val2a=0;
int stato1=0;
int stato2=0; //utili per il debounce
int colore=0; //ordine per switchare il colore


void setup() {
pinMode(RED, OUTPUT);
pinMode(GREEN, OUTPUT);
pinMode(BLUE, OUTPUT);
pinMode(P1, INPUT_PULLUP);
pinMode(P2, INPUT_PULLUP); //i pulsanti sono collegati direttamente al GND, usando le resistenze interne

}

void loop() {


val1=digitalRead(P1);

if ((val1==1)&&(val1a==0)) {
  stato1 = 1 - stato1;
  delay(15);                                           //debounce per P1
  if (colore<6) colore=colore+1;
  else colore=0;                                     //selezionare tra 7 colori
}

val1a=val1;                                           //utile per il debounce

switch (colore)
{

  case 1:                                              //Rosso
  digitalWrite(RED, HIGH);
  digitalWrite(GREEN, LOW);
  digitalWrite(BLUE, LOW);
  break;

  case 2:                                              //Giallo
  digitalWrite(RED,HIGH);
  digitalWrite(GREEN, HIGH);
  digitalWrite(BLUE, LOW);
  break;

  case 3:                                             //Verde
  digitalWrite(RED, LOW);
  digitalWrite(GREEN, HIGH);
  digitalWrite(BLUE, LOW);
  break;

  case 4:                                             //Celeste
  digitalWrite(RED, LOW);
  digitalWrite(GREEN, HIGH);
  digitalWrite(BLUE, HIGH);
  break;

  case 5:                                             //Blu
  digitalWrite(RED, LOW);
  digitalWrite(GREEN, LOW);
  digitalWrite(BLUE, HIGH);
  break;

  case 6:                                             //Viola
   digitalWrite(RED, HIGH);
  digitalWrite(GREEN, LOW);
  digitalWrite(BLUE, HIGH);
  break;

  case 0:                                             //Bianco
  digitalWrite(RED,HIGH);
  digitalWrite(GREEN, HIGH);
  digitalWrite(BLUE,HIGH);
  break;
  
}

}

Qui viene il grosso problema: inspiegabilmente, nel selezionare i colori, i valori di HIGH e LOW sono invertiti. Ovvero, va da Celeste (Stato1) a Verde (Stato6), dopodiché si spegne (Stato 0).
Perché sta cosa? Non riesco a capire dove ho sbagliato.

Inoltre: il secondo pulsante come dovrei programmarlo? Ho provato a mettere un comando uguale al P1 ma con R:LOW, G:LOW, B:LOW, ma il pulsante non si accorge neanche se lo premo.

So che è una cosa mooolto basilare. Mi aiutereste, per favore?

In if ((val1==1)&&(val1a==0)) {...} devi mettere subito val1a=val1;.

Fai un ciclo veloce per la lettura dei pulsanti e imposta le uscite solo quando c'è un cambiamento, non a ogni ciclo.

Ogni volta che c'è una variazione del colore (if (colore!=colorePrecedente)) aggiorna una cella della EEPROM con il valore corrente: EEPROM.update(0, colore);
Per farlo, all'inizio devi includere eeprom.h.
La cosa migliore sarebbe farlo un attimo prima dello spegnimento, ma servirebbe un minimo di elettronica in più.

Credo che il promo problema siano i rimbalzi, con un debouce fatto csì sicuramente hai problemai, implementalo hardware se puoi o al limite software qui un esempio.
Dopodiché vedrai scomparire effetti indesiderati e seguendo il consiglio fornito da @Datman memorizzati il colore precedente e setta i pin solo sulla variazione di colore.
Per gestire il secondo pulsante fai allo stesso modo due variabili, una con lo stato precedente (acceso/spento) e una con lo stato attuale, quando premi il pulsante vari lo stato attuale, se è uguale al precedente non fai nulla, altrimenti se è cambiato ed è spento metti tutti i pin a low, se è acceso campi il valore del colore precedente in modo tale da rientrare nel case di gestione dei colori e accendere il led con il colore corretto
@Datman
Nel acso dell'utente l'EEPROM non c'entra nulla non sta parlando di spegnimento della mcu ma di spegnere e accendere il led alla pressione del pulsante

Ah, è vero. Hai ragione!
Beh, adesso può mantenere lo stato anche alla riaccensione! :slight_smile:

L'antirimbalzo non è molto efficace, ma potrebbe bastare. Sicuramente un condensatore da circa 100nF in parallelo al pulsante aiuterebbe.

Temo che mi manchino degli elementi fondamentali per capire.
Sono davvero alle prime armi, ci sono molte cose che non so di quelle che mi avete detto: non riesco a configurare il debounce come spiegato dal tutorial di @fabpolli, né come impostare un loop con le due variabili che ha consigliato.
Oltretutto non so in cosa si traduca

Fai un ciclo veloce per la lettura dei pulsanti e imposta le uscite solo quando c'è un cambiamento, non a ogni ciclo.

Grazie comunque tantissimo per l'aiuto, se poteste chiarirmi questi dubbi mi fareste un favore enorme. Grazie :slight_smile:

TheSleeper1928:
Temo che mi manchino degli elementi fondamentali per capire.
Sono davvero alle prime armi, ...

Direi di si, in questi casi conviene sempre procedere per gradi, ovvero non ostinarti a tentare di integrare il codice che già hai (che forse è frutto di copia incolla da altri esempi o roba del genere) parti dal codice del debounce che ti ho postato e inizia a modificarlo in modo da stampare sulla seriale qualcosa tipo "Premuto" solo se il pulsante è stato premuto, se premuto devi stampare una sola volta sulla seriale "Premuto".
A quel punto sei già a metà strada, replichi il codice per il secondo pulsante e fai la solita cosa stampando un altra scritta, quando hai raggiunto questo obiettivo sei quasi arrivato alla soluzione, ti basta inserire il tuo codice (cambio colore o led on off) al posto del codice che scrive sulla seriale e arriverai a capo del problema.
Poi per la cronaca se possibile il debounce si fa hardware che così il codice diviene più semplice ma farlo software in questo caso credo sia propedeutico per muovere i primi passi nellla programmazione di Arduino

Prima di tutto, come consiglio sempre, usa debounce hardware ... un condensatore da 100n fra il pin e massa, ed una resistenza da 100 ohm fra pin e pulsante, e ti togli dalle scatole qualsiasi routine di debounce software, semplificando lo sketch ed evitando i delay bloccanti ... :wink:

Poi, se devi leggere il pulsante una sola volta per ogni pressione, dovrai usare almeno un ciclo if-else ed una flag (variabile di stato) per ogni pulsante ... esempio, fai la digitalread, e subito dopo esegui un'if solo se il pulsante e' premuto e la relativa flag e' a zero, nell'if metti la flag ad uno ... poi nell'else esegui solo se il pulsante e' rilasciato e la flag ad uno, e rimetti la flag a zero ... in questo modo, al momento della pressione quello che c'e' nell'if viene eseguito una sola volta, poi ignorato finche' il pulsante rimane premuto, quando lo rilasci l'else rimette la flag a zero, cosi alla prossima pressione rieseguira' una sola volta quello che c'e' nell'if, e cosi via ... :wink:

L'altro modo e' usare gli interrupt impostandoli come "rising" oppure "falling", in base a come e' collegato il pulsante, se chiude verso VCC o verso GND ...

Etemenanki:
Prima di tutto, come consiglio sempre, usa debounce hardware ... un condensatore da 100n fra il pin e massa, ed una resistenza da 100 ohm fra pin e pulsante, e ti togli dalle scatole qualsiasi routine di debounce software, semplificando lo sketch ed evitando i delay bloccanti ... :wink:

Sfortunatamente non posso farlo in Hardware, ho già chiuso e sigillato il circuito. Sono stato poco previdente, ma è la mia prima esperienza.

Poi, se devi leggere il pulsante una sola volta per ogni pressione, dovrai usare almeno un ciclo if-else ed una flag (variabile di stato) per ogni pulsante ... esempio, fai la digitalread, e subito dopo esegui un'if solo se il pulsante e' premuto e la relativa flag e' a zero, nell'if metti la flag ad uno ... poi nell'else esegui solo se il pulsante e' rilasciato e la flag ad uno, e rimetti la flag a zero ... in questo modo, al momento della pressione quello che c'e' nell'if viene eseguito una sola volta, poi ignorato finche' il pulsante rimane premuto, quando lo rilasci l'else rimette la flag a zero, cosi alla prossima pressione rieseguira' una sola volta quello che c'e' nell'if, e cosi via ... :wink:

L'altro modo e' usare gli interrupt impostandoli come "rising" oppure "falling", in base a come e' collegato il pulsante, se chiude verso VCC o verso GND ...

Di tutto ciò purtroppo ho capito molto poco. Vorrà dire che tornerò sul manuale di Arduino (un pdf trovato su questo forum) e vedrò di chiarire i dubbi da me, grazie mille comunque :slight_smile:

Pseudocodice buttato li molto al volo, e' da controllare ...

   if ((digitalRead(pin-pulsante1) == 1) && (prev1 == 0))
   {
      ... operazione da eseguire alla pressione, una volta ...
      prev1 = 1;
   }
   else if ((digitalRead(pin-pulsante1) == 0) && (prev1 == 1))
   {
      ... operazione da eseguire al rilascio (se c'e'), una volta ...
      prev1 = 0;
   }

prev1 e' la flag, impostala come bool e 0 nel setup ... se i pulsanti sono due, ovviamente ti servira' una seconda flag per il secondo, nonche' un secondo ciclo if-else ... il reset della flag va fatto all'interno dei cicli if, mi sembra che tu l'abbia messo invece all'esterno ... inoltre, se quello "stato1 = 1 - stato1" e' per invertire la variabile, la sintassi corretta dovrebbe essere "stato1 != stato1" ... :wink:

TheSleeper1928:
Temo che mi manchino degli elementi fondamentali per capire.
Sono davvero alle prime armi, ci sono molte cose che non so di quelle che mi avete detto: non riesco a configurare il debounce come spiegato dal tutorial di @fabpolli, né come impostare un loop con le due variabili che ha consigliato.
Oltretutto non so in cosa si traduca
Grazie comunque tantissimo per l'aiuto, se poteste chiarirmi questi dubbi mi fareste un favore enorme. Grazie :slight_smile:

far funzionare qualcosa "direttamente" con i pulsanti è troppo sbagliato, (SEMPRE)

il pulsante deve sempre cambiare di stato una variabile che deve "congelarsi in quello stato" per un minimo di tempo in modo che il comportamento umano stacchi il dito dal bottone in un tempo ragionevole (circa 300 millisecondi) cosi funzionerà sempre tutto,

bisogna scrivere queste righe di codice una volta per tutte che servono sempre