informazione su possibile interruzione attraverso pulsante

Salve a tutti, mi spiego meglio, tempo fa ho realizzato un programma per comandare una striscia a led rgb, in pratica appena parte il colore è bianco, e variando i vari valori, dopo poco sfumano i colori passando dal verde acqua al verde al rosa rosso e cosi via. Ora mi chiedevo se fosse possibile inserire un pulsantino, dicendo nel programma che quando lo si preme si stoppa diciamo il ciclo. Esempio se è sul verde tendente al giallo e io lo premo mi si ferma li e non va avanti, e quando lo ripremo riparte. Vorrei aggiungere questa piccola cosa ma non saprei come fare. Utilizzo un Arduino Uno, una striscia led RGB comprata a poco su eBay. Se avete bisogno di altre informazione chiedetele pure spero di essere stato abbastanza chiaro.
Questo è il codice che ho usato:

int pin1 = 6; int pin2 = 5; int pin3 = 3;
int value3; int value2; int value1;
int x;
int y;
void setup(){

  x = 10000;
  y = 100;
 
  // bianco
value1 = 255;
value2 = 255;
value3 = 255;

analogWrite(pin1, value1);  //r
analogWrite(pin2, value2);  //g
analogWrite(pin3, value3);  //b

 // migreazione all'azzurro
 for (int x=255; x>=0; x--) {
   value1 = x;
   analogWrite(pin1, value1);
   delay(y);
 }
 //azzurrro
 delay(x);

}

void loop(){
 
 //migrazione al verde
 for (int z=255; z>=0; z--) {
   value3 = z;
   analogWrite(pin3, value3);
   delay(y);
 }
  // verde
  delay(x);
 
  //migrazione al giallo
 for (int x=0; x<255; x++) {
   value1 = x;
   analogWrite(pin1, value1);
   delay(y);
 }
  // giallo
  delay(x);
 
   
 //migrazione al arancione
 for (int y=255; y>=165; y--) {
   value2 = y;
   analogWrite(pin2, value2);
   delay(y);
 }
  // arancione
  delay(x);
 
 
  //migrazione al rosso
 for (int y=165; y>=0; y--) {
   value2 = y;
   analogWrite(pin2, value2);
   delay(y);
 }
  // rosso
  delay(x);
 
 
  //migrazione al rosa
 for (int z=0; z<=127; z++) {
   value3 = z;
   analogWrite(pin3, value3);
   delay(y);
 }
  // rosa
  delay(x);
 
  //migrazione al magenta
 for (int z=127; z<256; z++) {
   value3 = z;
   analogWrite(pin3, value3);
   delay(y);
 }
  // magenta
  delay(x);
 
 
  //migrazione al viola
 for (int x=255; x>=143; x--) {
   value1 = x;
   analogWrite(pin1, value1);
   delay(y);
 }
  // viola
  delay(x);
 
 
  //migrazione al blu
 for (int x=143; x>=0; x--) {
   value1 = x;
   analogWrite(pin1, value1);
   delay(y);
 }
  // blu
  delay(x);
 
  //migrazione al azzurro
 for (int y=0; y<256; y++) {
   value2 = y;
   analogWrite(pin2, value2);
   delay(y);
 }
  // azzurro
  delay(x);
 
}

Grazie per l'aiuto.

Non avendo il codice non ho idea di dove inserire il codice, quindi devi vedere tu dove inserirlo.

Carica nell'IDE l'esempio Button
Al posto di questo codice:

buttonState = digitalRead(buttonPin);

  // check if the pushbutton is pressed.
  // if it is, the buttonState is HIGH:
  if (buttonState == HIGH) {
    // turn LED on:
    digitalWrite(ledPin, HIGH);
  }
  else {
    // turn LED off:
    digitalWrite(ledPin, LOW);
  }

ci metti:

