Giu 282013
 

In un precedente articolo abbiamo visto come sia possibile usare il chip 74HC595 per espandere le uscite digitali di Arduino. Nel caso non sappiate cos’è e come funziona uno shift register vi consiglio di andarlo a rivedere prima di proseguire. Questo sarà un articolo complementare, vediamo infatti come sia altrettanto semplice espandere anche gli ingressi digitali in maniera molto simile a quanto visto in precedenza. Il concetto è del tutto analogo anche se ovviamente il tutto funziona in maniera speculare. Dalle uscite i valori verranno copiati nelle celle di memoria interne del 74HC165 e poi i vari dati verranno shiftati un bit alla volta verso una linea di ingresso. Toccherà al nostro Arduino catturare questi bit per comprendere qual’è l’originario stato degli ingressi. Qui a lato potete vedere il pinout del chip in questione, vediamoli brevemente:

  • GND: Come in ogni schema, gnd indica la massa (Ground).
  • Vcc: Pin di alimentazione, possiamo usare valori da 2 a 6 V.
  • A-H: I pin contrassegnati con le lettere dalla A alla H sono gli ingressi digitali che verranno letti.
  • SER:  è il pin usato per la connessione con chip dello stesso tipo collegati in serie per espandere ulteriormente il numero di ingressi.
  • QH: è il pin in cui i dati letti dagli ingressi vengono trasferiti verso Arduino.
  • QH*: Il QH con il trattino sopra presenta un segnale invertito rispetto QH, ossia se il primo è alto fornisce un valore basso e viceversa.
  • SH_LS (Shift-load): Quando viene portato allo stato basso, copia i dati delle uscite nelle celle di memoria per prepararsi all’invio verso Arduino.
  • CLK: come nel caso del 74HC595 viene usato un segnale di clock che, passando da alto a basso, determina lo shift dei dati.
  • CLK INH: se tenuto alto inibisce il segnale di clock, per cui deve essere messo ad un livello basso (è possibile collegarlo direttamente a massa).

Il funzionamento è molto semplice. Dapprima portiamo a basso il livello di SH/LD in modo che lo stato delle uscite venga copiato nelle celle di memoria dello shift register. A questo punto fornendo ripetuti abbassamenti del segnale su CLK otteniamo in sequenza i dati dei singoli bit sul pin QH. Da notare che con Arduino gran parte del lavoro viene svolto direttamente della funzione ShifIn, analoga alla ShiftOut che abbiamo studiato con il 74HC595. Qui sotto vi lascio lo schema di collegamento. Sulla parte sinistra al posto di Arduino ho messo un semplice connettore con massa, alimentazione ed i 3 pin per Clock, Dati seriali e SH/LD. Nel collegare un vero Arduino è sufficiente unire la massa ad un pin GND, la vcc ai 5V ed i restanti 3 pin a qualunque dei pin digitali di Arduino, sarà infatti poi possibile specificarli nel software.

Questo schema è stato predisposto per collegare dei pulsanti esterni ai connettori che ho messo sulla destra. Come vedete i poli negativi sono connessi a massa attraverso un resistore da 10K. Faccio notare che anche CLK_INH è connesso direttamente a massa. In rete alcuni utilizzano anche su questo pin un resistore da 10k interposta, io sinceramente non l’ho utilizzata. Ho fatto dei test con l’oscilloscopio sul prototipo in breadboard e non ho notato variazioni con o senza l’uso del resistore, ma farò delle verifiche sul circuito finale non appena avrò i PCB pronti.

Il listato è estremamente semplice:

const int IN_PL = 9;  //azzurro
const int IN_Data=10; // verde
const int IN_Clock=8; // marrone

int attuale=0;
int lettura=0;

void setup()
{
  pinMode(IN_PL,OUTPUT);
  pinMode(IN_Data,INPUT);
  pinMode(IN_Clock,OUTPUT);
  Serial.begin(9600);
}

void loop()
{
  delay(50);
  digitalWrite(IN_Clock, HIGH);
  digitalWrite(IN_PL, LOW);
  digitalWrite(IN_PL, HIGH);
  lettura=shiftIn(IN_Data, IN_Clock, MSBFIRST );
  if(attuale!=lettura)
  {
    attuale=lettura;
    Serial.println (lettura);
  } 
}

Nelle prime righe del listato vengono definite le costanti per i tre pin di connessione ad Arduino, ossia il SH/LD (PL), Dati e clock. Attenzione, nel setup, che la linea di dati in ingresso sarà di tipo INPUT a differenza delle altre due che sono di tipo OUTPUT.  Nell’esempio ho usato la porta seriale per scrivere a terminale il valore letto dagli ingressi, si ricordi che è una cifra compresa fra 0 e 255 in base a quali ingressi sono attivati al momento della lettura (logica binaria). Il loop comincia con un delay(50) che ha la semplice funzione di rudimentale sistema antirimbalzo. Questo valore può essere ridotto per rendere il sistema ancor più reattivo ma ricordate che valori troppo bassi possono genererare repentine letture contrastanti durante la pressione di un pulsante. Subito dopo troviamo il motivo per cui l’articolo è una seconda revisione. Grazie ad una segnalazione di Daniele che ringrazio tantissimo per l’intenso scambio di mail e di Angelo, che mi ha fatto notare il medesimo problema solo poche ore prima della correzione di questo articolo, troviamo l’istruzione digitalWrite(IN_Clock, HIGH); che porta ad HIGH la linea di clock. Questo passaggio è fondamentale in quanto la sua assenza determina uno shift dei dati durante la successiva fase di copia dei dati degli ingressi nelle relative celle di memoria dello shift register il che comporta una corrispondenza sfalsata fra il pin che viene attivato e ciò che Arduino realmente legge e a cui si aggiunge la perdita di informazioni da parte del primo pin. Successivamente, per quanto riguarda la lettura degli ingressi, si noti l’utilizzo della digitalWrite con valore prima LOW e subito dopo HIGH sul pin SH/LD, cosa che determina la copia dello stato degli ingressi nelle celle di memoria. Poi, a differenza di gran parte dei tutorial che troverete in rete, viene usata la funzione shiftIn per leggere tutti gli 8 ingressi e trasferirli in un byte di nome “lettura”.

