Espansione I/O con il Microchip MCP23017: guida completa e applicazioni pratiche

Sperimentiamo con il popolare I/O expander della Microchip, attraverso una scheda applicabile anche su breadboard, interfacciabile con Arduino.

Esistono varie situazioni pratiche in cui occorre gestire numerosi segnali e attuatori con un microcontrollore, che perรฒ non ha sufficienti pin di I/O; in tali situazioni รจ utile ricorrere a quegli integrati noti come I/O expander, la cui funzione รจ serializzare un certo numero di linee di input e output cosรฌ da controllarle tramite un solo I/O, ovvero una linea di comunicazione seriale come puรฒ essere la comune e diffusissima IยฒC-Bus, presente in molti microcontrollori e, non ultime, nelle schede Arduino.

Per rispondere allโ€™esigenza di moltiplicare (espandere, appunto, come dice il termine โ€œexpanderโ€…) le linee di I/O, abbiamo realizzato la breakout board basata su MCP23017, che proponiamo in questo articolo, sulla quale troviamo tale integrato Microchip che รจ appunto un I/O expander a 16 bit, oltre allโ€™hardware minimo per farlo funzionare, che nel caso specifico consiste in un dip-switch e qualche resistore di pull-up.

Ciรฒ diventerร  piรน chiaro guardando lo schema elettrico della scheda, che trovate in queste pagine.

Infine, per darvi unโ€™idea di cosa si puรฒ realizzare con un I/O expander, vi proporremo un esempio applicativo dove la breakout board pilota una serie relรฉ (otto in tutto) montati su una scheda pilotabile tramite livelli TTL o la pressione di pulsanti.

Ma andiamo con ordine ed analizziamo lo schema circuitale.

Schema elettrico dell’I/O expander

Come potete vedere, la breakout board รจ qualcosa di estremamente essenziale, perchรฉ a bordo vi troviamo lโ€™integrato MCP23017 in versione DIP (a montaggio tradizionale) con riportati sulle piazzole laterali, che sul PCB sono a passo 2,54 mm in previsione del montaggio di pin-strip per lโ€™inserzione in altre schede o su breadboard, tutti i piedini ad eccezione dei tre per lโ€™impostazione dei bit meno significativi dellโ€™indirizzo IยฒC-Bus di periferica.

Pertanto รจ stato previsto un dip-switch a 3 vie (siglato SW1 nello schema elettrico) per impostare lโ€™indirizzo di comunicazione sullโ€™IยฒC-Bus, i cui piedini A0, A1, A2, sono provvisti di resistori di pull-up che a dip-switch aperti li mantengono a livello logico alto.

Riepilogando, tutti i pin relativi agli I/O dei registri A e B sono stati portati in esterno su pin strip maschi. Questi pin sono stati disposti su entrambi i lati per poter connettere la nostra scheda con facilitร , ad esempio alla scheda relรฉ cod. RELAY8CH della Futura Elettronica, ma ovviamente sono pin I/O digitali, pertanto si puรฒ collegare tutto ciรฒ che si vuole, nei limiti della corrente e tensione supportati dallโ€™integrato MCP23017.

Oltre ai pin strip laterali a passo 2,54 mm, che permettono di ospitare il modulo anche in una breadboard, sono stati previsti altri 4 pin su uno strip (sempre a passo 2,54 mm) chiamato I2C, per poter collegare al bus direttamente nella parte superiore del modulo. Resta inteso che i soli pin laterali sono sufficienti per tutta la comunicazione e interfacciamento con il modulo, pertanto i quattro pin del connettore I2C sono posti in parallelo a quelli giร  esistenti sulla scheda.

Notate che sul circuito stampato, per praticitร  i pin del registro A sono stati riportati su un lato e quelli del B si trovano sul lato opposto, sempre nellโ€™ottica di semplificare le connessioni.

I piedini facenti capo al bus IยฒC sono stati riportati sul pin-strip siglato I2C, insieme al positivo 5V e alla massa; entrambi sono provvisti di pull-up.

Il reset dellโ€™I/O-expander nella nostra breakout board non รจ utilizzato, quindi per disattivarlo abbiamo posto il relativo piedino (il 18, RSTโ€ฆ) a livello logico alto mediante il resistore R4.

Tra i pin laterali della scheda troviamo anche ripetute le linee GND e +5V.

Lโ€™elemento principale del circuito รจ chiaramente lโ€™MCP23017, che possiamo considerare un convertitore IยฒC-Bus/parallelo, prodotto dalla Microchip (siglato U1); lโ€™integrato, del quale vedete lo schema a blocchi interno in Fig. 1, funziona come periferica (Slave) del bus IยฒC e supporta le due modalitร  di input e output.

