Giu 192013
 

Oggi vediamo come collegare numerosi relè 12V ad Arduino. Uno degli articoli più visitadi di questo blog è il primo articolo sul collegamento di un relè 12V a cui vi rimando per un ripasso delle informazioni di base; inoltre vi ricordo che qui ho pubblicato un calcolatore online utile per dimensionare la resistenza alla base del transistor. Oggi vediamo l’evoluzione di quegli articoli e ci chiediamo: come facciamo ad aggiungere altri relè? E se volessi comandare 24 relè con un singolo Arduino posso farlo? E se si come? Ora che sappiamo quali sono le domande cominciamo con la parte pratica.

ULN2803

Se abbiamo studiato come collegare un relè, possiamo facilmente espandere la cosa sino an un massimo di 14, ossia il numero di porte digitali in uscita da arduino, anche se a dirla tutta potremmo sfruttare anche quelle analogiche per pilotare i transistors, ma non complichiamoci la vita inutilmente. Se ricordate, per ogni relè ci servirà una resistenza, un diodo ed un transistor, oltre al relè vero e proprio. Nello schema qui sopra vediamo come anche aggiungendo solo 3 relè a quello iniziale comincia a generarsi abbastanza confusione con un notevole aumento di componenti e piste sul circuito. Sia ben chiaro, un circuito così è facilmente realizzabile, è funzionante e non c’è particolare motivazione per non indicarlo se escludiamo il numero di collegamenti da creare e l’ingombro complessivo. Ma sicuramente qualcuno prima di noi avrà cercato di ridurre la ripetitività di questo tipo di circuito ed avrà trovato una soluzione che ci possa semplificare la vita. Ebbene si, esistono in commercio dei circuiti integrati che fanno al caso nostro: parliamo dell’ULN2803. Che cosa ci permette di fare? Semplice, con un solo integrato dal costo inferiore all’euro abbiamo otto canali indipendenti già completi e pronti all’uso, nel senso che va a sostituire, per ogni canale, la resistenza, il diodo ed il transistor, inoltre accetta voltaggi fra 5V e 50V e carichi sino a 500mA per ogni singolo canale. Nella realtà è un po’ più complesso della mia solita semplificazione, ma ai fini del nostro articolo ci basta sapere che può sostituire tutti i componenti (esclusi i rele’) permettendo correnti sino 500mA per canale e tensioni da 5 a 50V. Lo schema classico è quello qui a lato: vediamo che ci sono gli otto ingressi e le otto uscite, una massa ed un ingresso per l’alimentazione. Il collegamento è molto semplice, non dobbiamo far altro che collegare le uscite di Arduino agli ingressi dell’ULN2803, collegare massa, alimentazione e per finire le uscite dell’ULN2803 ai relè. Lo schema è riportato qui sotto: come potete vedere c’è un notevole risparmio in componentistica con evidente semplificazione del circuito. Inoltre il minor numero di saldature sul circuito finale determinerà una maggior affidabilità dello stesso. Fate attenzione al fatto che l’ULN gestisce l’attivazione o lo scollegamento delle linee di massa e non di alimentazione. Altra cosa, vi faccio notare,  le masse di Arduino e dell’alimentazione esterna devono essere unite insieme. Per completezza, vi allego qui sotto una foto reale di un test su breadbord funzionante. Potete notare il collegamento di Arduino con l’ULN e quest’ultimo con tre relè. Ne ho collegati solamente tre solo per motivi di praticità. Sul lato destro della foto si notano due coccodrilli rosso e nero che portano rispettivamente la VCC e la massa dell’alimentatore 12V esterno.

Ma andiamo oltre. Arduino possiede altre porte libere per cui potremmo affiancare un altro ULN2803 per unire ulteriori relè, anche se non riusciremmo a sfruttare tutte le uscite del secondo integrato. Ma se volessimo andare oltre ad esempio collegando 16 relè? E’ possibile farlo? In effetti potremmo avere l’esigenza di comandare 16 relè e magari gestire altrettanti ingressi ma a prima vista sembrerebbe necessario usare due schede Arduino in quanto non abbiamo abbastanza porte.

