PULSANTE E LED INTERMITTENTI

Ciao a tutti... Come ho scritto nel mio saluto iniziale ho iniziato a lavorare con Arduino solo pochi giorni fa.

Ho cominciato con la realizzazione del classico led lampeggiante per poi passare allo spegnimento e accensione del led con un pulsante e poi all'accensione di più led.

Siccome mi scocciava tener premuto il pulsante ho messo la cosidettà Autoritenuta con questo sistema:

int LEDRED = 13;
int LEDBLUE = 12;
int LEDYELLOW = 11;
int BOTTONE = 7;
int TASTO = LOW;
int STATOLED = LOW;
int TASTOPREC = LOW;
int STATO = LOW;

void setup() {
  // inizializzazione del pin in uscita
  pinMode (LEDRED, OUTPUT);
  pinMode (LEDBLUE, OUTPUT);
  pinMode (LEDYELLOW, OUTPUT);
  pinMode (BOTTONE, INPUT);
}

void loop() {
  // Acquisizione stato bottone
  STATO = digitalRead(BOTTONE);
  if (STATO != TASTOPREC && STATO == HIGH)
  {
  STATOLED = 1 - STATOLED;
  } 
  digitalWrite (LEDRED,STATOLED);
  digitalWrite (LEDBLUE,STATOLED);
  digitalWrite (LEDYELLOW,STATOLED);
  delay (1000);
  TASTOPREC = STATO;
}

Ora sto diventando matto perchè vorrei che alla pressione del pulsante si accendessero i led e iniziassero a lampeggiare fino a quando non ripremo il pulsante per spegnere il tutto. Quello che ottengo invece è che i led lampeggiano ma non si spengono.

Forse mi sto troppo focalizzando su questo codice e forse dovrei cambiarlo totalmente... Vi chiedo un aiutino...

Ciao,
intanto, come dice il regolamento, i codici dovrebbero stare nell'apposita casella code.

Passando al tuo sketch, ci sono un bel po' di cose sbagliate, ma non disperare, è l'inizio.
Intanto ti proporrei di studiare un po' di C, che non fa mai male, dopodiché il sito è pieno di esempi, guide e tanto, ma tanto materiale per vedere come funziona Arduino.

Veniamo al dunque, nel tuo sketch c'è uno spreco immenso di memoria, che, per ora non i serve, ma quando farai cose più complicate allora si che sarà un problema, quindi sarebbe buona norma abituarti già da ora. Per una variabile che sai assumerà per forza due valori è inutile usare un int, ma è preferibile usare una variabile booleana, vedi bool. Nel tuo caso ci sono quattro variabili che hanno proprio queste caratteristiche ovvero TASTO, STATOLED, TASTOPREC e STATO. Ma ancora non siamo arrivati alla risoluzione del tuo problema. Ora, passando alla logica. Il problema per cui non fa quello che vuoi è che non acquisisci bene il segnale, non so cosa volessi fare con quel STATOLED = 1 - STATOLED, ma non credo proprio sia giusto, un approccio più corretto sarebbe:

if (TASTO != TASTOPREC)
  {
  STATO = digitalRead(BOTTONE);
  }

