Aiuto su codice base pulsante-led

Salve a tutti,
sono appena arrivato in questo forum e solo da qualche giorno sto utilizzando Arduino (con precisione Arduino Duemilanove). Seguendo vari tutorial online ho svolto vari esercizietti che mi hanno fatto capire alcune meccaniche di Arduino, subito interessanti.

Ecco però che sorge il primo problema: seguendo una guida sull'interazione di un pulsante con un led, dovevo far in modo di attivare il pulsante e fa andare in lampeggiamento il led e al secondo tocco del pulsante il led dovrebbe spegnersi. Il mio problema sorge nel secondo momento, lo spegnimento, che non avviene istantaneamente.

Posto il codice per capirci meglio:

// Il led lampeggia se premo il pulsante  
// premendo una seconda volta il pulsante si spegne il led  
  
#define LED 13                // LED collegato al pin digitale 13  
#define BUTTON 7              // pin di input dove è collegato il pulsante  
int val = 0;                  // val per conservare lo stato del pin di input  
int vecchio_val = 0;          // vecchio_val per conservare lo stato del pin di input al passo precedente  
int stato = 0;                // ricorda lo stato in cui si trova il led, stato = 0 led spento, stato = 1 led acceso  
  
void setup() {  
  pinMode(LED, OUTPUT);       // imposta il pin digitale come output  
  pinMode(BUTTON, INPUT);     // imposta il pin digitale come input  
}  
  
void loop() {  
  val = digitalRead(BUTTON);  // legge il valore dell'input e lo conserva  
  
  // controlla se è accaduto qualcosa  
  if ((val == HIGH) && (vecchio_val == LOW)){  
    stato = 1 - stato;  
    delay(15);                // attesa di 15 millisecondi  
  }   
  
  vecchio_val = val;          // ricordiamo il valore precedente di val  
  
    if (stato == 1) {  
    digitalWrite(LED, HIGH);  // accende il LED  
    delay(1000);              // aspetta un secondo  
    digitalWrite(LED, LOW);   // spegne il LED  
    delay(1000);              // aspetta un secondo  
  }  
  else {  
    digitalWrite(LED, LOW);    //spegne il led  
  }  
}

Il problema è appunto che per spegnere il led in pratica devo tener premuto per qualche secondo il pulsante, al contrario io invece vorrei che il pulsante funzionasse all'istante e facendo quindi tornare, in un istante, il led allo stato 0, ossia spento.

Spero di essere stato chiaro nella spiegazione del problema e spero altrettanto che qualcuno possa darmi una mano! Grazie mille in anticipo :smiley:

Ciao il tuo problema è determinato da questo passaggio

 if (stato == 1) {  
    digitalWrite(LED, HIGH);  // accende il LED  
    delay(1000);              // aspetta un secondo  
    digitalWrite(LED, LOW);   // spegne il LED  
    delay(1000);              // aspetta un secondo  
  }

Una volta entrato nella if hai due delay che devono essere eseguiti e solo dopo trascorso tale tempo il tuo programma potrà andare a controllare lo stato del pulsante e spegnere il led se il pulsante é premuto.

Molto interessante. C'è un modo per ovviare al problema evitando di togliere quei ritardi che mi danno il lampeggiamento del led?

Non si può ovviare al problema senza togliere i delay perchè come hai capito sono bloccanti cioè bloccano l'esecuzione del codice.
Un modo per aggirare il problema è quello di usare il millis().
Trovi tutte le informazioni necessarie nel reference e c'è un esempio di lampeggio del led che non utilizza i delay ma appunto la funzione millis(),dagli un'occhiata e vedrai che ti sarà utile.

Edit. reference è una cartella che trovi all'interno del pacchetto che hai scaricato per l'ide :slight_smile:

Il Reference lo trovi anche on line sul sito di Arduino: Arduino - Home

Sapevo di poter contare sul vostro aiuto e infatti sono riuscito ad ottenere ciò che volevo :smiley:

