Pressione e pressione prolungata pulsante arduino

Ciao a tutti, ho girato un pò su internet e sul forum ma non ho trovato una soluzione, vi espongo il problema. Ho un pulsante (installato tramite resistenza di PULL-UP, quindi se premuto la allo stato LOW) che alla pressione prolungata di ad esempio 2 secondi deve accendere un led, mentre alla pressione prolungata di 5 secondi ne deve accendere un altro il tutto senza aspettare che il pulsante venga rilasciato (i led devono rimanere accesi). Ho cosi scritto il seguente sketch:

int i_pulsante=0;
unsigned long t_pulsante=0;


void setup(){

  pinMode (6, OUTPUT);
    pinMode (9, OUTPUT);
      pinMode (A2, INPUT);
}


void loop(){

i_pulsante = digitalRead(A2);

if (i_pulsante == LOW){ t_pulsante = millis();
if (i_pulsante==LOW  && millis() - t_pulsante >=500){digitalWrite(6,HIGH);}
if (i_pulsante==LOW  && millis() - t_pulsante >=1000){digitalWrite(10,HIGH);}
}}

Non funziona e non riesco a capire il perchè, cosa potrei aver sbagliato? Grazie!

ma i LED possono essere accesi assieme o no?...cioe dopo 2 secondi LED1 ON...dopo altri 3, quindi 5 totali, LED 2 ON (e LED1 ON da prima) oppure all'accendersi di LED2 il LED1 si deve spegnere?

PS: comunque prova a cambiare il primo if da LOW ad HIGH

Ciao! Non funziona perché se premi il pulsante t_pulsante diventa uguale a millis(), per cui se tieni premuto il pulsante t_pulsante viene di continuo aggiornato al valore di millis(), e i confronti di tempo saranno sempre falsi perché t_pulsante sarà sempre uguale a millis()

Prova qualcosa del genere:

unsigned long t_pulsante=0;


void setup(){

    pinMode (6, OUTPUT);
    pinMode (9, OUTPUT);
    pinMode (A2, INPUT);
}


void loop(){



if (digitalRead(A2) == LOW){

    t_pulsante = millis(); //Alla pressione del pulsante aggiorno il tempo
    while(digitalRead(A2)==LOW){//Finché il pulsante è premuto

        if ( millis() - t_pulsante >=500){digitalWrite(6,HIGH);}
        if ( millis() - t_pulsante >=1000){digitalWrite(10,HIGH);}
     }


}

in ogni caso comunque il primo led si accenderà appena trascorsi i 500 millisecondi e il secondo dopo i 1000

se al contrario vuoi che se ne accenda solo uno in base a quanto tempo hai premuto devi cambiare ancora procedura

unsigned long t_pulsante = 0;
byte ledDaAccendere ;  // memorizzo il led da accendere

void setup() {
  pinMode (6, OUTPUT);
  pinMode (9, OUTPUT);
  pinMode (A2, INPUT);
}

void loop() {
  if (digitalRead(A2) == LOW) {
    t_pulsante = millis(); //Alla pressione del pulsante aggiorno il tempo
    while (digitalRead(A2) == LOW) { //Finché il pulsante è premuto
      if ( millis() - t_pulsante >= 500) {
        ledDaAccendere = 1;
      } 
      if ( millis() - t_pulsante >= 1000) {
        ledDaAccendere = 2;
      }
    }
    switch (ledDaAccendere) {
      case 1:
        digitalWrite(6, HIGH);
      case 2:
        digitalWrite(10, HIGH);
    }
    ledDaAccendere = 0;
  }
}

ovviamente poi manca lo spegnimento dei led ;)

Considera che quest'ultimo programma è bloccante, cioè durante la pressione del tasto non può fare altro.

Così non è bloccante:

byte i_pulsante=1;
byte iPrec=1;
unsigned long t_pulsante=0;

void setup()
{
pinMode (6, OUTPUT);
pinMode (9, OUTPUT);
pinMode (A2, INPUT);
}

void loop()
{
i_pulsante = digitalRead(A2);
if (i_pulsante==LOW)
  {
  if (iPrec==1) {iPrec=0; t_pulsante = millis();}
  if (millis() - t_pulsante >=2000) digitalWrite(6,HIGH);
  if (millis() - t_pulsante >=5000) digitalWrite(9,HIGH);
  }
else iPrec=1;
}

Per evitare problemi di "rimbalzi" del pulsante (falsi contatti) devi mettere un condensatore da circa 1uF in parallelo al pulsante stesso. C'è chi lo fa via software, ma mi sembra una complicazione inutile che serve solo per risparmiare un condensatore che svolge benissimo il suo lavoro... Via software, dovresti aggiungere due variabili e il loop verrebbe così:

byte z=0;
unsigned long t1=0;

void loop()
{
i_pulsante = digitalRead(A2);
if (i_pulsante==LOW)
  {
  z=0;
  if (iPrec==1) {iPrec=0; t_pulsante = millis();}
  if (millis() - t_pulsante >=2000) digitalWrite(6,HIGH);
  if (millis() - t_pulsante >=5000) digitalWrite(9,HIGH);
  }
else 
  {
  if(z==0) {z=1; t1=millis();}
  if(millis-t1>100) iPrec=1;
  }
}

Datman: Considera che quest'ultimo programma è bloccante, cioè durante la pressione del tasto non può fare altro.

Esatto. Ma diamo tutti per scontato che abbia messo un debounce hardware, vero?. ;)

Poi i "requisiti" parlano di 2 secondi per il primo led, e 5 secondi per il secondo, nel codice vedo invece mezzo secondo (500) ed un secondo (1000)...

A parte infine l'errore di aver inizializzato il secondo led sul pin 9 ma poi nel codice usa il 10... (ah la "#define" questa sconosciuta.. :)) ).