while (digitalRead(buttonPin);

Solo che devi vedere di integrarlo nel tuo codice e se il tuo codice usa delay() la modifica non funzionerà, per cui
dovrai sostituire delay con l'uso di millis(). Se non posti il codice non si va lontano.

Ciao.

Non si può proprio integrare, perché usi delay(). Devi prendere esempio dal codice Blink without Delay, dove come vedi il led si accende e spegne secondo tempistiche specificate e nell'attesa che queste tempistiche scadano si può continuare ad eseguire altro codice.

A parole con il delay equivale a dire:
Fai questo e quello (altro codice)
ora conta il tempo fino a 1000 ms e non fare altre che questo fino a che non hai contato 1000ms (delay(1000))

E ovvio il micro non esegue null'altro per 1000ms.

Nel blink senza delay a parole equivale a dire:

Salva tempo corrente in previousMills
controllo se millis() (che ora è il tempo corrente all'istante T) - previuosMillis è maggiore di 1000 esegui questo codice, altrimenti esegui quest'altro codice.

All'instante T previuousMillis = millis() per esempio vale 10000 (dicimila)
qui c'è l'istruzione seguente che considera essere previusMillis come uno o più istanti precedenti
qui c'è un'altra istruzione e quindi sarà passato tot tempo
qui leggo il tempo corrente millis() che ora vale 101100

101100 - 10000 = 1100 sono passati 1100 millesimi di secondo che sono maggiori di 1000 quindi esegui il codice dentro {} della if che fa il controllo if ( (millis() - previousMills) > 1000) { }

Ciao.

Quindi dovrei modificarlo sostituendo il delay con il millis() ?

Intanto dovresti cominciare a correggere il tuo post quà sopra racchiudendo il codice entro gli appositi TAG "code" (vd. regolamento, punto 7). Se vai in edit, sono quelli che inserisce il bottone # ... il terzultimo della seconda fila.

Poi ...
... NO, non puoi semplicemente mettere millis() al posto di delay() ma devi modificare il codice.

Guarda QUI per vedere di cosa stiamo parlando ... :roll_eyes:

Guglielmo

Ecco post modificato, comuque si lo so, intendevo dire modificare tutto il codice per inserire il millis().

Bé ... "tutto" è una parolona ...
... dovrai modificare una parte del codice per togliere la delay() ed adattare il codice all'uso della millis() ... :grin:

Guglielmo

P.S. : Sicuramente ti è utile anche la lettura di QUEST'altro articolo di Leo ... :wink:

Grazie per le risposte, in questi giorni proverò a modificarlo e lo posterò qui, grazie ancora.

Ho un problema, se al posto del delay uso la funzione millis() il programma continua ad andare facendo gli altri cambi di colore, come si potrebbe fare, cioè con la funzione delay per cambiare il valore ci mette un tot di tempo e poi rimane fermo a quel colore ma col millis lui andrebbe avanti facendo gli altri. Soluzioni ?

Ho preso in prestito ad uwe (ma lui non lo sa) la sfera di cristallo e vedo che tu hai usato millis() nel modo sbagliato, tuttavia non posso postare il tuo codice, perché uwe ha protetto con password il trasferimento dati. :grin:

Aspetta, un momento se tu posti il codice, io posso rendere la sfera ad uwe prima che se ne accorga, così mi evito il cazziatone. :grin:

Ciao.

Il codice è scritto sopra, la mia era una domanda, se in quel codice integro il millis() al posto del delay rischio che non mi vada più in sequenza ?

Ho un problema, se al posto del delay uso la funzione millis() il programma continua ad andare facendo gli altri cambi di colore, come si potrebbe fare, cioè con la funzione delay per cambiare il valore ci mette un tot di tempo e poi rimane fermo a quel colore ma col millis lui andrebbe avanti facendo gli altri. Soluzioni ?

Da questo post io ho dedotto che avevi provato ad usare millis() e che ti eri accorto di un problema. L'unico indizio che si trattava di una supposizione è nel verbo "andrebbe" che mi è sfuggito.

Se il tempo di delay è uguale per tutti i colori, potresti pensare di fare così:

 //migrazione al verde
 for (int z=255; z>=0; z--) {
   value3 = z;
   analogWrite(pin3, value3);
   delay(y);  // questo delay qui impedisce l'intercettazione del tasto per tutto il tempo necessario a completare il ciclo for

 }
  // verde
  // delay(x);
  getButton(); // nuova funzione utente che attende x tempo e controlla continuamente se è stato premuto un tasto

Con una funzione getButton(arg, arg, ...) puoi anche gestire ritardi ti tempo variabili, però è complesso
e non saresti in grado di scriverla.

C'è una soluzione, potresti usare gli interrupt, documentati su questi e prova a tirare fuori un codice
di test che li usa per far qualcosa quando viene premuto il pulsante.

In sostanza tutti i pin possono provocare (sollevare) una interruzione della cpu, quando ciò avviene del codice
utente viene eseguito il quale imposta una variabile ad un valore es buttonPushed = 1

In ogni posto in cui impegni il micro (es nei vari for) ci scrivi while (buttonPushed == 1);

Il micro in sostanza rimane ad eseguire codice della while(buttonPushed == 1) che è un ciclo infinito con una condizione di uscita che è buttonPushed == 0.

Otterresti il blocco a patto di inserire il while(button.... in ogni ciclo
Ma ciò non risolve il problema del delay, che risolverai dopo.

Ti consiglio di concentrati sul problema non lavorando sul codice attuale, crea un altro progetto
con un solo for al cui interno oltre a fare il gioco di luci, inserisce while (buttonPushed == true);
Abilita un interrupt con attachInterrupt() e nella funzione utente ci metti:

buttonPushed = true;

La variabile buttonPushed deve essere dichiarata globale così:
volatile boolean buttonPushed = false;

Appena premi il pulsante il for del gioco di luci si deve fermare e non sarà più possibile farlo riprendere, ma c'è una soluzione, cioè rimettere la variabile buttonPushed = false, questa cosa potrebbe anche farla la funzione attaccata
all'interrupt, ma per il momento ti conviene testare il fatto che il for del gioco di luci si fermi, poi posti il codice
e io ci aggiungo il resto per sbloccare il for.

Ciao.

Grazie per l'aiuto :), ieri stavo provando con un singolo led ed un singolo colore integrando l'interrupt, in questi giorni proverò ha riscrivere un codice più breve con meno cambi colore solo per vedere se funziona poi lo postero qui. Grazie ancora :slight_smile:

Finalmente ho trovato un po' di tempo e ho iniziato a provare il codice, per ora ho fatto solo un paio di colori e sembra tutto funzionare volevo solo un vostro parere sul codice e se continuare cosi come sto procedendo grazie. :slight_smile:

int pin1 = 9; int pin2 = 11; int pin3 = 10;
int value3; int value2; int value1;
int x,y ,z= 255, z1=0,z2 =255, z3 =0, z4 = 0, z5= 0;
boolean k, g;
const int buttonPin = 2;     // ingresso pulsante
int buttonState = 0;      // variabili del
long previousMillis = 0;
unsigned long interval = 50;
void setup(){
 buttonState = 0; 
  // bianco
value1 = 255; 
value2 = 255;
value3 = 255;
 Serial.begin(9600);
analogWrite(pin1, value1);  //g
analogWrite(pin2, value2);  //b
analogWrite(pin3, value3);  //r

}

void loop(){
   
  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   
    k = 1;
  }
  else {k=0;}
  
  
    if (digitalRead(buttonPin) == HIGH) {
    delay(30); //piccola attesa per evitare i rimbalzi
    if (digitalRead(buttonPin) == HIGH) { //se il pulsante è ancora premuto si continua
      //inverto lo stato del led
      if (g == 0) {
        g = 1; 
         Serial.println(g);
         Serial.print("bottone premuto");
      }
      
      else {
        g = 0;
       
      
      }
      analogWrite(pin1, value1);  //g
      analogWrite(pin2, value2);  //b
      analogWrite(pin3, value3);  //r
      delay(800); //fermo la situazione per avere il tempo di lasciare il pulsante
    }
  }
  
  
 if(g == 0)
 { 
   //migrazione al azzurro
   for (; z>=0 && k ==1 ; z--) {
     value3 = z;
     analogWrite(pin3, value3); //(rosso va a 0)
    
     Serial.println(z);
     k = 0;
     if(z==0){z1 = 1;}
   }
   
   //migrazione al blu
   
   if(z1 == 1)
   {
     for(; z2>=0 && k==1; z2--) //(verde va a 0 )
     {
       value1 = z2;
       analogWrite(pin1, value1);
       Serial.println(z2);
     
     k = 0;
     
     if(z2==0){z3 = 1;}
     }
   }
   //migrazione al viola
   if(z3 == 1)
  
  { 
    for(; z4>=0 && k==1; z4++) //(rosso va a 255 )
     {
       value3 = z4;
       analogWrite(pin3, value3);
       Serial.println(z4);
     
     k=0;
     if(z4==255) {z5 = 1;}
  }
 }
 
 
}
}

Continuare così non mi sembra il caso, appena aggiungi l'altro codice la leggibilità diminuisce ulteriormente.
Ci sono altri modi realizzare l'algoritmo, sta a te sperimentare al fine di trovare soluzioni alternative che ti permettono di realizzare l'algoritmo in modo che sia:

  1. Leggibile: Si capisce al volo cosa fa il programma.
  2. Facilmente modificabile: Grazie al punto 1 modificare il programma è più semplice
  3. Riutilizzabile: Non sempre è possibile scrivere codice riutilizzabile anche per un programmatore esperto.
    Ciò potrebbe comportare un ulteriore investimento di tempo che non sempre è ripagato.
    Occorre esperienza per valutare se investire tempo o meno su questo punto
  4. Efficiente: Questa fase è riservata per ultimo e non è sempre necessaria. Se è necessario significa
    che le risorse sono insufficienti per le funzionalità che vogliamo introdurre. Valutare se e dove intervenire
    comporta una spesa di tempo che non sappiamo prima dove ci porterà. L'ottimizzazione potrebbe non essere
    sufficiente e lo scopriamo solo dopo giorni di lavoro, se lo avessimo saputo prima avremmo ripiegato su
    una piattaforma di sviluppo con più risorse.

Visto che al momento il codice sembra funzionare, ti consiglio di investire un poco ti tempo per
effettuare il refactoring.

Le variabili globali devono avere nomi lunghi e molto significativi, k, x, y, z sono nomi corti e corto deve essere il loro
scope, cioè devono essere locali ed essere distrutte poche righe di codice dopo la creazione.

Il data type "int" è grande 16 bit, e il range di valori ammesso comprende valori negativi.
Usare int solo se:
Conterrà un valore negativo.
Se il valore supera la dimensione di un byte (8 bit).

Se una variabile non cambia durante il programma allora è un costante, per cui usare "const"

La lunghezza del nome di una variabili non occupa più spazio in memoria, per cui perché non approfittarne per
trovare dei nomi di variabile più significativi.

L'implementazione può essere modificata in modo da realizzare una macchina a stati, documentati
su switch case. I vantaggi sono molteplici, uno dei principali è quello di dividere in piccoli pezzetti il codice da eseguire, la sequenza di questo pezzetti di codice lo decide la macchina a stati.
Inoltre il codice diventa molto comprensibile e i problemi sono localizzati all'interno di uno stato, che tanto più piccolo è più facile è modificarlo, comprenderlo ecc (questo non vuol dire che l'obbiettivo è creare uno stato composto da una sola istruzione).

Sono cosciente che ti ho messo davanti tante cose, poco chiare. Se vuoi puoi provare a introdurre gli altri colori
ma questo sketch te lo tieni come promemoria, cioè lo commenti e lo salvi con un altro nome, questo per avere sempre almeno una versione funzionante, e una in sviluppo. Capita spesso di ripartire da zero e alcuni pezzi del codice precedente possono tornare utili.

Ciao.