Se questo è diverso dal valore precedentemente memorizzato (variabile “attuale”) viene inviato il valore attraverso il monitor seriale, altrimenti non viene eseguita nessuna operazione in quanto non vi sono state pressioni o rilasci di pulsanti.Visto che nella precedente revisione dell’articolo sono stato un po’ frettoloso nel descrivere l’utilizzo di più shift register in cascata, vediamo di dedicare qualche riga in più a questo argomento. Per collegare un secondo shift register dovete usare la line SER (pin 10) del primo shift register e collegarla al pin QH del secondo e così a cascata. Il software resta quasi identico, basterà aggiungere una chiamata alla funzione shiftIn per ogni chip aggiuntivo collegato. Visto che ho creato un nuovo prototipo con 48 ingressi e quindi 6 shift register in cascata, vi riporto non solo la foto che potete vedere qui vicino, ma anche il nuovo listato che permette di tenere sotto controllo lo stato di tutti gli ingressi di tutti gli shift registers. Se ne avete di meno o di più rispetto ai miei 6, non dovete far altro che modificare la prima linea di codice.

#define NUM_CHIP 6

const int IN_PL = 9;
const int IN_Data=10;
const int IN_Clock=8;


int attuale[NUM_CHIP]; // array per tenere le letture attuali
int lettura[NUM_CHIP]; // array per tenere l'ultima lettura fatta.

void setup()
{
  pinMode(IN_PL,OUTPUT);
  pinMode(IN_Data,INPUT);
  pinMode(IN_Clock,OUTPUT);
  for(int i=0;i<NUM_CHIP;i++) {attuale[i]=0;lettura[i]=0;} // inizializzo gli array a 0
  Serial.begin(9600);
}

void loop()
{
  delay(50);
  digitalWrite(IN_Clock, HIGH);
  digitalWrite(IN_PL, LOW);
  //delayMicroseconds(5);
  digitalWrite(IN_PL, HIGH);
  for(int i=0;i<NUM_CHIP;i++) lettura[i]=shiftIn(IN_Data, IN_Clock, MSBFIRST ); // faccio tutte le letture
 
  for(int i=0;i<NUM_CHIP;i++) // controllo se ci sono modificazioni
  {
  
   if(attuale[i]!=lettura[i])
   {
    attuale[i]=lettura[i];
    Serial.print("IC ");
    Serial.print(i);
    Serial.print(" - ");
    Serial.println (lettura[i]);
   }
  } // chiusura for
}

C’è un ultimo problema che vorrei segnalarvi. Ho scoperto che alcuni utenti hanno avuto dei problemi di “letture continue” ossia di continue variazioni degli ingressi anche in assenza di reali variazioni. Sembra che più di qualcuno abbia risolto il problema collegando alle linee seriali (SER e QH) un resistore verso massa da 1k. Io non sono riuscito a riprodurre il problema. La mia opinione è che in questi casi ci sia del rumore elettronico che interferisce sulle linee seriali al punto da far passare lo stato logico da 0 a 1 ed il resistore permette di ridurre questo rumore rendendo il funzionamento più stabile. La mia idea è che vada ricercata la causa di questo rumore più che metterci una pezza a priori, però non essendo riuscito a riprodurre il problema non ho nessun modo per aiutarvi ulteriormente. Vi faccio notare un’altra cosa importante. Nello schema iniziale è data per scontata una cosa che forse, alle prime armi, così scontata non è. In tutti gli integrati deve essere usato un cosidetto condensatore di disaccopiamento che nella stragrande maggioranza dei casi può essere da 100nF (0.1μF). Questo deve essere posizionato fisicamente il più vicino possibile al pin di alimentazione, per cui, nel nostro schema, fra i pin 15 e 16. La sua funzione è quella di limitare le fluttuazioni sulla linea di alimentazione a causa degli improvvisi assorbimenti dell’integrato stesso durante le varie fasi di funzionamento. Ad esempio con il 74HC595 senza condensatore  mi trovavo qualche sporadico errore che però, vista la connessione con un display LCD, mi deteriorava la leggibilità dello schermo. Vi consiglio di metterli sempre, anche se vi sembra che il circuito funzioni correttamente senza.

  2 Responses to “74HC165: come espandere gli ingressi digitali di Arduino. REV2 – it”

  1.  

    vorrei sapere quando supporta il serial input in lunghezza massima. 30 metri li regge?

    grazie

  2.  

    Ciao, scusa il ritardo ma sai com’è, è fine anno anche per me. Se la tua intenzione è quella di mettere due shift register a 30metri di distanza uno dall’altro o da Arduino, beh, lascia perdere magari hai la fortuna che funzioni, ma non posso certo consigliartelo. Non dovrebbero esserci. Invece problemi con gli ingressi, comunque proverò questa cosa a casa mia visto che devo leggere gli ingressi dei pulsanti a muro di un piano della casa e ti faccio sapere.