Far lampeggiare 2 led con un pulsante

Buona sera a tutti premetto che sono un principiante :slightly_frowning_face: :slightly_frowning_face: e sto cominciando a muovere i primi passi con arduino quindi quello che vi chiedo sarà sicuramente banale per voi.

Ho seguito una lezione qui ma poi per complicarmi un pò la vita e incominciare a capire qualcosa senza copiare, ho aggiunto un ulteriore led e ho cercato di eliminare delay sostituiendolo con millis per far lampeggiare i led.
Il mio intento sarebbe far lampeggiare il led rosso alla prima pressione, alla seconda accendere il verde e spegnere il rosso e cosi via.
In parte funziona cioè il led rosso lampeggia alla prima pressione, alla seconda pressione il verde sfarfalla velocemente e il rosso si spegne ma ad ogni pressione i led sembra che si comportino in maniera diversa.
allego il codice

#define ledgreen 12
#define ledred 13                // LED collegato al pin digitale 13  
#define BUTTON 7              // pin di input dove è collegato il pulsante  
int val = 0;                  // si userà val per conservare lo stato del pin di input
int vecchio_val = 0;          // si userà 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
int ledredstato = 0;
int ledgreenstato = 0;
long tempovecchiored = 0;
long tempovecchiogreen = 0;
long intervallogreen = 1000; //tempo di lampeggio led green
long intervallored = 300;  //tempo di lampeggio led rosso

