Bloccare LED nel suo stato attuale tramite pulsante

Ciao a tutti,
vorrei realizzare un circuito composto da 7 LED (+ le dovute resistenze), e un pulsante in cui faccio accendere e spegnere in sequenza un LED alla volta che va avanti e indietro tramite arduino e se premo il pulsante vorrei che il tutto si fermasse e che il LED che è acceso rimanga acceso (ho allegato l’immagine del circuito come l’ho collegato).
Vi posto il codice che ho fatto finora che consente ai LED di accendersi in sequenza:

int pinLow = 3;
int pinHigh = 9;
int pinButton = 2;
int lag = 80;
void setup() {
  for(int thisPin = pinLow; thisPin <= pinHigh; thisPin++){
    pinMode(thisPin, OUTPUT);
  }
  pinMode(pinButton, INPUT);
}

void loop() {
  for(int thisPin = pinLow; thisPin <= pinHigh; thisPin++){
    digitalWrite(thisPin, HIGH);
    delay(lag);
    digitalWrite(thisPin, LOW);
  }
  for(int thisPin = pinHigh; thisPin >= pinLow; thisPin--){
    digitalWrite(thisPin, HIGH);
    delay(lag);
    digitalWrite(thisPin, LOW);
  } 
}

Praticamente l’obiettivo finale sarebbe fare un gioco in cui tu devi premere il pulsante quando è acceso il LED giallo e se riesci allora aumenta la velocità di scorrimento dei LED e devi riuscire di nuovo a bloccarlo al LED giallo e così via fino ad un certo limite.

La cosa che però non so proprio come fare è il modo che mi permette di fare in modo che quando premo il pulsante la sequenza si blocchi e rimanga acceso il LED che era acceso in quel momento.
Spero di essere stato chiaro e di poter ricevere una mano.

Ciao. Per fare quel tipo di funzione, secondo me dovresti usare la funzione if con gli appositi delay e fai una cosa del genere:

int pinLed1 = 3
//lo ripeti fino al pinLed 7
int pinLed 7 = 9;
int buttonPin = (esempio) 12;

