Cerca nel blog

La Chat

venerdì 18 febbraio 2022

74HC595

 Registro a scorrimento

ha 8 pin di uscita separati pilotati da solo 3 pin di ingresso

        

Push Button e 74HC595 su Arduino

Tutorial Push Button – 1 74HC595, 8 led e 2 Pulsanti

In questo tutorial useremo due pulsanti push button ed approfondiremo l’uso di uno Shift Register 74HC595 per accendere interattivamente 8 led con Arduino.

Introduzione

Questo tutorial estende il precedente (Tutorial 74HC595 v1) 8 led con uno Shift Register introducendo due pulsanti con cui andare a comandare lo Shift Register; seguitelo fino al completamento dell’assemblaggio della breadboard, cioè arrivate allo step 9. Il codice utilizzato in quel tutorial non sarà qui necessario.

Lista della SpesaPush Button 74HC795 8 LED

Per questo progetto avrete bisogno di:


[amazon_link asins=’B01N67ICEC,B00QH6FFXS,B008GRTSV6,B06X3VT6TD,B01JJ94UVW’ template=’ProductCarousel2′ store=’azerbinati-21′ marketplace=’IT’ link_id=’4c2fb225-37e6-11e8-bef0-8339c29fbe44′]

I Pulsanti

Prima di iniziare, un piccolo ripasso sui pulsanti push button. Questi componenti sono più correttamente denominati interruttori momentanei, ad indicare in primo luogo che dal punto di vista elettrico sono interruttori ed inoltre che la loro caratteristica meccanica impone che lo stato dell’interruttore ritorni al suo punto di equilibrio quando lo si rilascia. Ci sono sia pulsanti normalmente aperti (NO, normally open) che normalmente chiusi (NC, normally closed), oltre ad interruttori che espongono entrambi gli stati; in ogni caso, se sono momentanei, il circuito viene aperto o chiuso solo finchè viene mantenuta la pressione su di esso. I più comuni nei progetti arduino sono push button NO, ossia sono pulsanti che chiudono il circuito solo quando li si preme e riaprono il circuito appena li si rilascia.

Push Button

Questi pulsanti hanno 4 piedini e non 2 come ci si potrebbe aspettare, ma è solo per questioni meccaniche: poggiando su 4 piedini potete premerli senza problemi. I 2 piedini sullo stesso lato sono sempre connessi tra loro (pin “a” e “c” dell’immagine), mentre i piedini appartenenti al lato opposto si connettono in base allo stato dell’interruttore. Quindi quando li montate fate attenzione a ruotarli nel verso corretto come indicato nel relativo datasheet. Se avete dubbi, un multimetro può aiutarvi a chiarire quale sia il lato giusto con la funzione “corto circuito”.

Se stavate pensando di collegare semplicemente al Vcc da un alto dell’interruttore ed un pin digitale dall’altra, sappiate che così non può funzionare. Infatti, quando il pulsante è aperto, il pin arduino si troverebbe sconnesso sia dal ground che dal vcc, ed il suo valore logico fluttuerebbe in balia delle interferenze elettriche. Che il circuito sia aperto o chiuso, il pin deve comunque risultare connesso. Vediamo quindi come fare.

Ci sono due modi per usare un pulsante con Arduino, in pull-up od in pull-down; nel primo caso il pin di INPUT sarà in stato LOW a pulsante rilasciato e HIGH a pulsante premuto, sarà il contrario nel caso del pull-down.

Schema pull-up pulsante ArduinoNello schema a fianco vediamo un esempio di collegamento di un pulsante in pull-up sul pin 4 di Arduino.

Quando l’interruttore è aperto, il pin D4 è connesso a ground tramite la resistenza da 10k; poichè non circola corrente, non c’è differenza di potenziale sulla resistenza e quindi l’input sarà quindi pilotato al livello LOW.

Quando si preme il pulsante, la corrente proveniente dal Vcc 5V fluirà attraverso l’interruttore, proseguirà attraverso la resistenza R1 da 10k ed andrà a ground. La corrente verso pin D4 è praticamente zero. Essendoci 5V di caduta di tensione su R1, possiamo anche calcolare quanta corrente passerà per il circuito quando si preme il pulsante: I= V/R = 5/10.000 = 0.5mA.

Poichè la caduta di tensione è totalmente a cavallo di R1, il pin D4, posto tra lo switch e la resistenza, andrà a livello HIGH di 5V.

Lo schema in pull-down è analogo: resistenza R1 e pulsante si scambiano di posto. Poichè la corrente non può fluire attraverso il pin di input, su R1 non c’è caduta di potenziale (V = RI, con I~0 -> V~0) ed il pin risulta quindi HIGH; con il pulsante premuto, si chiude il circuito tra tra Vcc e Ground, sulla resistenza vengono quindi imposti 5v di potenziale ed il pin D4, trovandosi dalla parte del ground, diventa LOW.

