Tre led ed un pulsante

Salve a tutta la comunità,
avrei bisogno di aiuto per capire come scrivere uno sketch....

in breve:

ho i miei tre led 1/2/3 ed un pulsante, alla pressione singola del pulsante lo stato dei led 1 e 2 deve invertirsi mentre alla pressione prolungata di un tot tempo del pulsante deve invertire lo stato del led 3 lasciando inalterato lo stato dei led 1 e 2.
La particolarità è che il led 3 deve accendersi dopo tot tempo anche se il pulsante è ancora premuto.
In pratica: premo e tengo premuto il pulsante, il led 3 si accende dopo un secondo, rilascio il pulsante, ripremo e tengo premuto il pulsante, il led 3 si spegne dopo un secondo, rilascio il pulsante.

Ho provato con la funzione millis ma purtroppo la conosco poco e riesco o a fare un'operazione o un'altra (o inverto i led 1 e 2 o accendo spengo il led 3 con pressione prolungata)

Ho omesso di postare un codice perché ne ho provati talmente tanti che non so più nemmeno io qual è quello che più si avvicina alla mia necessità…

Qualcuno può aiutarmi a risolver??
Grazie mille in anticipo,
Gabriele.

Ciao, Gabriele
Fai qualcosa tipo:

if([Il pulsante è premuto] && premuto_prec==0)
  {premuto_prec=1; t=millis();}