Ecco, adesso non vorrei essere troppo palloso, ma è sorto un altro piccolo problema che penso e spero sia di facile risoluzione.
In pratica adesso ho un ritardo, probabilmente di 1 o 2 secondi massimo all'accensione dell led dopo aver premuto il pulsante.
Posto nuovamente il codice in modo da capire anche se ho manomesso troppo con la funzione milliss:

// Il led lampeggia se premo il pulsante  
// premendo una seconda volta il pulsante si spegne il led  
  
#define LED 13                  
#define BUTTON 7                
int val = 0;                    
int vecchio_val = 0;            
int stato = 0; 
int ledState = LOW;             
long previousMillis = 0;        
long interval = 800;


void setup() {  
  pinMode(LED, OUTPUT);         
  pinMode(BUTTON, INPUT);      
}  
  
void loop() {  
  val = digitalRead(BUTTON);    
  
  // controlla se è accaduto qualcosa  
  if ((val == HIGH) && (vecchio_val == LOW)){  
    stato = 1 - stato;  
                   
  }   
  
  vecchio_val = val;           
  
    if (stato == 1) { 
      unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) {
     
    previousMillis = currentMillis;   

    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;

    
    digitalWrite(LED, ledState); 
  }
    }  
  else {  
    digitalWrite(LED, LOW);     
  }  
}

Considerate che sono alle primissime armi, quindi per la funzione milliss mi sono limitato a capire dove dovevo copiare le varie parti dall'esempio nel reference.

In pratica adesso ho un ritardo

Se non vuoi il ritardo all'accensione devi accendere il led subito dopo aver controllato la variabile stato