Shift Register 74HC595

La soluzione è lo shift register, come ad esempio il 74HC595 che è un chip SIPO (Serial In Output Out). Cose significa? Significa che riceve un input seriale e fornisce un output parallelo. Pensiamoci bene. Sappiamo già cos’è una trasmissione seriale, un singolo carattere trasmesso occupa 8 bit per cui con un solo byte inviato serialmente si potrebbe indicare lo stato di ben 8 uscite. Il concetto è proprio questo. Vengono inviati i singoli bit allo shift register, questi “si spostano” all’interno delle otto celle di memoria dello shift register stesso fino al completamento dei bit ricevuti. Arriva il primo bit che si mette nella prima cella. Quando arriva il secondo, il precedente sarà spostato (shift) nella cella adiacente e la prima sarà occupata dal nuovo bit e via discorrendo sino al termine dei dati. A questo punto, per completezza, meglio specificate che esistono due grosse famiglie di shift registers, quelli con latch e quelli senza. I secondi, man mano che arrivano i bit, impostano le relative uscite, mentre quelli con latch attendono un segnale aggiuntivo per copiare i dati dalle celle dello shift register in apposite celle di memoria (storage) che vanno a loro volta ad attivare o disattivare le varie uscite. Ovviamente non possiamo usare uno shift register senza latch per comandare ad esempio dei relè. Facciamo un semplice esempio. Se inviamo un primo bit pari a 1, se lo shift register non ha un meccanismo di latch, viene subito attivata la prima uscita ed il relè si attiva. All’arrivo di un secondo bit pari a 0 il precedente si sposta sulla seconda uscita accendendo il secondo relè ed andando a spegnere il primo per l’arrivo dello 0. In questo modo si ha una repentina serie di accensioni e spegnimenti finché il dato non è completato. Questo tipo di chip è perciò indicato quando il ricevente và a leggere le uscite solamente quando tutti i dati sono arrivati a destinazione, come può essere il caso di alcuni display LCD, argomento che affronteremo in futuro. Se invece il nostro chip possiede un meccanismo di latch ci limitiamo ad inviare i dati e poi forniamo un segnale per copiare le celle di memoria nelle relative uscite. Alcuni chip latch come il 74HC595 hanno un secondo meccanismo di attivazione, infatti oltre a copiare le celle di memoria come appena visto, hanno un cosi detto pin di abilitazione (OE: Output Enable) che se non attivato non permette l’abilitazione delle uscite anche se le celle di memoria dello shift register sono state copiate nello storage register (latch). Ora andiamo ad approfondire quanto detto, ossia i dettagli che permettono di inviare i dati nelle celle dello shift register, copiarle nelle memorie dello storage latch e successivamente settare le uscite del 74HC595. Vediamo uno per uno i vari pin del chip 74HC595. DS (Data Serial) è il pin a cui inviamo in ingresso i bit seriali. Da notare una cosa importante. Il primo bit che inseriamo finirà nella prima cella di memoria, poi però con l’inserimento del secondo bit, il primo verrà shiftato (spostato) nella seconda cella e così discorrendo. Una volta inserito l’ottavo bit il primo inserito si troverà nella posizione numero 8 per cui in posizione 8 abbiamo il primo bit, nella 7 il secondo, nella 6 il terzo e via discorrendo. Si comprende perciò che dobbiamo inviare i dati in senso invertito, partendo dall’ultimo per arrivare al primo. ST_CP (detto anche latchPin) e SH_CP sono rispettivamente lo STorage e lo SHift clock pin. Lo shift serve appunto a shiftare nelle celle di memoria i vari bit facendone “entrare” uno nuovo, mentre lo storage, quando attivato, copia le celle di memoria nello stato in cui si trovano in quel momento e le riporta nel latch storage. La loro funzione viene attuata quando il segnale nei loro pin passa da LOW ad HIGH. Quindi, riassumendo, impostiamo su DS il bit da inserire, a LOW o HIGH. Una volta fatto portiamo ad HIGH il valore dell’SH_CP così il nostro bit scorre all’interno delle celle di memoria. Quando vogliamo copiare i valori delle celle dello shift register nello storage register portiamo ad HIGH anche il ST_CP. OE (Output Enable) attiva le uscite quanto il segnale è basso. Quindi quando il segnale è LOW il contenuto dello storage register viene trasferito alle uscite determinandone l’apertura o chiusura in base ai valori memorizzati. Q0 –  Q7 sono le uscite: si noti che Q0 si trova su un versante e gli altri sull’altro, inoltre si noti che Q0 è la prima uscita e Q7 l’ottava. Discorso a parte per il Q7′ che ha un’altra funzione che vedremo dopo ma che, vi anticipo, serve a connettere in serie più 74HC595. GND e Vcc (da 3 a 5V)  non hanno certo bisogno di presentazioni. MR è il master reset che azzera tutte le uscite quando il segnale è low motivo per cui lo connettiamo ai +5V (non vogliamo che resti perennemente azzerato). Nota: è consigliato l’utilizzo di un condensatore da 1microfarad fra l’ST_CP e la massa. Ora che abbiamo tutt le informazioni necessarie,  vediamo come collegare i vari pin nello schema che vi propongo qui sotto:

Ovviamente alle uscite dell’ULN2803 vanno collegati i relè, io ho disegnato dei connettori con contatti a coppie 12V/Gnd. Alcune note: come vedete il MR è collegato direttamente ai +5V per cui le uscite non vengono mai azzerate. OE è collegato a massa, ciò significa che non appena memorizziamo qualcosa nello storage register il suo contenuto si riflette direttamente sull’effettivo contenuto delle uscite. Ovviamente se OE è collegato a massa, dobbiamo per forza controllare direttamente il ST_CP per decidere quando copiare le celle dello shift register nello storage register. In definitiva potete notare come con soli 3 pin di Arduino occupati siamo in grado di pilotare 8 relè, ma la bella notizia è che possiamo unire in serie multipli 74HC595 per andare a comandare 16,24,32 o oltre uscite in contemporanea. Per farlo non facciamo altro che collegare Q7′ al DS del chip successivo ed il gioco  fatto. Nello schema qui sotto vi faccio vedere come si collegano in serie. In questo caso il pin Q7′ è l’uscita seriale del primo chip ed andrà nell’ingresso (DS) del secondo, e così a cascata per eventuali ulteriori chip.

Ora vi domandereet: dov’è la fregatura? La risposta è la velocità, ma solo teoricamente. Infatti, a titolo di paragone,  il nostro Arduino arriva a 16MHz mentre questi chip da 57 a 100MHz (ci sono diversi modelli), ossia possono cambiare stato dello shift register decine di decine di migliaia di volte al secondo, motivo per cui occorre collegarne davvero tanti prima di riuscire a percepire un rallentamento umanamente riconoscibile. Ho fatto un test con 8 led al posto dei relè che si accendo in serie dal primo all’ultimo per poi riprendere e, togliendo ogni tipo di ritardo, la velocità è tale che i led sembrano sempre accesi, non è possibile vedere ad occhio la variazione di luminosità. Anche con 16 led non risulta possibile distinguere ad occhio le tempistiche di illuminazione e spegnimento.

Una cosa importante che ho scordato di dire è che le uscite del 74HC595 hanno una tensione pari a quella di alimentazione (tipicamente 5V ma funziona anche a 3) con una corrente che è inferiore a quella delle uscite di Arduino, tipicamente 20mA.

A dirla tutta è possibile usare degli artifizi misti tra hardware e software per ridurre ulteriormente il numero di pin Arduino impiegati, il rovescio della medaglia è una ulteriore riduzione della velocità ed un incremento della complessità del software, ma in alcuni casi può essere un’opzione da tenere in considerazione, specie se invece che usare l’Arduino si utilizzano chip con un minor numero di pin (come l’AT tiny85) o vi sia la necessità di risparmiare pin per altri utilizzi. Un caso tipico è l’uso di display LCD in cui non vi è la necessità di refresh real-time, magari in futuro potrei scrivere un articolo in merito visto che è una tecnica che non ho mai provato e potrebbe essere interessante compararla con le vie più classiche.