void setup() {
  pinMode(ledgreen, OUTPUT);     // imposta il pin digitale come output
  pinMode(ledred, 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
  delay (15);

  unsigned long temponuovo = millis();

  // controlla se è accaduto qualcosa
  if ((val == HIGH) && (vecchio_val == LOW)) {
    stato = 1 - stato;
  }

  vecchio_val = val;            // ricordiamo il valore precedente di val

  if (stato == 1)
  {
    if (temponuovo - tempovecchiored > intervallored)
    {
      tempovecchiored = temponuovo;
      if (ledredstato == LOW)
      {
        ledredstato = HIGH;
      }
      else {
        ledredstato = LOW;
      }
      digitalWrite(ledred, ledredstato);
    }
  }


  if (stato == 0)
  {
    if (temponuovo - tempovecchiogreen > intervallogreen)
    {
      tempovecchiogreen = temponuovo;
    }
    if (ledgreenstato == LOW)
    {
      ledgreenstato = HIGH;
    }
    else
    {
      ledgreenstato = LOW;
    }
    digitalWrite(ledgreen, ledgreenstato);

  }
}

Forse il codice che ho scritto non ha senso ma ripeto che vorrei imparare a programmare per poi in futuro costruire il mio primo robot.
Qualsiasi consiglio su cosa fare per imparare e capire ben accetto :wink:

Grazie

Ciao, mi piace come hai scritto il codice, l'uso di #define per costanti, nome scelto da te per le variabili e non copiate dagli esempi, indentazione corretta, credo tu abbia un po di talento :slight_smile:

Non ho capito alcune cose del codice, mi sembra logicamente corretto, ho fatto solo una modifica sul cambiamento della variabile stato, vedi se trovi dei miglioramenti, non ho il circuito per provare e quindi non è testato.

#define ledgreen 12
#define ledred 13                // LED collegato al pin digitale 13  
#define BUTTON 7              // pin di input dove è collegato il pulsante  
int val = 0;                  // si userà val per conservare lo stato del pin di input
int vecchio_val = 0;          // si userà 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
int ledredstato = 0;
int ledgreenstato = 0;
long tempovecchiored = 0;
long tempovecchiogreen = 0;
long intervallogreen = 1000; //tempo di lampeggio led green
long intervallored = 300;  //tempo di lampeggio led rosso

void setup() {
  pinMode(ledgreen, OUTPUT);     // imposta il pin digitale come output
  pinMode(ledred, 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
  delay (15);

  unsigned long temponuovo = millis();

  // ALLA PRESSIONE DEL TASTO STATO CAMBIA VALORE DA 1 A 0 O DA 0 A 1
  
  /*
     Se si volessero gestire molte situazioni proporrei un incremento della variabile
	 stato, in base al suo valore eseguire un codice 
	 raggiunto un valore massimo tornare a zero
	 Esempio;
	 if ((val == HIGH)  {
       stato++;
       if(stato>=3) stato=0;	   
  }
  
  
  */
  if ((val == HIGH)  {
     if(stato==1)
	     stato=0;
	 else
         stato=1;	 
  }

  

  if (stato == 1)
  {
     digitalWrite(ledgreen, LOW);//led verde spento
    if (temponuovo - tempovecchiored > intervallored)
    {
      tempovecchiored = temponuovo;
      if (ledredstato == LOW)
      {
        ledredstato = HIGH;
      }
      else {
        ledredstato = LOW;
      }
      digitalWrite(ledred, ledredstato);
    }
  }


  if (stato == 0)
  {

   digitalWrite(ledred, LOW);// led rosso spento 
    if (temponuovo - tempovecchiogreen > intervallogreen)
    {
      tempovecchiogreen = temponuovo;
    }
    if (ledgreenstato == LOW)
    {
      ledgreenstato = HIGH;
    }
    else
    {
      ledgreenstato = LOW;
    }
    digitalWrite(ledgreen, ledgreenstato);

  }
}

Ciao grazie sei molto gentile ma non è farina del mio sacco io ho cercato di fondere 2 sketch cioè volevo far lampeggiare i led senza usare delay.
Ma quando ci sono troppi if mi va in pappa il cervello, perchè non riesco a capire la sequenza del programma.
Ho provato la tua versione ma nulla funziona come la mia sembra che il led verde prenda il tempo di lampeggio dal delay (15); e salti tutto if dedicato al led verde .

Ricordo che sono un neofita se qualcuno mi vuole anche consigliare qualche libro o corso sarei grato.

Non è quello il problema, ma TUTTE le variabili coinvolte nel calcolo dei millisecondi DEVONO essere unsigned long e non solo long.
Quindi:
unsigned long tempovecchiored=0;
unsigned long tempovecchiogreen=0;

chiccoard:
Il mio intento sarebbe far lampeggiare il led rosso alla prima pressione, alla seconda accendere il verde e spegnere il rosso e cosi via.

Questo non è chiaro. Quel così via... per una macchina non basta.
Devi spiegare bene quali comportamenti vuoi dai led. Ti conviene creare 1 variabile statogenerale con vari valori
Accendi Arduino=tutto spento ? (statogenerale=0)
Premo 1 volta, accendo rosso (statogenerale=1)
Premo ancora, accendo verde, spengo rosso (statogenerale=2)
Premo ancora, qui non saprei, torni a statogenerale=0 oppure a 1 ? Oppure li accendi tutti e due ?

Mi arrabbio quando non capisco subito il problema, ma però penso sia più difficile capire il codice scritto da altri, che scrivere un codice dal principio con la propria testa.

Mi sembra che il cambiamento di stato dei led, non sia condizionato da nessun if(), infatti, premendo il pulsante si calcola il tempo con millis() e si aggiornano le variabili che contano il tempo, ma il cambiamento di stato acceso,spento dei led, viene eseguito sempre a velocità microprocessore :slight_smile:

Prova questa modifica, e vedi se migliora qualcosa.

#define ledgreen 12
#define ledred 13                // LED collegato al pin digitale 13  
#define BUTTON 7              // pin di input dove è collegato il pulsante  
int val = 0;                  // si userà val per conservare lo stato del pin di input
int vecchio_val = 0;          // si userà 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
int ledredstato = 0;
int ledgreenstato = 0;
unsigned long tempovecchiored = 0;
unsigned long tempovecchiogreen = 0;
long intervallogreen = 1000; //tempo di lampeggio led green
long intervallored = 300;  //tempo di lampeggio led rosso

void setup() {
  pinMode(ledgreen, OUTPUT);     // imposta il pin digitale come output
  pinMode(ledred, 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
  delay (15);

  unsigned long temponuovo = millis();

  // ALLA PRESSIONE DEL TASTO STATO CAMBIA VALORE DA 1 A 0 O DA 0 A 1
  
  /*
     Se si volessero gestire molte situazioni proporrei un incremento della variabile
	 stato, in base al suo valore eseguire un codice 
	 raggiunto un valore massimo tornare a zero
	 Esempio;
	 if ((val == HIGH)  {
       stato++;
       if(stato>=3) stato=0;	   
  }
  
  
  */
  if ((val == HIGH)  {
     if(stato==1)
	     stato=0;
	 else
         stato=1;	 
  }

  

  if (stato == 1)
  {
     digitalWrite(ledgreen, LOW);//led verde spento
    if (temponuovo - tempovecchiored > intervallored)
    {
      tempovecchiored = temponuovo;
      if (ledredstato == LOW)
      {
        ledredstato = HIGH;
      }
      else {
        ledredstato = LOW;
      }
      digitalWrite(ledred, ledredstato);
    }
  }


  if (stato == 0)
  {

   digitalWrite(ledred, LOW);// led rosso spento 
    if (temponuovo - tempovecchiogreen > intervallogreen)
    {
      tempovecchiogreen = temponuovo;
   // } questa parentesi faceva si che il lampeggio non dipendesse dal tempo
    if (ledgreenstato == LOW)
    {
      ledgreenstato = HIGH;
    }
    else
    {
      ledgreenstato = LOW;
    }
    digitalWrite(ledgreen, ledgreenstato);

  } // end if
}// end if


}// end loop() function

Ma quando ci sono troppi if mi va in pappa il cervello, perchè non riesco a capire la sequenza del programma.

Questo non accade solo a te, per questo odio "if (con) break;" tutto su una linea.

Cura l'indentazione del codice, usa spazi e righe vuote e anche i commenti tornano utili con if annidate.

Anche le due if annidate a seguire possono fare girare gli occhi a seconda della indentazione.

if ((espressione0) && (espressione1))  {
    // codice
    if ((espressione2) && (espressione3))  { 
        // codice 
    }
    // codice 
}

La stesse if a seguire sono scritte in modo da agevolare la lettura:

if ( (espressione0) && (espressione1) )  {
    // codice

    if ( (espressione2) && (espressione3) )  { 

        // codice 

    } // end if "( (espressione2) && (espressione3) )"  

    // codice 

} // end "if ( (espressione0) && (espressione1) )"

Si possono notare gli spazi su entrambe le parentesi "(" di apertura e chiusura.
I commendi end "if dopo la parentesi }

Se questi accorgimenti non bastano allora si deve investire maggiore tempo e forse è anche il caso di riprogettare
parte del codice al fine di non annidare troppe if e ridurre la lunghezza del blocco di codice delimitato da { }.

Il codice contenuto dentro un blocco { } associato ad una condizione può essere ridotto spostando parte del codice all'interno di funzioni.

Tornando al problema specifico ti consiglio di studiare il comando "switch case".
Inoltre "divide et impera" consiglia di fare lampeggiare un solo led per sempre, dopo un reset, evitando di usare
la funzione "delay". Questo significa concentrare la nostra attenzione su un numero limitato di istruzioni, visto che la nostra capacità di concentrazione è una costante, riducendo il numero di istruzioni, sfruttiamo meglio la nostra capacità, a tal fine
le funzioni agevolano la concentrazione.

L'ho sempre detto e lo ripeto, il C/C++ va studiato e sperimentato usando un compilatore per PC, il quale genera un programma eseguibile sul PC e il risultato lo possiamo vedere subito eseguendolo.

Possiamo anche fare lampeggiare un led senza usare millis e delay, ma la frequenza di lampeggio è determinata
da quanto tempo il micro impiega per eseguire un loop completo.

#define BLINK_LED0_AT_FREQ 10000;
unsigned int blinkLed0AtFreq = BLINK_LED0_AT_FREQ;


void loop () {

    blinkLed0AtFreq--;
    if ( blinkLed0AtFreq == 0 ) {
        digitalWrite( 4, !digitalRead(4) ); 
        blinkLed0AtFreq = BLINK_LED0_AT_FREQ;
    }
}

Io ho usato indentazione di 4 spazi, mentre arduino IDE di default ne usa 2 soli, per i miei occhi sono insufficienti.

Ciao.

Grazie a tutti, adesso studio e provo le vostre modifiche, ma sicuramente non avrò capito qualcosa

Ciao allora ho provato a curare l'indentazione del codice come suggerita da @MauroTec e fatte le modifiche di @torn24 enid69ita poi ho aggiunto Serial.println per vedere cosa succedeva quando premevo il pulsante.

Adesso funziona.

ecco il risultato

#define ledverde 12
#define ledrosso 13                // LED collegato al pin digitale 13 
#define BUTTON 7              // pin di input dove è collegato il pulsante 
int val = 0;                  // si userà val per conservare lo stato del pin di input
int stato = 0;                // ricorda lo stato in cui si trova il led, stato = 0 led spento, stato = 1 led acceso
int ledrossostato = 0;
int ledverdestato = 0;
unsigned long tempovecchiorosso = 0;
unsigned long tempovecchioverde = 0;
long intervalloverde = 200; //tempo di lampeggio led green
long intervallorosso = 300;  //tempo di lampeggio led rosso

void setup() {
  pinMode(ledverde, OUTPUT);     // imposta il pin digitale come output
  pinMode(ledrosso, OUTPUT);       // imposta il pin digitale come output
  pinMode(BUTTON, INPUT);     // imposta il pin digitale come input
  Serial.begin(9600);
}

void loop() {
  val = digitalRead(BUTTON);  // legge il valore dell'input e lo conserva
  delay (50);

  unsigned long temponuovo = millis();

  // ALLA PRESSIONE DEL TASTO STATO CAMBIA VALORE DA 1 A 0 O DA 0 A 1
 
 
  
  if ( (val == HIGH) ) {
    
     if(stato==1)
     
      stato=0;
      
     else
  
      stato=1; 
  }

 

  if (stato == 1)  {
    
     digitalWrite(ledverde, LOW);   //led verde spento 
     
    if (temponuovo - tempovecchiorosso > intervallorosso)  {
      
      tempovecchiorosso = temponuovo;
      
      if (ledrossostato == LOW) {
        
        ledrossostato = HIGH; // mette la variante led rosso HIGH
      }
      
      else {
        
        ledrossostato = LOW; // mette la variante led rosso LOW
      }
      
      digitalWrite(ledrosso, ledrossostato);
    }
  }


  if (stato == 0) {

    digitalWrite(ledrosso, LOW);     // led rosso spento 
   
    if (temponuovo - tempovecchioverde > intervalloverde) {
      
      tempovecchioverde = temponuovo;   
   
    if (ledverdestato == LOW) {
      
      ledverdestato = HIGH; 
      }
      
    else {
      
     ledverdestato = LOW;
    }
    digitalWrite(ledverde, ledverdestato);

  } // end if
}// end if

Serial.print("Valore stato:");
Serial.println(stato);

}// end loop() function

Ma adesso io non ho capito una cosa ,cioè tante cose ma incomincio da questa

guardando questo pezzo iniziale del codice

 if ( (val == HIGH) ) {
    
     if(stato==1)
     
      stato=0;
      
     else
  
      stato=1; 
  }

Se la condizione del primo if è falsa, il programma a che riga salta o bisogna guardare le parentesi graffe ?

Grazie

La parentesi graffa aperta inizia un BLOCCO di istruzioni che si conclude alla corrispondente parentesi graffa chiusa. Se quel IF è falso, il BLOCCO non viene eseguito (... mentre, se ci fosse, eseguirebbe quello dell'else).

Guglielmo

Grazie @gpb01 partendo da principiante una delle mie difficolta è impostare il programma oltre alle funzioni.

Cioè se per le funzioni ci sono manuali, sezione reference del sito, pdf,esempi ecc.
Io non riesco a trovare la parte prima, dedicata alla progettazione,esempio per far lampeggiare il led ti servono x variabili imput , y variabili output , z variabili di stato e poi penso bisognerebbe fare un diagramma su carta, giusto ?

Non hai qualche dritta su dove cercare o libro da comprare ?

Grazie.

Manuali e libri ce ne sono parecchi. Io ho sempre usato google

la miglior cosa è sbattere la testa più vai avanti più impari.

In programmazione la maggior parte delle volte si possono usare diverse strade per fare la stessa cosa.

All'inizio scrivi qualcosa di semplice ma lungo da scrivere poi con l'esperienza con poche linee di codice
Fai la stessa cosa.

Una cosa comune è scrivere il codice poi testandolo lo sporchi, quando hai capito il modo migliore per
Farlo lo riscrivi da capo in maniera pulita ed elegante.

Davide

Non hai qualche dritta su dove cercare o libro da comprare ?

Se vuoi puoi accomodare guardando alle risorse on line, ma è impossibile per un principiante giudicare se i contenuti sono ottimi o scadenti. Quindi le risolse on line a pizzichi e bocconi per il momento te le sconsiglio.

Un buon libro (magari più di uno) sul linguaggio C è un compagno immancabile a cui fare riferimento nei momenti di difficoltà.

Su un libro serio dovresti trovare spiegato l'argomento blocchi di codice più o meno così:

La creazione di un blocco di codice in C si ottiene tramite i delimitatori di blocco { }, il primo apre il blocco e il secondo lo chiude. Un blocco di codice può esistere anche se è privo di un legame con una delle seguenti istruzioni:
if (cond) else else if
switch (n)
while (cond)
for
void myFunction ()

Le prime 4 istruzioni sono dotate di un blocco di codice implicito limitato ad una sola istruzione, che può trovarsi sulla stessa linea o in quella seguente. Si può estendere il blocco di codice implicito legando un blocco di codice esplicito ad una di queste istruzioni.

Una definizione di funzione richiede un blocco di codice esplicito il quale rappresenta il corpo della funzione.

I blocchi di codice possono essere annidati e come detto prima possono esistere slegati da qualunque istruzione.
Un blocco di codice di questo tipo può essere usato per ottimizzare l'uso di memoria stack.

Tutte le variabili dichiarate dentro un blocco di codice legato o meno ad una istruzione sono da considerare variabili locali visibili e accessibili al blocco di codice in cui sono dichiarate, terminato il blocco di codice tutte le variabili locali vengono distrutte liberando risorse.

Ciao.

Un buon libro (magari più di uno) sul linguaggio C è un compagno immancabile

Grazie cercherò un libro di C e continuerò a sperimentare

Ci sono due pdf free scritti da una professoressa. Non sono male per imparare.
cerca "Tiziana Marsella Arduino"

Programmazione.pdf

Applicazioni.pdf

ok grazie scaricati, pensavo anche a questo libro “corso completo di c di deitel”

Non lo conosco. L'importante è che sia per principianti.
Personalmente eviterei la bibbia del C, quello bianco con C azzurra di Kernighan & Ritchie, secondo me NON adatto ad un principiante. Opinione personale.

nid69ita:
Personalmente eviterei la bibbia del C, quello bianco con C azzurra di Kernighan & Ritchie, secondo me NON adatto ad un principiante. Opinione personale.

Nid, quello è un libro che si DEVE assolutamente avere, ma va preso ovviamente per quello che è, IL REFERENCE del C e non un tutorial.

Come tutorial si può prendere QUESTO o QUESTO o uno dei tanti che si trovano su Amazon :wink:

Guglielmo

Quelli che ti ha linkato Gugliemo sono indirizzati ad Arduino, meglio di testi generici sul C, secondo me.
Purtroppo sono in inglese, forse alcuni ci sono anche italiano, se hai problemi con l'inglese.

Quello che ho indicato, le recensioni di amazon lo descrivono come un libro anche per i principianti, provo a guardare anche quelli di Guglielmo

Grazie.