void setup(){
// dichiari i pin

void loop(){
if(digitalRead(buttonPin)==HIGH){
digitalWrite(pinLed1,HIGH);
delay(esempio-->100);
}

if(digitalRead(buttonPin)==HIGH){
digitalWrite(pinLed2,HIGH);
delay(esempio-->100);
}
// e poi continui così fino al pin del led num.7 e lo personalizzi a tuo piacimento!

Spero ti sia stato d'aiuto, fammi sapere,
Luigi.

Ma se faccio in questo modo come fanno a spegnersi i LED?
Forse ho scritto male sopra.
Allora quando parte il programma voglio che si accendi un LED, si spenga e subito si accende quello accanto, poi si spegne e si accende quello accanto e così via.
Però voglio che se viene premuto il pulsante il loop si blocchi lasciando inalterati gli stati in cui si trovano i LED.

Allora devi fare in modo che fin quando il tasto è premuto, esegue un loop ben stabilito. Ci rifletterò sù :wink:

Credo che il tuo pulsante dovrebbe andare al piedino con l' interrupt e vedere tale libreria. In tal senso puoi fermare in ogni momento qualsiasi ciclo di for.
Altrimenti dovresti sondare il pulsante in tutti i cicli di for e rimandare ad una subroutine che decide il da farsi.

Grazie per il consiglio ma non so come usare l’interrupt, ho provato a guardare la libreria che mi hai lasciato nella risposta ma non capisco come devo usarla. E’ possibile usare il pulsante per bloccare la funzione loop?
E se possibile potreste mettere magari un codice di esempio di come usare la funzione interrupt.

Chiedo scusa se dico una scemenza, ma se fai per esempio. un "void stop"? che interrompe tutto il loop finchè tieni premuto il tasto? e poi quando lo rilasci ricomincia da dov'era...

Ma io vorrei fare in modo che premendo e rilasciando il pulsante il ciclo dei LED si interrompa; cioè si interrompa al momento in cui premo (quindi passa da LOW ad HIGH) e poi anche se rilascio rimane bloccato dove è per un certo tempo (per esempio 15 secondi) e poi riparta.

Ho cambiato il tipo di interrupt con quello di TimerOne, perché ho notato che la libreria sopracitata crea disturbo con le funzioni delay() e millis().
Ti posto il codice, nell’ intento che lo studi ed applichi quello che capisci dal mio esempio.

/* Spiegazione del sistema.
 * la libreria TimerOne impone un interrupt ogni decimo di secondo e va ad
 * eseguire la verifica se si e' premuto uno dei due pulsanti
 *
 * buttonPin diminuisce il valore della frequenza di scansione dei LEDS
 * buttonPin2 blocca la scansione dei LEDS, fino a quando rimane premuto.
 */

#include <TimerOne.h>                   // usato per le temporizzazioni

#define buttonPin  12                   // define per il primo pulsante
                                        // per variare la frequenza LEDS
#define buttonPin2  11                  // secondo pulsante per arresto scansione
#define TIMELAPSE 100000                // frequenza di verifica pulsanti
                                        // espresso in microsecondi

uint16_t esempio = 500;                 // valore iniziale della pausa di scansione
bool stop = 0;                          // condizione che controlla l' arresto

void interrupt() {
    /* Funzione chiamata dall'interrupt che legge i due pulsanti
     *
     * buttonPin fa variare da un massimo di 1000 a 50 millisecondi la pausa
     * di accensione di un LED
     *
     * buttonPin2 fa l' arresto
    */

    if (!digitalRead(buttonPin)) {      // se premuto
        if (esempio > 50) esempio -= 10;   // col valore di esempio maggiore di 50
                                        // lo si decrementa di 10
        else esempio = 1000;            // se fosse a 50 ritorna a 1000
    }
    if (!digitalRead(buttonPin2)) stop = 1; // se premuto, attivo il flag di stop
    else stop = 0;                      // se rilascio il buttonPin2 ritorna
                                        // a zero
}

void setup(){
    pinMode(buttonPin, INPUT_PULLUP);   // attivo basso in ingresso al pin 12
    pinMode(buttonPin2, INPUT_PULLUP);  // attivo basso in ingresso al pin 11
    // di seguito si abilitano 8 uscite dalla 2 alla 9 compresa
    for (uint8_t i=2; i < 10; i++) pinMode(i, OUTPUT);
    // si assegna un interrupt col Timer1
    Timer1.initialize(TIMELAPSE);       // imposta l'interrupt
    Timer1.attachInterrupt(interrupt);  // routine da eseguire
}

void loop(){
    for (uint8_t i=2; i < 9; i++) {     // primo ciclo accendo 1 LED
        while (stop) {};                // se ho stop attivo, esegue un loop
                                        // infinito
          // questo verifica se è il primo, di spegnere l' ultimo oppure
          // quello precedente
        if (i > 2) digitalWrite(i-1, LOW);
        else digitalWrite(8, LOW);
        digitalWrite(i, HIGH);
        delay(esempio);                 // ritardo per visualizzare l' accensione
    }
    // questo e' il ciclo che parte dal piedino piu' alto e scende indietro
    for (uint8_t i=9; i == 2; i--) {
        while (stop) {};                // se ho stop attivo, esegue un loop
        if (i < 9) digitalWrite(i + 1, LOW);
        else digitalWrite(2, LOW);
        digitalWrite(i, HIGH);
        delay(esempio);
    }
}

Spero che i commenti aiutino a ragionare.

Grazie dell’aiuto ora mi studio questa nuova libreria e spero di riuscire a risolvere il problema.

Allora ci ho pensato sù... prova a fare cosi:

//esempio casuale.
//Scrivo direttamente dal void loop.
//Finchè il buttonPin è alto, esegue il loop che fa accendere e spegnere come da te richiesto i led con un delay di 100ms. l'uno.

void loop(if(digitalRead(buttonPin)==HIGH)){
digitalWrite(led1,HIGH);
delay(100);
digitalWrite(led1,LOW);
digitalWrite(led2,HIGH);
delay(100);
digitalWrite(led2,LOW);
digitalWrite(led3,HIGH);
delay(100);
digitalWrite(led3,LOW);
digitalWrite(led4,HIGH);
delay(100);
digitalWrite(led4,LOW);
digitalWrite(led5,HIGH);
delay(100);
digitalWrite(led5,LOW);
digitalWrite(led6,HIGH);
delay(100);
digitalWrite(led6,LOW);
digitalWrite(led7,HIGH);
delay(100);
digitalWrite(led7,LOW);
digitalWrite(led6,HIGH);
delay(100);
digitalWrite(led6,LOW);
digitalWrite(led5,HIGH);
delay(100);
digitalWrite(led5,LOW);
digitalWrite(led4,HIGH);
delay(100);
digitalWrite(led4,LOW);
digitalWrite(led3,HIGH);
delay(100);
digitalWrite(led3,LOW);
digitalWrite(led2,HIGH);
delay(100);
digitalWrite(led2,LOW);
digitalWrite(led1,HIGH);
delay(100);
digitalWrite(led1,LOW);
digitalWrite(led1,HIGH);
delay(100);
digitalWrite(led1,LOW);

Spero funzioni così :grin: :wink:

Dealer:
Grazie dell'aiuto ora mi studio questa nuova libreria e spero di riuscire a risolvere il problema.

Non è difficile, ti richiama una routine allo scadere dei microsecondi impostati. Una volta finito riprende a fare quello prima della interruzione.

Luigi grazie della risposta però quello che hai fatto tu è la parte che permette di accendere e spegnere i LED in sequenza, a me serve un modo che mi permetta di bloccare questa funzione.
Tra l'altro, non so se hai sbagliato o non ti sei accorto, comunque non si può mettere la condizione "if" tra le parentesi tonde del loop.

Dovresti usare millis() al posto dei delay().
Inizia con un led, per imparare l'uso di millis().
Poi passa a due led e quindi a tre e poi a tutti i tuoi led.

Fatto questo, vedrai che sarà semplicissimo introdurre la condizione sul pulsante.

Grazie a tutti, sono riuscito a risolvere il problema facendo uno switch, vi posto il codice se vi interessa:

int pinLow = 3;
int pinHigh = 9;
int pinButton = 2;
int lag = 200;
volatile byte stato = 0;
volatile byte precedente = 20;

void setup() {
  for(int thisPin = pinLow; thisPin <= pinHigh; thisPin++){
    pinMode(thisPin, OUTPUT);
  }
  pinMode(pinButton, INPUT);
  attachInterrupt(digitalPinToInterrupt(pinButton), Led_on, RISING);
  Serial.begin(9600);
}

void loop() {
  Serial.println(lag);
  if (precedente==20) {
    for(stato = 0; stato<=13; stato++) {
      if(precedente!=20)
        break;
      switch(stato){
        case 0:
          digitalWrite(3, HIGH);
          delay(lag);  
        break;
    
        case 1:
          digitalWrite(3, LOW);
        break;
    
        case 2:
          digitalWrite(4, HIGH);
          delay(lag); 
        break;
    
        case 3:
          digitalWrite(4, LOW);
        break;
        
        case 4:
          digitalWrite(5, HIGH);
          delay(lag);  
        break;
    
        case 5:
          digitalWrite(5, LOW);
        break;
        
        case 6:
          digitalWrite(6, HIGH);
          delay(lag);  
        break;
    
        case 7:
          digitalWrite(6, LOW);
        break;
        
        case 8:
          digitalWrite(7, HIGH);
          delay(lag);  
        break;
    
        case 9:
          digitalWrite(7, LOW);
        break;
  
        case 10:
          digitalWrite(8, HIGH);
          delay(lag);  
        break;
    
        case 11:
          digitalWrite(8, LOW);
        break;
  
        case 12:
          digitalWrite(9, HIGH);
          delay(lag);  
        break;
    
        case 13:
          digitalWrite(9, LOW);
        break;
  
        default: 
          stato = 0;
      }
    }
  }
  else {
      digitalWrite(precedente/2+3, HIGH);
      delay(5000);
      digitalWrite(precedente/2+3, LOW);
      if(((precedente/2+3) == 6) && (lag == 25)) {
          for(int thisPin = pinLow; thisPin <= pinHigh; thisPin++){
            digitalWrite(thisPin, HIGH);
            delay(80);
            digitalWrite(thisPin, LOW);
          }
          for(int thisPin = pinHigh; thisPin >= pinLow; thisPin--){
            digitalWrite(thisPin, HIGH);
            delay(80);
            digitalWrite(thisPin, LOW);
          }
          lag = 400;
      }
      if((precedente/2+3) == 6) {
        lag = lag/2;
      }
      precedente=20;
  }
}

void Led_on() {
  precedente=stato;
}

Bravo!
Ho imparato qualcosa anche dal tuo esempio.
Come vedi il principio sta nel mettere un interrupt.