Push Button su Breadboard connesso ad ArduinoIn questo tutorial useremo lo schema pull-up per i nostri push button. Sulla breadboard possiamo vedere implementato lo stesso schema pull-up. Quando il pulsante non è premuto sulla resistenza non scorre corrente e quindi non c’è differenza di potenziale tra il GND ed il pin4.   Premendo il pulsante, la corrente scorre dal Vcc al GND del rail inferiore generando la differenza di potenziale a cavallo della resistenza e portando così a HIGH il pulsante a cui è collegato il cavetto che porta al pin4.

Push Button e 74HC595 su Arduino

Aggiungiamo due pulsanti; per entrambi, da un lato avremo un cavetto connesso a Vcc e dall’altro lato avremo sia una resistenza da 10k che il cavetto verso un pin digitale di arduino, usate i pin 12 e 13. Le resistenze andranno poi connesse a GND. Fate attenzione però che il rail inferiore ha il potenziometro in serie, quindi non è un GND! Collegatevi invece al GND del rail superiore o a valle del potenziometro (come mostrato nello schema).

Lo sketch

Sketch
//Connesso al Pin DS del 74HC595
int dataPin = 8;
//Connesso al Pin ST_CP del  74HC595
int latchPin = 9;
//Connesso al Pin SH_CP del 74HC595
int clockPin = 10;
 
//connesso ad uno pulsante
int button1Pin = 12;
//connesso ad uno pulsante
int button2Pin = 13;
 
 
//flag di stato dei pulsanti
bool b1Status=LOW;
bool old_b1Status=LOW;
bool b2Status=LOW;
bool old_b2Status=LOW;
 
 
 
void setup() {
  //configuriamo i 3 pin di  output
  pinMode(dataPin, OUTPUT);
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
 
  pinMode(button1Pin, INPUT );
  pinMode(button2Pin, INPUT);
 
}
 
 
//procedura che ci consente di mandare da un singolo bit al 74HC595
 
void push(bool aBit)
{
   digitalWrite(clockPin, 0); //mi assicuro che clock si LOW
   digitalWrite(latchPin, 0); //abbasso il latch per iniziare a programmare il 74HC595
 
   digitalWrite(dataPin,aBit ); // alzo il pin data in base al bit corrente in aByte;
   digitalWrite(clockPin, 1); //alzo il clock -> abbiamo "spinto" il valore 1 nel primo registro del 74HC595.
    
   digitalWrite(dataPin, 0); //rimetto a zero il data pin e clock pin per non portare valori HIGH oltre questo punto.
   digitalWrite(clockPin, 0);
 
   digitalWrite(latchPin, 1); //latch HIGH per confermare gli output.
}
 
 
void loop() {
 
   b1Status=digitalRead(button1Pin); //leggiamo lo stato dei due pulsanti
   b2Status=digitalRead(button2Pin);
   if ( old_b1Status!=b1Status && b1Status== HIGH) //il primo pulsante è premuto, e non lo era prima
    push(1);
    
      
   if ( old_b2Status!=b2Status && b2Status== HIGH) //il secondo pulsante è premuto, e non lo era prima
     push(0);
 
   delay(100);  //anti bounce minimale.
    
   old_b1Status=b1Status;
   old_b2Status=b2Status;
 
}

Bounce, il rimbalzo del pulsante.

Cos’è il rimbalzo del push button?

In questo sketch abbiamo usato un delay(100) per evitare il rimbalzo del pulsante, ma di che cosa si tratta?

Molto semplice, il pulsante è un dispositivo fisico ed il suo comportamento non è ideale e va incontro sia a problemi di natura meccanica che fisica.

Ci sono problemi meccanici perché, per quanto sia veloce il movimento esercitato su di esso, i due contatti inizieranno dapprima toccandosi timidamente per poi stringersi via via più saldamente, e quando iniziano solo a toccarsi appena appena potrebbero dare un contatto estemporaneo che subito si interrompe; inoltre le due lamine, sfregandosi durante movimento, potrebbero sovrapporre parti leggermente ossidate che interrompono solo momentaneamente il contatto.

Bisogna anche ricordare che non si può andare contro la fisica, sappiamo come funziona il circuito aperto e come funziona il circuito chiuso, tuttavia abbiamo trascurato il transitorio in cui le correnti non sono continue, ma passano da un equilibrio ad un altro. Con correnti variabili, anche un semplice cavetto, presenterà una certa induttanza così come ogni componente interessato al cambiamento; semplificando, il nostro circuito si opporrà al cambio di equilibrio che non verrà raggiunto immediatamente bensì solo al termine di un concitato transitorio durante il quale le tensioni lette dal pin4 potrebbero oscillare attorno al livello logico che separa HIGH da LOW.

Debounce con delay()