Ora che abbiamo visto la parte hardware dobbiamo passare a quella software che in realtà è davvero molto semplice.

const int latchPin = 12;  //Pin connected to latch pin (ST_CP) of 74HC595
const int clockPin = 11;  //Pin connected to clock pin (SH_CP) of 74HC595
const int dataPin = 13;   //Pin connected to Data in (DS) of 74HC595

void setup() {
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);  
  pinMode(clockPin, OUTPUT);
}

void loop()
{
 for (int i=0;i<8;i++) 
 {
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, 1<<i);
  digitalWrite(latchPin, HIGH);
  delay(90); 
 }
}

Con questo codice vedrete i led o comunque ciò che collegate alle uscite, aprirsi in sequenza: si accende il primo, si spegne e si accende il secondo, si spegne e accende il terzo e via discorrendo. Questo listato gestisce le prime 8 uscite, ma fate attenzione a questa cosa. Quando abbiamo inviato gli 8 bit che determinano quali uscite vanno accese o spente, tutte le celle di memoria sono occupate. A questo punto quando passiamo ad un nuovo ciclo ed inviamo un nuovo bit, l’ultimo presente nelle celle dello shif register passa a Q7′ e quindi, se vi sono shift register aggiuntivi collegati in cascata, andrà a finire nel secondo integrato. Di fatto quel che succede è che, inviando sempre il medesimo loop, i due shift register connessi insieme avranno le uscite disposte nella stessa maniera per cui si forma una sorta di copia. Il listato di sopra è molto semplice. Prima vengono definite tre costanti per memorizzare a quale pin abbiamo connesso il 74HC595, questo passo non è obbligatorio, ma ci permette di modificare in maniera semplice il listato se decidiamo di modificare l’hardware. Nel setup vengono impostati come uscite i tre pin necessari al collegamento. Poi si passa al loop principale in cui abbiamo inserito un ciclo for che determina l’accensione di un led alla volta. Vediamo che prima portiamo a LOW la linea latch, poi facciamo lo shift con l’apposita finzione shiftOut e poi riportiamo ad HIGH la linea latch per copiare i dati shiftati precedentemente nelle relative uscite. Ricordiamo che OE è sempre connesso a massa per cui non dobbiamo preoccuparcene da un punto di vista software. Per quanto riguarda l’istruzione shiftOut, vediamo che prende come parametri il pin ove inviare i dati seriali, il clock SH_CP e altri due parametri. Il primo dei due può essere impostato a MSBFIRST o a LSBFIRST, ossia indica se inviare il byte di dati a partire dal bit più significativo o dal meno significativo a seconda di come abbiamo fatto i collegamenti sull’hardware e come vogliamo utilizzare il software. L’ultimo parametro riguarda il byte da shiftare dentro il 74HC595. Ricordatevi che deve essere un valore compreso fra 0 (tutte le uscite spente) a 255 (tutte accese), utilizzando la logica binaria. 

Nell’esempio ho usato 1 < < i che è l’equivalente di 2 elevato alla i, quindi inizialmente abbiamo 2 alla 0 che vale 1 (solo prima uscita aperta), poi vale 2,4,8,16,32,64 e per finire 128. Se banalmente sommate questi valori, nel caso abbiate problemi con la matematica binaria, ottenete l’accensione delle relative uscite.
L’istruzione shiftOut invia solamente un byte alla volta per cui se ad esempio ne avete due, vi conviene mantere un array di caratteri con le diverse uscite ed inviarle in successione. Giusto per fare un esempio, prendiamo quello di sopra ed inviamo al secondo shift register la copia speculare del primo, in modo che il primo accenda le luci da sinistra a destra ed il secondo da destra a sinistra:

const int latchPin = 12;  //Pin connected to latch pin (ST_CP) of 74HC595
const int clockPin = 11;  //Pin connected to clock pin (SH_CP) of 74HC595	
const int dataPin = 13;   //Pin connected to Data in (DS) of 74HC595	 	
void setup() {	 	
  pinMode(latchPin, OUTPUT);	 	
  pinMode(dataPin, OUTPUT);  	 	 
  pinMode(clockPin, OUTPUT);	 	 
}	 	
void loop()	 	
{	 	
 for (int i=0;i<8;i++) 	 	
 {	 	
  digitalWrite(latchPin, LOW);	 	
  shiftOut(dataPin, clockPin, MSBFIRST, 1<<(7-i)); // oppure shiftOut(dataPin, clockPin, LSBFIRST, 1<<i);
  shiftOut(dataPin, clockPin, MSBFIRST, 1<<i);	  //  shiftOut(dataPin, clockPin, MSBFIRST, 1<<i);
  digitalWrite(latchPin, HIGH);	 	 
  delay(90); 	 	 
 }	 	
}
}

Come vedete la differenza rispetto a prima è minima è solo l’aggiunta della riga che invia i dati al secondo shift register. Dato che i dati scorrono dal primo al secondo, risulta ovvio che prima vanno inviati per primi i dati per il secondo e poi per il primo. Nell’immagine a lato vedete una foto del prototipo funzionante con ques’ultima versione del software. Nella parte bassa ci sono i due 74HC595, in quella più alta i relativi ULN280A. Più in alto ancora i led rossi connessi al polo positivo 12V con delle resistenze da 560 ohm. Visto così sembra un’inutile lampeggiatore per led, ma vi ricordo che i LED sono stati usati per praticità, lo scopo infatti è quello di applicare dei relè per carichi 220V/16A, alimentati a 12V. Spero che anche questo articolo vi sia gradito. Se avete domande scrivetemi pure, vi ricordo che occorre essere registrati ed il primo commento deve essere approvato, cosa che purtroppo sono stato obbligato ad introdurre a causa del massivo spam che finiva fra i commenti.

  4 Responses to “Arduino: collegare multipli relè 12V – it”

  1.  

    Bellissimo Post.

    Una domanda: io sto usando una scheda relè da 8 (http://www.sainsmart.com/8-channel-dc-5v-relay-module-for-arduino-pic-arm-dsp-avr-msp430-ttl-logic.html).

    E’ attivata mettendo a GND il pin desiderato.

    Al momento sto usando uno shift register come sopra solo che al posto di avere ULN2803 ho dei singoli transistor. Fin qui tutto bene. Quando faccio il test funziona tutto alla grande. Quando invece attacco il carico (ogni relè serve per attivare una tapparella da 200W – 220V 1A circa) e gioco un po attivando e disattivando il relè, magicamente si attivano dei relè che non ho comandato. Domanda:

    – può essere qualche induzione provocata dalla 220V ?
    – come posso risolvere?
    – questa scheda relè è attivata per LOW quindo posso usare uno ULN2803 lo stesso?

    Grazie

    •  

      l’ULN si lo puoi usare, le uscite sono a massa e non i positivi, per cui non hai problemi. Se però “senza carichi” non hai problemi, non dipende certo dal fatto che usi i transistor piuttosto che l’uln. Difficile darti una risposta certa, l’unica cosa sicura è che non dovresti avere questo tipo di problema :-). Hai messo il condensatore di disaccopiamento della linea di alimentazione dello shift register? Se la risposta è non aggiungilo. Altre cosa, come alimenti la “scheda relè”? Se prelevi direttamente da Arduino potrebbe essere che sei ai limiti (o oltre) le possibilità del regolatore di tensione il che si comincia a manifestare con problemi un po’ casuali….prova ad usare una fonte di alimentazione esterna che garantisca il massimo assorbimento quando tutti i relè sono chiusi……anche se in teoria non dovrebbe cambiare nulla con o senza carico esterno collegato.

    •  

      Ciao Simone,
      ho avuto qualche problema anche io con l’attivazione carichi induttivi sui relè.
      Ho risolto con qualche prova mettendo dei filtri RC in uscita ai contatti dei relè.
      Per carichi 24Vac ho messo un condensatore da 0,1uF in serie a una resistenza da 47ohm, mentre per carichi 220Vac condensatore 0,1uF e resistenza 100ohm. Fai attenzione al condensatore sulla 220Vac che regga la tensione (lo vedi sul lato) altrimenti scoppia.
      Se non hai problemi senza carichi dovrebbe funzionare.
      Ciao