if (stato == 1) { 
      unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) {

se stato ==1 accendi subito il led e poi procedi con la millis e trascorso il tempo lo spegni....tu invece stai aspettando che sia passato il tempo da te impostato e poi accendi il led.

Ciao, i miei 2 cents non c'entrano col tuo problema, ma... Visto che sei alle prime armi abituati ad indentare correttamente il codice. CTRI+T nell'IDE ti sarà d'aiuto. L'indentazione non è una questione estetica, serve a capire il flusso di esecuzione "a occhio".

Non aggiungo altro perché ti hanno già risposto esaurientemente gli altri. :slight_smile:

Innanzitutto grazie tuxduino per il consiglio sull'indentazione del codice, spero di tenerlo sempre a mente. :slight_smile:

Ritornando al mio stupido problema, ma che ahimè non sono riuscito a risolvere.
Ho riflettuto sul consiglio datomi, tonid, ma non riesco a capire come far accendere il led prima di mettere il Millis; mi spiego:

// Il led lampeggia se premo il pulsante  
// premendo una seconda volta il pulsante si spegne il led  

#define LED 13                  
#define BUTTON 7                
int val = 0;                    
int vecchio_val = 0;          
int stato = 0; 
int ledState = LOW;             
long previousMillis = 0;      
long interval = 1000;


void setup() {  
  pinMode(LED, OUTPUT);         
  pinMode(BUTTON, INPUT);       
}  

void loop() {  
  val = digitalRead(BUTTON);    


  if ((val == HIGH) && (vecchio_val == LOW)){  
    stato = 1 - stato;  
    delay(15);                  
  }   

  vecchio_val = val;          

  if (stato == 1) { 

    digitalWrite(LED, ledState);
    unsigned long currentMillis = millis();

    if(currentMillis - previousMillis > interval) {

      previousMillis = currentMillis;   


      if (ledState == LOW)
        ledState = HIGH;
      else
        ledState = LOW;


      digitalWrite(LED, ledState); 
    }
  }  
  else {  
    digitalWrite(LED, LOW);      
  }  
}

Come potete vedere ho aggiunto il comando, stupidamente penso, digitalWrite [che è l'unico che conosco per accendere il LED] con la variabile ledState; ho fatto ciò perché aggiungendo digitalWrite (LED, HIGH) [come per accendere il LED] avevo come risultato un normale circuito con tocco di pulsante - led accesso, tocco di pulsante - led spento.
Ho notato il cambiamento, ma ovviamente come ben sapete non è assolutamente ciò di cui avevo bisogno :-/
Mi stimola risolvermi questi piccoli problemi; scusate, ma cerco di apprendere quanto più possibile queste nozioni base!
Grazie ancora per i consigli!

Mi stimola risolvermi questi piccoli problemi; scusate, ma cerco di apprendere quanto più possibile queste nozioni base!

Per accendere subito il led appena entri nella if la variabile ledState deve essere inizializzata HIGH e non LOW

#define LED 13                  
#define BUTTON 7                
int val = 0;                    
int vecchio_val = 0;          
int stato = 0; 
int ledState = LOW;             
long previousMillis = 0;      
long interval = 1000;

In questo modo....

if (stato == 1) { 

    digitalWrite(LED, ledState);
    unsigned long currentMillis = millis();

    if(currentMillis - previousMillis > interval) {

      previousMillis = currentMillis;   


      if (ledState == LOW)
        ledState = HIGH;
      else
        ledState = LOW;


      digitalWrite(LED, ledState); 
    }
  }

accendi subito il led,aspetti che il tempo da te impostato con interval venga raggiunto ed entri nella if aggiornandoti il valore su previousMillis,subito dopo controlli lo stato del led ovvero lo cambi da HIGH a LOW e viceversa e dai al led il valore attuale con il digitalWrite.

Compila, ma non l'ho provato:

// Il led lampeggia se premo il pulsante  
// premendo una seconda volta il pulsante si spegne il led  

#define LED 13                  
#define BUTTON 7                
int val = 0;              // stato attuale del pulsante
int vecchio_val = 0;      // stato del pulsante nella lettura precedente
int stato = 0;            // 0 = led spento, 1 = led lampeggiante
int ledState = LOW;       // stato attuale del led
long previousMillis = 0;      
long interval = 1000;     // semiperiodo di lampeggio del led

void setup() {  
    pinMode(LED, OUTPUT);         
    pinMode(BUTTON, INPUT);       
}  

void loop() {  
    val = digitalRead(BUTTON);    

    if ((val == HIGH) && (vecchio_val == LOW)) {
        // inverto il flag di abilitazione al lampeggio
        stato = 1 - stato;
        
        // non appena cambia il flag di abilitazione al lamepggio
        // aggiorniamo lo stato del led
        
        if (stato == 0) {
            // se il lampeggio è stato disabilitato, spegnamo subito il led
            ledState = LOW;
            digitalWrite(LED, ledState);
        }
        else {
            // se il lampeggio è stato abilitato, accendiamo subito il led
            // e inizializziamo il timer del lampeggio
            ledState = HIGH;
            digitalWrite(LED, ledState);
            previousMillis = millis();    // il led cambierà stato dopo interval ms da ora
        }
        
        delay(15);
    }   

    vecchio_val = val;

    if (stato == 1) { 
        unsigned long currentMillis = millis();

        if(currentMillis - previousMillis > interval) {

            previousMillis = currentMillis;   

            if (ledState == LOW)
                ledState = HIGH;
            else
                ledState = LOW;

            digitalWrite(LED, ledState); 
        }
    }  
    else {
        // probabilmente questo ora non serve
        digitalWrite(LED, LOW);      
    }  
}

L'idea è che se vuoi reagire immediatamente alla pressione del pulsante, allora devi pilotare il led non appena ha rilevato tale evento.

Veramente esaustivo, grazie mille! E il codice funziona anche su base pratica :smiley:

Avevo già intuito da ciò che mi avevi spiegato in precedenza che dovevo dividere in due casi il codice, una parte a LED spento e l'altra a LED lampeggiante ma non ho afferrato subito l'idea di poter usare "stato == 0" per spegnerlo in pratica o in caso contrario accenderlo e "stato == 1" per farlo lampeggiare. Se ho capito bene è questo che hai fatto nel codice.

Funziona perfettamente, l'ultimo "digitalWrite" non è necessario come sostenevi già tu e inoltre mi ritengo soddisfatto di aver appreso di più sulla funzione Millis e anche sulla stesura totale del codice con le varie parti.

Grazie mille a tutti!