Senza accorgimenti, il nostro Arduino nel leggere il potenziale sul pin potrebbe considerare ogni piccolo sbalzo del transitorio come una nuova pressione del tasto. Mettere un delay(100) è un modo molto semplice per evitare il problema. In pratica, ogni volta che rileviamo la pressione di un tasto ci blocchiamo per 100ms, al termine dei quali il transitorio sarà cessato.

Non è certo il modo migliore, ma forse il modo migliore per sperimentare cosa sia il bounce: commentate il delay e riprovate a premere i pulsanti; sono certo che questa volta non sempre ad una pressione corrisponderà un solo shift del registro!

Un lato negativo dell’uso di un delay per evitare il rimbalzo è che stiamo bloccando l’MCU per tutto il tempo del transitorio, precludendo così qualsiasi gestione “multitask” del dispositivo: se ad esempio dei sensori ci stanno mandando dei segnali, rischiamo di perderli. Vedremo nel prossimo sketch la tecnica corretta per gestire il debounce.

Debounce con millis()

Possiamo usare la funzione <code>millis()</code> per ignorare ogni pressione che avvenga troppo vicina ad una precedente senza mettere mai in pausa l’MCU.

Nello sketch sono state aggiunte due variabili, una che viene aggiornata con il tempo dell’ultima pressione valida ed una con il numero di millisecondi in cui si presume il transitorio si sia esaurito. Il tempo presunto è arbitrario, e dipende dal tipo di interruttore (o sensore) e dal tipo di utilizzo.

Ho usato un’unica gestione del transitorio per entrambi i pulsanti a dimostrare che non c’è bisogno di gestire il transitorio per ogni pulsante collegato ad arduino.

Ovviamente se gli input sono molto diversi o indipendenti, potrebbe essere opportuno differenziarne la gestione: immaginate di avere un interruttore a galleggiante che si chiude quando il livello di un serbatoio raggiunge un certo livello: è facile immaginare che per un tale interruttore il transitorio possa durare anche diversi secondi se non addirittura minuti visto che ogni movimento del liquido potrebbe far scattare ripetutamente l’interruttore. Se avete avuto macchine molto vecchie, vi ricorderete di quando la spia della riserva si accendeva in curva e si spegneva in rettilineo!

Sketch finale

Qui sotto vi riporto lo sketch finale con la gestione del debounce con l’uso di millis()

Sketch
//Connesso al Pin DS del 74HC595
int dataPin = 8;
//Connesso al Pin ST_CP del  74HC595
int latchPin = 9;
//Connesso al Pin SH_CP del 74HC595
int clockPin = 10;
 
//connesso ad uno pulsante
int button1Pin = 12;
//connesso ad uno pulsante
int button2Pin = 13;
 
//flag di stato dei pulsanti
bool b1Status=LOW;
bool old_b1Status=LOW;
bool b2Status=LOW;
bool old_b2Status=LOW;
 
unsigned long lastDebounceTime = 0;  // tempo dell'ultimo click
unsigned long debounceDelay = 100;   // millisecondi del transitorio
 
 
void setup() {
  //configuriamo i 3 pin di  output
  pinMode(dataPin, OUTPUT);
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
 
  pinMode(button1Pin, INPUT );
  pinMode(button2Pin, INPUT);
  
}
 
 
//procedura che ci consente di mandare un singolo bit
 
void push(bool aBit)
{
 
  
    
   digitalWrite(clockPin, 0); //mi assicuro che clock si LOW
   digitalWrite(latchPin, 0); //abbasso il latch per iniziare a programmare il 74HC595
 
   digitalWrite(dataPin,aBit ); // alzo il pin data in base al bit corrente in aByte;
   digitalWrite(clockPin, 1); //alzo il clock -> abbiamo "spinto" il valore 1 nel primo registro del 74HC595.
    
   digitalWrite(dataPin, 0); //rimetto a zero il data pin e clock pin per non portare valori HIGH oltre questo punto.
   digitalWrite(clockPin, 0);
 
   digitalWrite(latchPin, 1); //latch HIGH per confermare gli output.
}
 
 
void loop() {
 
   b1Status=digitalRead(button1Pin); //leggiamo lo stato dei due pulsanti
   b2Status=digitalRead(button2Pin);
   if ( (millis() - lastDebounceTime) > debounceDelay && old_b1Status!=b1Status && b1Status== HIGH) //nessun pulsante è stato premuto di recente ed il primo pulsante è premuto, e non lo era prima
   {
    push(1);
    lastDebounceTime = millis();
   }
    
      
   if ( (millis() - lastDebounceTime) > debounceDelay && old_b2Status!=b2Status && b2Status== HIGH) //nessun pulsante è stato premuto di recente ed il secondo pulsante è premuto, e non lo era prima
   {
     push(0);
     lastDebounceTime = millis();
   }
 
   old_b1Status=b1Status;
   old_b2Status=b2Status;
 
}
Video Player

Nessun commento: