Arduino e Digital and Analog IO Expander Shield

Ciao a tutti ragazzi, ho appena comprato una shield Digital And Analog IO Expander per Arduino (Low cost Digital and Analog IO Expander Shield | Numato Lab). Come faccio a pilotare un determinato pin? Vanno gestiti con i byte? Dal codice di esempio si riescono ad eccendere e spegnere tutti insieme ma io vorrei gestirli in maniera indipendente, grazie a tutti.

Vi posto il codice di esempio.

/*
 *  There are two on board MCP23017(U2 and U4) IO Expander ICs on this Shield
 *  Select jumper positions of AD1=AD2=AD3=0, to set the Address of U2 as 0x20
 *  Select jumper positions of AD4=0; AD5=0; AD6=1, to set the Address of U4 as 0x21
 *  Digital Pins 0 - 7 belongs to PORTA and 8 - 15 belongs to PORTB of U2
 *  Digital Pins 24 - 27 belongs to PORTA and 16 - 23 belongs to PORTB of U4
 */
 
#include "Wire.h"

void setup()
{
   Wire.begin();                                  // Begin I2C bus
   /* 
    *  The following code starts I2C communication with MCP23017(U2).Please refer MCP23017 datasheet
    *  for register addresses. Sets all GPIOs of this IC to OUTPUT 
    */
   Wire.beginTransmission(0x20);                  // Starts communication with MCP23017(U2) IC
   Wire.write(0x00);                              // Set MCP23017 memory pointer to IODIRA address
   Wire.write(0x00);                              // Set all pins of PORTA to outputs
   Wire.endTransmission();                        // Ends I2C communication with MCP23017(U2) IC

   Wire.beginTransmission(0x20);                  // Starts communication with MCP23017(U2) IC
   Wire.write(0x01);                              // Set MCP23017 memory pointer to IODIRB address
   Wire.write(0x00);                              // Set all pins of PORTB to outputs
   Wire.endTransmission();                        // Ends I2C communication with MCP23017(U2) IC
   /* 
    *  The following code starts I2C communication with MCP23017(U4).Please refer MCP23017 datasheet
    *  for register addresses. Sets all GPIOs of this IC to OUTPUT 
   */ 
   Wire.beginTransmission(0x21);                  // Starts communication with MCP23017(U4) IC
   Wire.write(0x00);                              // Set MCP23017 memory pointer to IODIRA address
   Wire.write(0x00);                              // Set all PORTA pins to OUTPUT
   Wire.endTransmission();                        // Ends I2C communication with MCP23017(U4) IC

   Wire.beginTransmission(0x21);                  // Starts communication with MCP23017(U4) IC
   Wire.write(0x01);                              // Set MCP23017 memory pointer to IODIRB address
   Wire.write(0x00);                              // Set all PORTB pins to OUTPUT
   Wire.endTransmission();                        // Ends I2C communication with MCP23017(U4) IC
}

void DigitalIO(int i)
{
   Wire.beginTransmission(0x20);
   Wire.write(0x12);                             
   Wire.write(i);                                 // Set or clear PORTA pins of U2
   Wire.endTransmission();
   
   Wire.beginTransmission(0x20);
   Wire.write(0x13);                              
   Wire.write(i);                                 // Set or clear PORTB pins of U2
   Wire.endTransmission();
    
   Wire.beginTransmission(0x21);
   Wire.write(0x12);                              
   Wire.write(i);                                 // Set or clear PORTA pins of U4
   Wire.endTransmission();
    
   Wire.beginTransmission(0x21);
   Wire.write(0x13);                              
   Wire.write(i);                                 // Set or clear PORTB pins of U4
   Wire.endTransmission();
}

void loop()
{
   DigitalIO(255);                                // All digital pins High
   delay(2500);
   DigitalIO(0);                                  // All digital pins Low
   delay(2500);
}

Bella schifezza di sito che hanno questi della numato.

Qui c’e’ un manuale che non dice nulla sul codice e mette un link a codice di esempio che porta a una pagina vuota.
Sul manuale dice " Each pin can individually be controlled by accessing the specific port register. Please refer to MCP23017 data-sheet for register addresses and more details."