Nella prima permette di trasferire sul bus, su richiesta del dispositivo Master IยฒC-Bus, gli stati degli I/O del registro A e del B in formato seriale, un byte per ciascun registro; nella seconda, invece, va ad impostare le linee di I/O convertendo i dati in arrivo sul bus IยฒC nello stato corrispondente delle linee dei registri A e B.

Fig. 1 Schema a blocchi dellโ€™MCP23017: รจ riportata anche la variante SPI che contraddistingue lโ€™MCP23S17

 

Lโ€™integrato MCP23017 fornisce unโ€™espansione I/O seriale/parallela generica a 16 bit ed รจ disponibile in due versioni: quella qui utilizzata, dotata di interfaccia IยฒC-Bus e la MCP23S17, variante ad interfaccia SPI.

Il chip รจ un I/O-expander a 16 bit, ripartiti in due porte da 8 bit ciascuna, interfacciato mediante IยฒC-Bus; questo significa che con due soli fili, riferiti a massa, consente di acquisire lo stato di ben 16 linee (modalitร  input) ovvero impostare lo stato logico di esse (modalitร  output).

Le linee di I/O sono, per impostazione predefinita, funzionanti come input.

Lโ€™MCP23017 รจ costituito da piรน registri in configurazione a 8 bit per ingresso, uscita e selezione della polaritร . Il master di sistema puรฒ abilitare gli I/O come ingressi o uscite scrivendo i bit di configurazione I/O (IODIRA/B) corrispondenti.

I dati per ogni ingresso o uscita sono conservati nel corrispondente registro di ingresso o di uscita.

La polaritร  di registro Input Port puรฒ essere invertita mediante il Polarity Inversion Register.

Tutti i registri possono essere letti dal master di sistema.

La porta I/O a 16 bit รจ funzionalmente composta da due porte a 8 bit, ossia port A e port B, cui fanno capi i piedini, rispettivamente 21รท28 e 1รท8.