Considerando chq anche questo non è corretto perché non c'è alcuna strategia di debounce, che imparerai per bene cos'è se avrai a che fare con dei pulsanti. Dopodiché l'altro problema sostanziale è il delay, da usare in casi più unici che rari perché mette in pausa l'arduino, in pratica dorme per 1 secondo e, se malauguratamente, la pressione del tuo tasto avviene proprio in quel secondo, lui se ne frega, perché sta riposando. Siccome noi dobbiamo evitare questi casi ci ingegniamo con la benedetta funzione millis() che ci viene in soccorso. per questo per il lampeggio del led (oltre a trovare un esempio nella cartella esempi dell'ide) è preferibile evitare il delay. Ho modificato quindi il tuo sketch così:

if(STATO == 1) {
    

    if(millis() - delayTime >= 1000) {
      delayTime = millis();

      if(STATOLED == LOW) {
        STATOLED = HIGH;
      }
      else{
        STATOLED = LOW;
      }
    }
    digitalWrite ( 13, STATOLED);
    digitalWrite (LEDBLUE,STATOLED);
    digitalWrite (LEDYELLOW,STATOLED);
    
  }

in modo tale che questo atmega non riposi mai!

Infine, non so quale sia il tuo schema per far fungere il tutto, ma dovresti mettere delle resistenze di pull-up sul pulsante oppure, se non ti aggrada l'idea di aggiungere altri componenti, cambiare il

pinMode (BOTTONE, INPUT);

in

pinMode (BOTTONE, INPUT_PULLUP);

questo attiverà la resistenza di pullup interna all'Arduino.

Spero di essere stato abbastanza esaustivo se hai altre domande chiedi pure!

(per i guru di arduino, se ho fatto errori anch'io, correggetemi! )

Ciao,
Giovicavalla

Ti ringrazio tantissimo @Giovicavalla so di aver trasgredito un po' di regole forzando la mano ma avevo bisogno proprio di una dritta su come impostare il lavoro in generale...

Qualche base di C++ ce l'ho ma devo implementare con le basi della programmazione in arduino. Sicuramente l'idea di ragionare fin da subito sull'uso della memoria ed evitare di sprecarla è un consiglio prezioso.

Per quanto riguarda la realizzazione del circuito ho messo anche la resistenza di Pullup. In elettronica me la cavo.

Il problema del debounce l'ho affrontato dopo aver pubblicato sul forum. Devo però ancora leggermi bene i vari post a riguardo.

Grazie anche per la dritta sul comando millis (). Già ieri notte ho letto svariati argomenti a riguardo perchè ignoravo proprio la possibilità di usare questo al posto di delay.

Il codice si deve racchiuderlo nei tag code, vedere sezione 7 del regolamento, spiega bene come fare ( pulsante </> ).
Altrimenti parte del codice può essere visualizzata male o mancare perchè interpretato come attributo del testo stesso.

Pensavo a qualcosa di semplice, che risolvesse il problema, prova a vedere se capisci il codice.

int LEDRED = 13;
int LEDBLUE = 12;
int LEDYELLOW = 11;
int BOTTONE = 7;
int STATO = LOW;

void setup() {
  // inizializzazione del pin in uscita
  pinMode (LEDRED, OUTPUT);
  pinMode (LEDBLUE, OUTPUT);
  pinMode (LEDYELLOW, OUTPUT);
  pinMode (BOTTONE, INPUT);
}

void loop() {
  // Acquisizione stato bottone
  STATO = digitalRead(BOTTONE);
  int funzione=0;
  if(STATO==HIGH){//SOLO QUANDO IL PULSANTE VIENE PREMUTO mettere high o low in base al circuito
      if(funzione==0){// cambio il valore di funzione, se 1 diventa zero, se zero diventa 1 solo quando premo il pulsante
         funzione=1;
      }
      else{
         funzione=0;;
      }
  }
  if(funzione==1)lampeggio();
}

void lampeggio(){
  digitalWrite (LEDRED,HIGH);
  digitalWrite (LEDBLUE,HIGH);
  digitalWrite (LEDYELLOW,HIGH);
  delay (1000);
  digitalWrite (LEDRED,LOW);
  digitalWrite (LEDBLUE,LOW);
  digitalWrite (LEDYELLOW,LOW);
  delay(1000);



}

devi unire questo
https://www.arduino.cc/en/tutorial/switch
e questo

il debounce software non è infallibile, ne con delay, ne con millis(), ti consiglio di associare un elementare debounce hardware per migliorare di molto le prestazioni degli impulsi di ingresso

c25c654030b17d64d12f3befb36fe27797af072b.png

Ciao,
@torn24, non capisco..non hai messo ne debounce, ne hai usato la funzione millis() per il lampeggio..la funzione delay() interrompe l'esecuzione di qualsiasi compito dell'arduino, non va usata quasi mai.

Ciao, Giovicavalla

Forse mi sto troppo focalizzando su questo codice e forse dovrei cambiarlo totalmente... Vi chiedo un aiutino...

si dovresti cambiarlo un attimino

come ti ho detto sopra

Funzione che intercetta la pressione del pulsante

void switch_button(){ 
  reading = digitalRead(inPin);

  if (reading && !previous && millis() - time > debounce) {
    if (button_state)  button_state = false;
    else  button_state = true;

    time = millis();    
  }
  lampeggio();

  previous = reading;
}

funzione che fa lampeggiare il led in base all'impulso intercettato dal button

void lampeggio() {
  if (millis() - previousMillis >= interval) {
    previousMillis = millis();
     if (!led_state) led_state = true;
     else led_state = false;
    
     digitalWrite(outPin, led_state * button_state);
  }
}

loop() che richiama di continuo la lettura del pulsante

void loop(){
  switch_button();
}

variabili varie

const byte inPin = 7;         
const byte outPin = 8;       

bool button_state = false;      
bool led_state = false;  
bool reading;            
bool previous = false;     

unsigned long time = 0;          
const long debounce = 200;   
unsigned long previousMillis = 0;      
const long interval = 400;
void setup(){
  pinMode(inPin, INPUT);
  pinMode(outPin, OUTPUT);
}

digitalWrite(outPin, led_state * button_state);
contiene una sorta di ENABLE invece che usare un IF()
Ci vuole anche un debounce RC

@Giovicavalla, è in pratica il classico esempio Blink led, non fa nessuna differenza se a lampeggiare sono 1 led, o 3, non vedo dal suo codice che volesse fare qualcosa di diverso, il quesito, la necessità, era che il pulsante fungesse da "interruttore" per il lampeggio dei led, premendolo lampeggiano, premendolo nuovamente, non lampeggiano più, delay() mette in pausa l'esecuzione del codice, ma questo è un problema sole se si devono fare più cose contemporaneamente, ossia necessito di una pausa per uno scopo ma al contempo devo eseguire altre cose,

In effetti, qui si devono fare due cose, leggere continuamente l'input del pulsante, e far lampeggiare i led, e quindi è meglio usare un sistema con millis

delay() o non delay() ? ... vi consiglio di leggere da QUI in poi :wink:

Guglielmo

Ciao,
@Guglielmo, in questo caso credo che il delay(), come dici tu "demonizzato", non si possa usare, soprattutto se i led devono avere un lampeggio di un secondo, vale a dire che il codice, ogni loop, si ferma per 2 secondi. in quei due secondi se premi il pulsante non succede proprio niente. Anch'io la trovo una funzione utilissima, vedi per esempio nel setup in uno sketch in cui si usa tanto la seriale. Poi non so, tu sei uno dei Guru della situazione!

@torn24, come hai precisato alla fine del tuo post, in questo caso, anche se semplicissimo, si devono fare due cose ben distinte, far lampeggiare i led e leggere il pulsante. Quindi, per quanto possa essere più semplice usare il delay e per quanto possa essere semplice lo sketch, il delay, per quanto mi riguarda, io non lo metterei.

Giovicavalla:
@Guglielmo, in questo caso credo che il delay(), come dici tu "demonizzato", non si possa usare, soprattutto se i led devono avere un lampeggio di un secondo, vale a dire che il codice, ogni loop, si ferma per 2 secondi. in quei due secondi se premi il pulsante non succede proprio niente.

... esatto ... quindi questo è uno dei casi dove usare la tecnica della millis() :wink:

Guglielmo

Mi dispiace ma concordo con @Guglielmo e @Giovicavalla

Anche se non avevo rimesso il codice perchè era troppo tardi avevo già iniziato a lavorare sulla variante inserendo il comando millis()

Il vero problema però era come gestire correttamente il pulsante e mi avete dato ottime idee...

Ringrazio tanto anche @Pablos per la dritta del condensatore sul pulsante per ovviare il problema del debounce... Nel mio circuito la resistenza da 10K è tra il pulsante e GROUND.

Ho messo una resistenza di Pull-up 1kΩ su ogni uscita che va a un diodo led.

Veramente ti ho dato anche lo sketch completo e funzionante che fa esattamente quello che chiedi :slight_smile:
non ti resta che provarlo, studiarlo e modificarlo aggiungendo il pulsanti e led che ti servono.
L'ho separato in blocchi (che puoi copiare e incollare nella stessa pag dell IDE) perchè comprendessi meglio le funzioni distinte piuttosto che miscelare tutto nel loop().
Per chi non conosce il millis() non non è prprio facile facile mischiare 2 funzioni millis nello stesso ciclo, ora hai la possibilità di capirlo, spesso si impara con programmi già fatti modificandoli e studiandoli.

ciao

PS: mancava il setup() che ho aggiunto adesso.

pablos:
... spesso si impara con programmi già fatti modificandoli e studiandoli.

Sai che non sono completamente d'accordo ...

... ritengo comunque propedeutico lo studio di ciò che si andrà ad utilizzare, poi ben vengano gli esempi per capire, perché ... la "pappa fatta" spesso è, purtroppo, usata solo per dei bei copia/incolla senza capire nulla ::slight_smile:

Guglielmo

mgonline:
...
Ho messo una resistenza di Pull-up 1kΩ su ogni uscita che va a un diodo led.

Scusa, ma la cosa non ha senso ... le pullup sulle uscite si usano solo in caso di uscita "open-collector", ma qui hai uscite che ti danno 1 o 0 , quindi non serve a nulla mettere pullup (o pulldown) su di esse ...

Sai che non sono completamente d'accordo ...

Si lo so ... e anche io spesso non sono d'accordo....

Riconosco i copia/incolla e non mi è sembrato uno di quelli.
Ha già iniziato a usare pulsanti e led ... ora a far lampeggiare un led con una procedura più complicata del normale, non penso che il suo intento sia quello di fermarsi al pulsantino e al led .
Se quello sketch non lo capisce fino in fondo non se ne farà nulla, non sarà nemmeno in grado di modificarlo.

Io ho imparato così leggendo copiando e modificando gli esempi sui libri e quegli esempi qualcuno li ha scritti.

comunque il tempo ci dirà :slight_smile:

pablos:
Riconosco i copia/incolla e non mi è sembrato uno di quelli.

Si, si, concordo :), il mio era un discorso generale e non mirato al caso in questione :wink:

Guglielmo

Tranquilli mi sbatto volentieri... Non mi piace molto la pappa pronta neanche a me tanto è vero che ho già comunque modificato il codice di @pablos per rendere ottimale il mio obiettivo cioè usare tre uscite con tre led lampeggianti e non una sola.

@Etemenanki le resistenze servono anche per proteggere i led... Avrei messo una resistenza da massimo 330 Ohm ma per sicurezza ho messo quella da 1 kOhm.

Vedete che non copio solo... Ho trasformato la breadboard in una discoteca ambulante :sweat_smile:

const byte LEDRED = 13;
const byte LEDBLUE = 12;
const byte LEDYELLOW = 11;
const byte PULSANTE = 7;

bool STATOLED = false;
bool STATOLED2 = false;
bool STATOPREC = false;
bool LETTSTATO;
bool STATOPULS = false;

unsigned long time = 0;          
const long debounce = 200;  
unsigned long previousMillis = 0;      
const long interval = 1000; 
unsigned long previousMillis2 = 0;
const long interval2 = 500; 

void setup() {
  // inizializzazione del pin in uscita
  pinMode (LEDRED, OUTPUT);
  pinMode (LEDBLUE, OUTPUT);
  pinMode (LEDYELLOW, OUTPUT);
  pinMode (PULSANTE, INPUT);
}


void button() {
  LETTSTATO = digitalRead(PULSANTE);

  if (LETTSTATO && !STATOPREC && millis() - time > debounce) {
    
      if (STATOPULS)  STATOPULS = false;
      else  STATOPULS = true;
    
    time = millis();    
    
  }
  lampeggioA();
  lampeggioB();
  STATOPREC = LETTSTATO;
}

void lampeggioA() {
  if (millis() - previousMillis >= interval) {
    previousMillis = millis();
     if (!STATOLED) STATOLED = true;
     else STATOLED = false;
     digitalWrite(LEDRED, STATOLED * STATOPULS);
     digitalWrite(LEDYELLOW, STATOLED * STATOPULS);
  }
}

void lampeggioB() {
  if (millis() - previousMillis2 >= interval2) {
    previousMillis2 = millis();
     if (!STATOLED2) STATOLED2 = true;
     else STATOLED2 = false;
     digitalWrite(LEDBLUE, STATOLED2 * STATOPULS);
   }
}

void loop() {
  button() ;
}