Hai un link funzionante alla libreria/codici di esempi ?

— piccolo intervento di moderazione sui termini usati … mi raccomando :wink: - gpb01

Infatti non ci ho capito niente!
Io ho scaricato da qui:

Grazie

visto che non sei pratico, perchè non usi una libreria che semplifica la gestione
ad esempio quella di Adafruit link

Non mi sembra un venditore cosí male. L' unica cosa che manca é un sketch di esempio. Nel manuale ci sono sia spiegazione che schema elettrico.

Per l' uso dei MCP23017 basta una libreria del MCP23017 e per il 4067 basta mandare un indirizzo del pin a 4 bit.

Ciao Uwe

netrising86:
Come faccio a pilotare un determinato pin? Vanno gestiti con i byte?

Secondo me si, quello che mandi viene scritto in un registro ed ogni bit di quel registro pilota il singolo pin.
P.S. scusate il linguaggio di prima

Mi potete scrivere un pezzo di esempio su come poter fare ad usare un paio di Pin per favore?

netrising86:
Mi potete scrivere un pezzo di esempio su come poter fare ad usare un paio di Pin per favore?

Puoi usare una variabile byte, quindi 8 bit, e usando la bitWrite() metti a 1 solo alcuni bit/pin. Poi spari il byte ad uno dei chip della shield con wire.
Prova ad aggiungere questo dopo la ultima delay(2500); del loop

byte bReg=0;
bitWrite(bReg,2,1); // bit 2 a 1
bitWrite(bReg,5,1); // bit 5 a 1
Wire.beginTransmission(0x21);
Wire.write(0x12);                              
Wire.write(bReg);                                 // Set or clear PORTA pins of U4
Wire.endTransmission();
delay(2000);

Io concordo col suggerimento di Brunello, di usare la libreria di Adafruit per l'MCP, funziona benissimo!

SukkoPera:
Io concordo col suggerimento di Brunello, di usare la libreria di Adafruit per l'MCP, funziona benissimo!

Mi pare che la shield ha due MCP, quindi bisogna creare due oggetti ed inizializzare la loro begin con indirizzo I2C giusto:

Adafruit_MCP23017 mcp1,mcp2;
...
void setup()
{ mcp1.begin(0x20);
  mcp1.begin(0x21);

Corretto. Bisogna anche trovare gli indirizzi dei due MCP (con l’i2c scanner) e quindi passarglieli:

mcp1.begin (addr1);
mcp2.begin (addr2);

Quindi il codice definitivo dev’essere così?

/*
 *  There are two on board MCP23017(U2 and U4) IO Expander ICs on this Shield
 *  Select jumper positions of AD1=AD2=AD3=0, to set the Address of U2 as 0x20
 *  Select jumper positions of AD4=0; AD5=0; AD6=1, to set the Address of U4 as 0x21
 *  Digital Pins 0 - 7 belongs to PORTA and 8 - 15 belongs to PORTB of U2
 *  Digital Pins 24 - 27 belongs to PORTA and 16 - 23 belongs to PORTB of U4
 */

#include "Adafruit_MCP23017.h" 
#include "Wire.h"

Adafruit_MCP23017 mcp1,mcp2;

void setup()
{
   Wire.begin();                                  // Begin I2C bus
   /* 
    *  The following code starts I2C communication with MCP23017(U2).Please refer MCP23017 datasheet
    *  for register addresses. Sets all GPIOs of this IC to OUTPUT 
    */
   Wire.beginTransmission(0x20);                  // Starts communication with MCP23017(U2) IC
   Wire.write(0x00);                              // Set MCP23017 memory pointer to IODIRA address
   Wire.write(0x00);                              // Set all pins of PORTA to outputs
   Wire.endTransmission();                        // Ends I2C communication with MCP23017(U2) IC

   
   mcp1.begin(0x20);
   mcp1.begin(0x21);

}

void DigitalIO(int i)
{
   Wire.beginTransmission(0x20);
   Wire.write(0x12);                             
   Wire.write(i);                                 // Set or clear PORTA pins of U2
   Wire.endTransmission();
}

void loop()
{
   DigitalIO(255);                                // All digital pins High
   delay(3000);
   DigitalIO(0);                                  // All digital pins Low
   delay(3000);
   byte bReg=0;
    bitWrite(bReg,2,1); // bit 2 a 1
    bitWrite(bReg,5,1); // bit 5 a 1
    Wire.beginTransmission(0x21);
    Wire.write(0x12);                              
    Wire.write(bReg);                                 // Set or clear PORTA pins of U4
    Wire.endTransmission();
    delay(2000);

    
}

Erm, no.

Prima di tutto devi trovare gli indirizzi i2c dei due MCP. Per fare ciò carica lo scanner che trovi qua: Gammon Forum : Electronics : Microprocessors : I2C - Two-Wire Peripheral Interface - for Arduino

A quel punto devi decidere se vuoi usare la libreria o no. Io ti consiglio ora ancora più vivamente di farlo, visto che - senza offesa - non mi sembri troppo disinvolto :).