Lโ€™MCP23X17 puรฒ essere configurato per funzionare nelle modalitร  a 8 bit o 16 bit; dispone inoltre dei due pin di interrupt, INTA e INTB, che possono essere associati alle rispettive porte (INTA per il Port A e INTB per Port B9 o possono essere assoggettati allโ€™operazione logica OR in modo che entrambi i pin si attivino se entrambe le porte determinano un interrupt.

Lโ€™uscita di interrupt puรฒ essere configurata per lโ€™attivazione in due condizioni (che si escludono a vicenda):
โ€ข quando uno stato di input รจ diverso dal suo corrispondente stato del registro della porta di ingresso; questa condizione รจ utilizzata per indicare al master di sistema che un stato di ingresso รจ cambiato;
โ€ข quando lo stato di un ingresso รจ diverso dal valore preconfigurato del registro (registro DEFVAL).

Le linee di interrupt INTA e INTB possono essere configurate come active-high, active-low oppure open-drain. Il registro Interrupt Capture acquisisce i valori delle porte nel momento in cui si attiva lโ€™interrupt, memorizzando cosรฌ la condizione che ha causato lโ€™interrupt.

Il Power-on Reset (POR) imposta i registri sui loro valori predefiniti e inizializza la macchina a stati del dispositivo.

La necessitร  di funzionare in modalitร  bidirezionale si deve al fatto che ogni periferica IยฒC-Bus deve sia poter leggere (per esempio i comandi) sia poter inviare i dati acquisiti, ad 8+8 bit, lungo il bus.

Come tutte le unitร  per IยฒC-Bus, lโ€™MCP23017 permette di impostarne lโ€™indirizzo in un range di 8 indirizzi ed allo scopo dispone dei pin A0, A1, A2, i quali consentono di impostare gli address dellโ€™unitร  Slave, se indirizzata direttamente dal Bus IยฒC; queste linee si impostano ciascuna mediante un interruttore del dip-switch SW1, per facilitare lโ€™impostazione del caso: ogni dip chiuso imposta lo zero logico sul rispettivo address, mentre, viceversa, un dip aperto determina lo stato logico 1.

La possibilitร  di definire otto indirizzi consente di affacciare fino a otto I/O-expander sullo stesso bus e controllare quindi un massimo di 128 I/O con tre sole linee.

Lโ€™intero circuito prende alimentazione dal contatto 5V (in realtร  abbiamo due contatti: 1 e 15, disposti sui lati lunghi della breakout board) riferita a massa (contatti GND, ossia 2 e 23 delle file laterali).

Con questo hardware, il funzionamento รจ il seguente: ogni volta che riceve una stringa lungo la linea SDA dellโ€™IยฒC-Bus (scandita dal segnale di clock sulla linea SCL) lโ€™integrato MCP23017 esegue il comando ivi contenuto (in questo caso quello che indica di caricare il byte di dati) e dispone le 8 linee di uscita IOA0รทIOA7 e IOB0รทIOB7 come i relativi bit, ovvero IOA0 assumerร  lo stato del primo bit del byte 1, IOA1 quello del secondo e via di seguito.

Analogamente avverrร  su IOB0รทIOB7, che rispecchieranno pari-pari i bit del secondo byte dati.

Naturalmente la conversione e presentazione sulle uscite avviene solo a condizione che la stringa ricevuta contenga lโ€™indirizzo IยฒC-Bus corrispondente a quello impostato, mediante i dip-switch dellโ€™SW1, per lโ€™U1. Alla ricezione di ogni stringa lโ€™integrato aggiorna lo stato delle proprie uscite e i rispettivi livelli logici determinano lโ€™accensione (o la permanenza nello stato di riposo) dei LED componenti i segmenti del display; se non viene inviata alcuna stringa successivamente, il display mantiene il numero visualizzato, perchรฉ le uscite dellโ€™integrato MCP23017 sono dotate di latch.

Quanto esposto vale per la modalitร  output, ossia in scrittura dello stato dei due byte IยฒC-Bus sui registri di uscita A e B; se invece il comando proveniente dal bus รจ di lettura, lโ€™MCP23017 acquisisce lo stato degli I/O di ciascun registro e genera due byte, contenenti il primo lo stato di IOA0รทIOA7 e il secondo la condizione logica di IOB0รทIOB7, quindi li invia lungo il bus IยฒC come risposta.

Per ogni applicazione cui vorrete destinare la breakout board, nella Tabella 1, vi riportiamo la corrispondenza tra gli address e lโ€™impostazione dei dip-switch.

 

Tabella 1 Impostazione dellโ€™indirizzo di periferica dellโ€™MCP23017

Piano di montaggio dell’espansione

Elenco Componenti:

R1, R2, R3, R4, R5, R6: 4,7 kohm
C1: 100 nF ceramico
SW1: Dip-switch 3 vie
U1: MCP23017-E/SP

Varie:
- Zoccolo 14+14
- Pin strip Maschio 12 vie (2 pz.)
- Pin strip Maschio 4 vie (1 pz.)
- Circuito stampato S1650 (61x23 mm)

Utilizziamo l’I/O espander con MCP23017 con Arduino

La breakout board nasce per essere interfacciata a un microcontrollore, giacchรฉ tipicamente gli I/O-expander vengono utilizzati da dispositivi provvisti di interfaccia seriale a IยฒC-Bus; siccome Arduino supporta questo bus, abbiamo realizzato un esempio di codice per leggere gestire gli I/O dellโ€™MCP23017 tramite Arduino.

Rendiamo disponibile il codice di esempio nella pagina dell’I/O expander (FT1650) affinchรฉ possiate scaricarlo e scriverlo nella vostra scheda tramite lโ€™IDE.

Questo sketch sostanzialmente consente di scrivere lo stato del registro Port A in funzione di un byte inviato da Arduino lungo il bus, i cui bit corrispondono allo stato letto sul Port B, che stavolta funziona da ingresso.

Per dare allโ€™esempio unโ€™applicazione concreta, abbiamo deciso di utilizzare gli stati logici degli I/O del Port A, che qui opereranno come uscite digitali, per pilotare una scheda a relรฉ; nello specifico, bisogna collegare le 8 linee di comando delle uscite a relรฉ della scheda RELAY8CH della Futura Elettronic al banco I/O del Port A, mentre al Port B sono da collegare 8 pulsanti normalmente aperti, aventi in comune il polo collegato a GND.

Per realizzare questa applicazione occorre collegare Arduino UNO, la breakout board, la scheda relรฉ e i pulsanti, come mostrato nello schema di cablaggio proposto in Fig. 2.

 

Fig. 2 Schema di cablaggio della applicazione di controllo relรฉ tramite pulsanti

 

Trattandosi di normalissimi pulsanti (nello specifico, normalmente aperti) e non avendo elettronica esterna, sono state abilitate le pull-up interne dellโ€™MCP (mediante libreria) in modo da gestirli e riconoscere il cambiamento di stato, in questo modo abbiamo attivato lโ€™uscita rispettiva quando il pulsante viene portato a massa (GND).

Per realizzare tutto ciรฒ, รจ stato scritto un codice molto semplice basato su Arduino UNO, sfruttando la libreria Adafruit, la quale, come vedete nel Listato 1, viene inclusa nella prima riga dello sketch con lโ€™istruzione:

Listato 1

#include <Adafruit_MCP23X17.h>

Adafruit_MCP23X17 mcp;

int i = 0;

int OUT[] = {
  7,
  6,
  5,
  4,
  3,
  2,
  1,
  0
}; //Rappresenta il PIN dellโ€™MCP23017 (A7...A0)
int IN[] = {
  8,
  9,
  10,
  11,
  12,
  13,
  14,
  15
}; //Rappresenta il PIN dellโ€™MCP23017 (B0...B7)
int STATO[] = {
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0
}; //Per ogni uscita viene salvato lo stato ad ogni commutazione

void setup() {
  Serial.begin(9600);
  Serial.println(โ€œMCP23017 INPUT / OUTPUTโ€);

  if (!mcp.begin_I2C(0x20)) //0x20 รจ lโ€™indirizzo dellโ€™MCP23017 con A0=A1=A2 > ON(GND)
  {
    Serial.println(โ€œMCP Errore!โ€); //Se lโ€™MCP non viene trovato si visualizza lโ€™errore
    while (1);
  }
  //Pin del banco A come uscite e del banco B come ingressi
  //La variabile STATO a 0 ad indicare uscite a riposo
  for (i = 0; i & lt; 8; i = i + 1) {
    mcp.pinMode(OUT[i], OUTPUT);
    mcp.pinMode(IN[i], INPUT_PULLUP);
    STATO[i] = 0;
  }
}

//******************* L O O P **********************
void loop() {
  String Testo_Debug = โ€œโ€;
  for (i = 0; i & lt; 8; i = i + 1) {
    //Se pulsante premuto o uscita non attivata, la attivo
    if ((mcp.digitalRead(IN[i]) == 0) & amp; & amp;
      (STATO[i] == 0)) {
      STATO[i] = 1;
      Testo_Debug = โ€œPulsanteโ€œ + String(i + 1) + โ€œpremutoโ€;
      Serial.println(Testo_Debug);
      mcp.digitalWrite(OUT[i], HIGH);
    }
    //Se pulsante rilasciato e uscita attivata, la porto a riposo
    if ((mcp.digitalRead(IN[i]) == 1) & amp; & amp;
      (STATO[i] == 1)) {
      STATO[i] = 0;
      Testo_Debug = โ€œPulsanteโ€œ + String(i + 1) + โ€œrilasciatoโ€;
      Serial.println(Testo_Debug);
      mcp.digitalWrite(OUT[i], LOW);
    }
  }
  delay(10);
}

 

Resta inteso che prima di poter caricare il codice nella memoria di programma della nostra Arduino รจ indispensabile scaricare la libreria dal sito www.adafruit.com e installarla mediante il Gestore delle librerie incluso nellโ€™IDE, o semplicemente estrarre il contenuto del file ZIP e copiare quindi lโ€™intera cartella โ€œAdafruit_MCP23017_Arduino_Libraryโ€ allโ€™interno della directory โ€œlibrariesโ€ normalmente presente allโ€™interno del sistema operativo al percorso โ€œDocumenti\Arduino\librariesโ€.

Caricata la libreria, sarร  sufficiente caricare il nostro codice di esempio e caricarlo allโ€™interno della scheda dopo aver scelto la corretta porta COM dal menu โ€œStrumentiโ€ dellโ€™IDE.

Nel codice viene richiesto lโ€™invio di un byte allโ€™MCP23017, contenente lo stato dei pulsanti e i relativi dati vengono elaborati e quindi scritti su un byte diretto allโ€™integrato, che imposterร  lo stato delle linee del Port A in maniera stabile, fino al refresh.

Affinchรฉ lโ€™interfacciamento funzioni รจ necessario impostare correttamente i dip-switch A0, A1 e A2 perchรฉ se al sensore non venisse assegnato lโ€™indirizzo 0x20, verrebbe mostrato un messaggio di errore sulla seriale; lโ€™address della breakout board si assegna con la combinazione 000 dei tre bit A0, A1, A2, quindi chiudendo a massa tutti e tre i dip-switch.

Se volete modificare lโ€™indirizzo riferitevi alla solita Tabella 1, fermo restando che dovrete modificare lโ€™address scritto nello sketch.

Lascia un commento

Il tuo indirizzo email non sarร  pubblicato. I campi obbligatori sono contrassegnati *

Menu