Insomma, io farei così:

int old_val = 0;  // Precedente valore del pin

unsigned long t_pulsante=0;

// Pin del pulsante
#define BUTTON A2
// Pin dei LED
#define LED1 6
#define LED2 10
// Primo intervallo
#define INT1 2000
// Secondo intervallo
#define INT2 5000

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

void loop()
{
  int val = digitalRead(BUTTON);
  if ((val == LOW) && (old_val == HIGH)){  
    // Pulsante premuto
    t_pulsante = millis();
    old_val = val;
    // Un minimo di debounce
    delay(100);
  }
  if ((val == HIGH) && (old_val == LOW)){  
    // Pulsante rilasciato
    t_pulsante = 0;
    old_val = val;
    // Spegne i LED
    digitalWrite(LED1,LOW);
    digitalWrite(LED2,LOW);
  }
  
  if (t_pulsante>0)
  {
    if (millis() - t_pulsante >=INT1) digitalWrite(LED1,HIGH);
    if (millis() - t_pulsante >=INT2) digitalWrite(LED2,HIGH);
  }
}

PS: perché un pin analogico per un input digitale? Se uno dei pin con interrupt fosse disponibile (2 e 3 sulla UNO) si potrebbero usare gli interrupt...

Ciao Davide,

io farei cosi':

[code]

unsigned long t_pulsante=0;

#define LED_1 6
#define LED_2 9
#define PULSANTE A2


void setup()
{
  pinMode (LED_1, OUTPUT);
  pinMode (LED_2, OUTPUT);
  pinMode (PULSANTE, INPUT_PULLUP);  
}


void loop()

{ 
  if (digitalRead(PULSANTE) == HIGH)
  {
    t_pulsante = millis();
  }

  else
  {
    if ((millis() - t_pulsante) >= 500)
    {
      digitalWrite (LED_1, HIGH);
    }
    
    if ((millis() - t_pulsante) >= 1000)
    {
      digitalWrite (LED_2, HIGH);
    }    
  }
}

[/code]

Ma diamo tutti per scontato che abbia messo un debounce hardware, vero?. ;)

Non c'e' bisogno di nessun antirimbalzo hardware: lo fa il software

Per evitare problemi di "rimbalzi" del pulsante (falsi contatti) devi mettere un condensatore da circa 1uF in parallelo al pulsante stesso. C'è chi lo fa via software, ma mi sembra una complicazione inutile che serve solo per risparmiare un condensatore che svolge benissimo il suo lavoro...

I microprocessori sono nati per sostituire l'hardware con il software. A mio parere le complicazioni inutili sono aggiungere componenti che potrebbero non esserci.

Ciao Marco

Non c'e' bisogno di nessun antirimbalzo hardware: lo fa il software

Non lo vedo nel tuo programma...

Se ci sono dei rimbalzi alla pressione del pulsante non c'e' nessun effetto negativo perche' il tempo viene riazzerato.

A meno che i rimbalzi durino piu' di 500 mS :D :D :D

Edit: a meno che nei rimbalzi ci sia uno stato LOW di piu' di 500 mS, nel qual caso si chiamerebbe "pressione del pulsante"

Non c'è, credo si riferisse alla mera attivazione della pullup interna...

ok come non detto ;)

Tante teste tante soluzioni diverse, chi peggio, chi meglio, chi molto meglio, risolvono il problema :) :) Adesso c'è un vecchio proverbio "il troppo stroppia" :) nel senso che con tante soluzioni diviene fuorviante, e in ogni soluzione ci sarebbe qualcosa da imparare che può tornare utile in altre occasioni, ma considerarle e studiarsele tutto diventa un lavoraccio :) :)

Sulimarco:

Se ci sono dei rimbalzi alla pressione del pulsante non c'e' nessun effetto negativo perche' il tempo viene riazzerato.

Appunto. Questo è un problema. :)

torn24:

considerarle e studiarsele tutto diventa un lavoraccio

No. Anzi, permette di vedere vari modi in cui si può affrontare un problema e valutarne pregi e difetti, anche in base alle esigenze specifiche.

Sulimarco: Non c'e' bisogno di nessun antirimbalzo hardware: lo fa il software

Si, lo fa quello che ho scritto IO, non quello originale... ;)

I microprocessori sono nati per sostituire l'hardware con il software. A mio parere le complicazioni inutili sono aggiungere componenti che potrebbero non esserci.

Questo lo dici tu. (cit.) ;) Nel caso in questione, dipende dalla qualità del pulsante, ma il debounce hardware è sempre più affidabile a meno di non mettere dei delay() relativamente lunghi che però bloccano l'esecuzione). Col debounce hardware ad esempio potresti gestire la cosa con gli interrupt su FALLING...

torn24: Tante teste tante soluzioni diverse, chi peggio, chi meglio, chi molto meglio, risolvono il problema :) :)

Si ma è l'OP che dovrebbe "farsi vivo" e magari dirci se le cose indicate come consiglio le comprende o meno, non trovi?

ma considerarle e studiarsele tutto diventa un lavoraccio :) :)

Studiare è SEMPRE utile e non si finisce mai, se uno vuole progredire e imparare magari cose nuove bisogna sforzarsi di farlo.

IL file allegato visualizza il concetto dell’antirimbalzo (debouncing)

Per gli amanti delle soluzioni hardware esistono dei chip dedicati come Questo

Forse puo’ essere interessante dare un’occhiata al datasheet …

Marco

Debouncing.jpg

Ragazzi che dirvi, siete fantastici! Il debounce l'ho messo tramite hardware. Mi studio tutte le soluzioni che avete proposto e vedrò di capire la migliore.