A quel punto come codice basta:

#include "Adafruit_MCP23017.h" 

Adafruit_MCP23017 mcp1,mcp2;

void setup()
{
   mcp1.begin(0x20);
   mcp2.begin(0x21);

}

dove al posto di 0x20 e 0x21 devi mettere gli indirizzi ricavati prima. Oppure prova direttamente con quelli, se li hai presi da una fonte affidabile.

Ti rimane poi da capire quale pin degli MCP corrisponde a quale pin fisico, ma per quello ti conviene armarti di un led e di un bel po' di pazienza, accendere un pin alla volta, e così via...

Credo di aver capito, ora faccio qualche prova e poi vi scrivo.
Non so davvero come ringraziarvi, grazie davvero!

Gli address che ho scritto li ho presi dall'esempio che ha postato @netrising e che funziona sulla sua shield (anche se lavora su tutti i pin in un colpo solo), quindi dovrebbero essere 0x20 e 0x21. Verifica però.

Ho dichiarato un array per i 16 pin del primo MCP in questo modo e funziona benissimo:

byte mcpPin[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};

Come faccio però ad inserire all’interno dello stesso array anche i pin diretti di Arduino, ad esempio il 2, 3, 4, 5 ecc. in modo da usare un unico array nelle varie funzioni?

Quell’array è completamente inutile, avendo valori uguale all’indice che usi per accederci. Usa direttamente l’indice e fai prima.

In ogni caso non puoi fare quello che vorresti, perché i pin di Arduino li comandi con digitalWrite(), mentre quelli dell’MCP con mcp1.digitalWrite () (o, ovviamente mcp2…). Meglio usare una sorta di funzione wrapper che implementa un qualche criterio per numerare i pin, tipo:

void myDigitalWrite (byte pin, int w) {
  if (pin < 14) {
    // Pin di Arduino
    digitalWrite (pin, w);
  } else if (pin < 30) {
    // Pin sul primo MCP
    mcp1.digitalWrite (pin - 14, w);
  } else if (pin < 46) {
    // Pin sul secondo MCP
    mcp2.digitalWrite (pin - 30, w);
  }
}

Fatto un po’ a caso, ma dovrebbe rendere l’idea :D.

Visto che come dici giustamente non sono proprio disinvolto :slight_smile:
Ho dichiarato così in alto:

byte mcpPin1[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
byte mcpPin2[6] = {16, 17, 18, 19, 20, 21};
byte mcpPinInputs[6] = {22, 23, 24, 25, 26, 27};
int inputs[16] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, A0, A1, A2, A3};

In pratica mi servono i 16 pin dell'mcp1 come uscite, 6 pin dell'mcp2 come uscite e 6 pin dell'mcp2 come ingressi, oltre che 16 ingressi diretti di arduino. Sono scritti giusti così?

La funzione "myDigitalWrite" come la faccio con questa configurazione?

Dai, prendi ispirazione da quella che ho fatto io sopra e provaci da solo! :slight_smile:

PS: Lascia perdere gli array.

Non ci salto fuori mi puoi aiutare?