if([pulsante non premuto] && premuto_prec==1)
  {
  premuto_prec=0;
  if (millis()-t<1000) {fai questo}
  else {fai quest'altro}
  }

Tra [ ] ho scritto la condizione del pulsante che rilevi con un digital Read().

Metti un condensatore da 100...470nF (1nF=1000pF) in parallelo al pulsante per eliminare i rimbalzi.

Adesso spero di riuscire a riaddormentarmi... :slight_smile:
Buona notte!

if([Il pulsante è premuto])
  {
  if(premuto_prec==0) // È stato premuto adesso
    {t=millis();}
  premuto_prec=1; 
  if(millis()-t>=1000)
    {fai questo e aspetta che venga lasciato}
  }
if([pulsante non premuto])
  {
  premuto_prec=0;
  if(millis()-t<500) // pressione breve
    {fai questo}
  }

Per pressioni fra 500ms e 1s non accade nulla.

Buongiorno Datman e grazie!
Credo di aver capito cosa fare, non avevo pensato di inserire una variabile sullo stato precedente del pulsante. Oggi svilupperò un codice e proverò il funzionamento!!
Grazie e buona giornata.

Gabriele Lampadina.

Eccomi qui, buonasera Datman
ho provato con entrambi gli sketch, che ho simulato con tinkercad. Il primo mi funziona ma per il secondo non riesco a compilarlo bene e non funziona come dovrebbe, probabilmente mi sfugge qualcosa.

Il primo postato:

unsigned long t=500;
int premuto_prec = 0;

void setup(){


   pinMode (2, OUTPUT);
   pinMode (3, OUTPUT);
   pinMode (4, OUTPUT);
   pinMode (5, INPUT);
   digitalWrite(5, HIGH);
   digitalWrite(2, HIGH); 
   digitalWrite(3, LOW);
   digitalWrite(4, LOW);
}


void loop()
 {
   if((digitalRead(5) == LOW) && (premuto_prec == 0))
     {premuto_prec = 1; t = millis();}
   
   if((digitalRead(5) == HIGH) && (premuto_prec== 1))
      {premuto_prec = 0;
    
   if (millis() - t < 1000) {digitalWrite(2, !digitalRead(2));
                                       digitalWrite(3, !digitalRead(3));}
    else {digitalWrite(4, !digitalRead(4));}
    }
    }

Funziona ma gli manca la caratteristica principale che mi servirebbe, ovvero alla pressione prolungata il led connesso la piedino 4 deve accendersi trascorso il tempo impostato anche con il pulsante premuto….
Cosa che succede invece con il secondo sketch il quale invece mi da problemi con gli altri due led , in pratica premendo il pulsante a volte si scambiano lo stato oppure si accendono contemporaneamente…
Sarà perché ho simulato con tinkercad e non con breadboard e relativi condensatori sugli interruttori???

Cordialmente,
Gabriele

Sì: il primo programma cronometra il tempo in cui il pulsante è premuto; quando viene lasciato, fa quello che deve fare in base al tempo rilevato.
Dato, però, che l'ho sempre fatto come dici tu, l'ho riscritto diversamente: il secondo programma, salvo errori, dovrebbe fare la prima cosa quando il pulsante viene lasciato dopo una pressione breve o fare la seconda se il pulsante viene tenuto premuto per almeno un secondo.

Il secondo programma, completo, viene:

unsigned long t=0;
int8_t premuto_prec = 0;

void setup()
{
pinMode (5, INPUT_PULLUP);
pinMode (2, OUTPUT);
pinMode (3, OUTPUT);
pinMode (4, OUTPUT);

digitalWrite(2, HIGH);
digitalWrite(3, LOW);
digitalWrite(4, LOW);
}

void loop()
{
if(!digitalRead(5)) // Se il pulsante è premuto
  {
  if(premuto_prec==0) {t=millis();} // È stato premuto adesso: prendo t.
  premuto_prec=1;
  if(millis()-t>=1000)
    {
    digitalWrite(4,!digitalRead(4)); // Inverte lo stato del terzo LED.
    while(!digitalRead(5)); // Attende che venga lasciato il pulsante.
    }
  }
  
if(digitalRead(5) && premuto_prec) // Se il pulsante è appena stato lasciato
  {
  premuto_prec=0;
  if(millis()-t<500) // Pressione breve
    {
    digitalWrite(2,!digitalRead(2)); // Inverte lo stato del primo LED.
    digitalWrite(3,!digitalRead(3)); // Inverte lo stato del secondo LED.
    }
  }
}

Ho modificato "Se il pulsante è appena stato lasciato".

Noi avevamo fatto questo

/*
   Una nuova idea DDD
   Del Dinamico Duo

   Sentitevi liberi di copiare
   Sentitevi liberi di trarre ispirazione
   Sentitevi liberi di dare un cenno di ringraziamento


   Copiato dalle specifiche del progetto:
   alla pressione singola del pulsante lo stato dei led 1 e 2 deve invertirsi mentre alla pressione prolungata di un tot tempo del pulsante deve invertire lo stato del led 3 lasciando inalterato lo stato dei led 1 e 2.
   La particolarità è che il led 3 deve accendersi dopo tot tempo anche se il pulsante è ancora premuto.
   In pratica: premo e tengo premuto il pulsante, il led 3 si accende dopo un secondo, rilascio il pulsante, ripremo e tengo premuto il pulsante, il led 3 si spegne dopo un secondo, rilascio il pulsante

   Creato con IDE 1.8.10
   25 Novembre 2019
*/

#define LED1 2
#define LED2 3
#define LED3 4
#define PULSANTE 5
#define TEMPOLED1 20
#define TEMPOLED3 1000
unsigned long int tempopressione;

void setup(void)
{
   pinMode(LED1, OUTPUT);
   pinMode(LED2, OUTPUT);
   pinMode(LED3, OUTPUT);
   pinMode(PULSANTE, INPUT);
}

void loop(void)
{
   if (digitalRead(PULSANTE))
   {
      if (!tempopressione)
      {
         tempopressione = millis();
      }

      if (millis() - tempopressione > TEMPOLED3)
      {
         digitalWrite(LED3, !digitalRead(LED3));
      }
   }
   else
   {
      if (millis() - tempopressione > TEMPOLED1)
      {
         digitalWrite(LED1, !digitalRead(LED2));
         digitalWrite(LED2, !digitalRead(LED2));
      }

      tempopressione = 0;
   }
}

previsto però per pulsante al +, non a gnd

aspettavamo a postarlo per nonn dare la pappa fatta, ma adesso è il momento giusto

Lampadina farebbe una bella cosa a dare un cenno e a studiare i programmi, per mostrare che gli sforzi non sono stati vani

Buongiorno Datman,
il secondo scetch lo avevo scritto come il tuo ultimo completo ma con piccolissime differenze,
qui:

 if(!digitalRead(5)) // Se il pulsante è premuto
-
-
- 
 if(digitalRead(5)) // Se il pulsante non è premuto

io avevo inserito anche lo sto del pulsante (HIGH e LOW) nel digitalRead.

 if(!digitalRead(5),HIGH) // Se il pulsante è premuto
-
-
- 
 if(digitalRead(5),LOW) // Se il pulsante non è premuto

Comunque ora sembra funzionare meglio, sempre simulato con tinkercad riuscendo a regolare diversamente i tempi e ad aggiungendo un condensatore in parallelo all'interruttore.... a parte qualche errore, credo dovuto al simulatore, si comporta bene!!

Riuscirò a montarlo su breadbord farò delle ulteriori prove.

Grazie di tutti i preziosi consigli!!

Gabriele Lampadina.

Ciao, Gabriele
Ho fatto una piccola modifica in "Se il pulsante è appena stato lasciato".
Nota anche l'attesa del rilascio del pulsante nella pressione prolungata.

Ducembarr ho visto ora la tua risposta, proverò entrambi i codici.

In verità ho speso del tempo ad analizzare i programmi postati da Datman capendoli e facendo modifiche, purtroppo le mie conoscenze con Wiring sono scarsine... sto cercando di imparare e a ragionare su come programmare, inteso sia come scrittura, tipo di istruzioni e sul flusso che il programma deve seguire, quale operazione fare e quando. Il mio livello di conoscenze informatiche risale ad un corso di Basic seguito a fine anni '80.... :blush:
Ho anche il pdf che Guglielmo consiglia sempre e lo sto leggendo, purtroppo alcuni termini mi rimangono ostici se non incomprensibili e quindi la mia crescita di conoscenza risulta un po lenta....
Ma piano piano imparerò :grinning:

Grazie a tutti di tutto,
Gabriele Lampadina

Quando pubblico un programmino simile, lo faccio proprio nella speranza che venga letto, analizzato e anche modificato per fare delle prove, non solo copiato ciecamente. :slight_smile: Così si impara e anch'io così ho fatto.

Che cosa ti è incomprensibile? Parliamone...

Per incomprensibile intendo parecchi termini a me sconosciuti che leggo nella guida pdf consigliata da Guglielmo per i quali poi devo andare a documentarmi.
Di incomprensibile negli sketch che mi hai gentilmente postato non c'è nulla, probabilmente qualcosa che mi confonde si.
Per esempio non avevo notato la negazione (!) qui:

 while(!digitalRead(5)); // Attende che venga lasciato il pulsante.

e che io non avevo inserito nel mio codice e che tu mi hai fatto notare.

Qui:

 if(!digitalRead(5)) // Se il pulsante è premuto

mi è oscuro perché non ci sia una comparazione tra lettura pulsante e uno stato, suppongo per il fatto che questo if legga solamente il cambio di stato, qualunque esso sia, del pulsante?? Oppure da per scontato che sia HIGH??

O anche qui:

if(digitalRead(5) && premuto_prec)

Idem come sopra compreso "premuto_prec"....

Sono sintassi (si chiamano così?) che non ho incontrato molto facilmente durante i miei "tour informativi" online e mi rimangono difficili da comprendere.
Vero, probabilmente dovrei fare qualche prova in più... ma sinceramente parlando non sarei mai arrivato ad inserire una negazione in un while!!!

Grazie per l'attenzione
Gabriele Lampadina

Edit:
int8_t dove 8_t stabilisce la grandezza in bits di int???

if(x) {} vuol dire: se x!=0, cioè se x è diverso da zero.
if(!x) {} quindi vuol dire: se x==0.

if(x && y) {} vuol dire: se sia x che y sono diversi da zero.

while(...); vuol dire: finché la condizione è vera, stai fermo lì. Le parentesi graffe vuote non sono necessarie. Puoi usarlo solo se è lecito che tutta l'esecuzione si fermi in quella condizione. Può essere lecito durante delle impostazioni, se tutto il resto si può fermare, altrimenti bisogna fare diversamente.

Abituati a queste sintassi più o meno "artistiche", così se le trovi scritte puoi capirle. :slight_smile:

Gli spazi molto spesso possono essere messi, tolti o prolungati senza conseguenze, se non per la comprensibilità. Quando ci sono diverse condizioni di seguito, ad esempio, metto spaziature diverse per facilitare la comprensione delle priorità.
Nei #define e nella dichiarazione delle variabili, però, ad esempio, gli spazi sono necessari.

Beh si ai miei occhi sono mooolto artistiche, ma non conoscendole brancolo nel buio.
Ho scoperto, credo, anche che int8_t definisce la grandezza in bits della variabile??
L'istruzione while la conosco tant'è vero che l'avevo inserita nello sketch che avevo creato, quindi scrivendo

 while(digitalRead(5));

gli dico che finchè il pin 5 è diverso da 0 (ovvero ad 1) stai fermo li. Equivarrebbe a while(x || 0)?

Diversamente:

 while(!digitalRead(5));

gli dico che finchè il pin 5 è 0 stai fermo li. Che equivarrebbe a while (x==0)?

Cose interessantissime!!!

Credo che ora sono riuscito ad interpretare bene il tuo sketch, sono riuscito a capire anche come il programma riesca ad entrare in questo if:

 if(digitalRead(5) && premuto_prec)

in pratica vede il pulsante rilasciato (digitalRead || 0) e lo stato premuto_prec a 1 proveniente dall'if precedente:

 f(!digitalRead(5)) // Se il pulsante è premuto
  {
  if(premuto_prec==0) {t=millis();} // È stato premuto adesso: prendo t.
  premuto_prec=1;

il quale premuto_prec cambiando da 0 ad 1 fa in modo anche di prendere una sola lettura di millis()??

Poi lo stato premuto_prec diventa di nuovo 0 e la procedura si azzera in pratica.

Ho visto (quasi giusto)????

[/code]

int8_t è una variabile a 8 bit con segno;
uint8_t è senza segno.

x||0?... || è l'OR logico; && è l'AND logico.
| e & sono, invece, operatori binari bit a bit.

while(!digitalRead(5)); è equivalente a
while(digitalRead(5)==0);

premuto_prec è la situazione del pulsante all'ultimo aggiornamento, prima che sia aggiornato nuovamente. Bisogna fare attenzione al fatto che è 1 (o, più formalmente, HIGH, ma per l'IDE HIGH=1) quando il pulsante è premuto, cioè digitalRead(5)==0.

... che poi sono tutte informazioni che si possono imparare studiando il reference di Arduino, dove queste cose sono spiegate in dettaglio con esempi per ciascuna di esse. :wink:

Guglielmo

P.S.: Salvo magari quei "tipi" di variabile che sono definiti in <stdint.h> che fa parte della onnipresente AVR libc.

Si scusate, non || ma != .....mi sono un po confuso... grazie Guglielmo!!!

Lampadina:
Si scusate, non || ma != ...

Trovi in dettaglio la spiegazione per entrambi nel suddetto reference che devi consultare sempre :wink:

Guglielmo