Er is een MCP23s17 die een SPI inteface heeft en een MCP23017 die een I2C interface heeft. Beide IC's zijn verder gelijk. Werkspanning van 3.3V t/m 5.5 V. Maximaal 150 mA per IC uitsturen.

Geen ervaring met I2C kijk dan hier.


MCP23x17

De MCP 23017 Is een mooi IC op dingen aan te sturen of in te lezen. Je hebt 16 onafhankelijk te programeren in of uitgangen verdeeld (als je dat wenst) over twee 8 bits registers.
Dit type IC heeft hardware adres 2x. Het is dus mogelijk om met A1 t/m A3 (Normaal laag maar hoog is instellen), diverse MCP23017 IC's vanaf 20 t/m 27 te adresseren.
Omdat er veel mogelijkheden zijn is het ook wat lastiger om het IC in te stellen.
Niets is moeilijk als je weet hoe het moet. ;-)
Het IC werkt met registers die ingesteld moeten worden, je moet bij het instellen altijd even in blokken denken, welk blok ga ik wat vertellen.
Stel je wil in een straat iedereen een persoonlijke brief sturen vanuit een ander land. Je moet dus van elk huis appart het volledige adres noteren op de anvelope. Dat is met de MCP23017 ook. Elk blok moet een volledig adres krijgen anders gaat het fout.


Er zijn 2 8_bits registers die A of B genoemd worden. Via IOCONBANK kunnen die 2 8_bits registers verteld worden dat ze als 1 16_bits register moeten samen werken. Elk register heeft een adres. De adressen zijn lastiger te onthouden dan de register namen. De namen van de 8 bits registers IODIRA etc. zijn al eens door iemand voorzien van de juiste adressen. Ik zie dit gebruik op meerdere site's en ik weet dus niet wie er mee begon maar diegene heeft goed werk gedaan.


#define IODIRA 0x00 // IO richting (0 = output, 1 = input (standaart))
#define IODIRB 0x01
#define IOPOLA 0x02 // IO polarity (0 = normal, 1 = inverse)
#define IOPOLB 0x03
#define GPINTENA 0x04 // Interrupt on change (0 = disable, 1 = enable)
#define GPINTENB 0x05 //
#define DEFVALA 0x06 // Default comparison for interrupt on change (interrupts on opposite)
#define DEFVALB 0x07
#define INTCONA 0x08 // Interrupt control (0 = interrupt on change from previous, 1 = interrupt on change from DEFVAL)
#define INTCONB 0x09
#define IOCON 0x0A // IO Configuration: Als deze 1 is is er een A (8 bits) en een B (8 bits) register en als deze een 0 is, is er 1 register van 16 bits. 00hex t/m 15hex.
//#define IOCON 0x0B // same as 0x0A
#define GPPUA 0x0C // Pull-up resistor (0 = disabled, 1 = enabled)
#define GPPUB 0x0D
#define INFTFA 0x0E // Interrupt flag (read only) : (0 = no interrupt, 1 = pin caused interrupt)
#define INFTFB 0x0F
#define INTCAPA 0x10 // Interrupt capture (read only) : value of GPIO at time of last interrupt
#define INTCAPB 0x11
#define GPIOA 0x12 // Port value. Write to change, read to obtain value
#define GPIOB 0x13
#define OLLATA 0x14 // Output latch. Write to latch output.
#define OLLATB 0x15


Er zijn 2 interuptpins INTA en INTB die naar hun poorten verwijzen of kunnen anders ingesteld worden.
Je moet dus:
Het adres van het IC aangeven. (0x20 tm 0x27)
Van 16 IO poorten aangeven of de data gelezen moet worden of geschreven.

Wire.beginTransmission(I2Cadres); // IIC Adres chip
Wire.send(IOCON); // IOCON register
Wire.send(0x20); // vertel welk adres
Wire.endTransmission();
Van alle IO ingangen aangeven of de pullup weerstand ingeschakeld moet worden

Wire.beginTransmission(I2Cadres);
Wire.send(GPPUA); //pull up weerstanden inschakelen
Wire.send(0xFF); // voor alle A ingangen
Wire.endTransmission();

Wire.beginTransmission(I2Cadres);
Wire.send(GPPUB); //pull up weerstanden inschakelen
Wire.send(0xFF); // voor alle B ingangen
Wire.endTransmission();
Moet de 16 IO poorten als 1 (AB) of als 2 (A)(B) in/uitgangen benaderd worden

Wire.beginTransmission(I2Cadres);
Wire.send(IOCON); //IOCON register
Wire.send(0x07); // voor 1 register
Wire.endTransmission();
De waarde die per poort uit moet gaan 1 of 0.

Wire.beginTransmission(I2Cadres);
Wire.send(IODIRA); // IODIRA register
Wire.send(0x00); // Allemaal 0, allemaal uitgangen
Wire.endTransmission();

Wire.beginTransmission(I2Cadres);
Wire.send(IODIRB); // IODIRB register
Wire.send(0xFF); // IODIRB, allemaal ingang
Wire.endTransmission();
De waarde die per poort in gelezen wordt.
Of de interrupt op A of B actief is.

Dan krijg je een adressering zoals in de voorbeeld sketch:


Er zijn ook complete prints met de MCP23017. Compleet met aansluiting voor een LCD scherm. Soms met een enkele rij van 16 pinnen en soms met zowel de rij van 16 pinnen en een rij van 20 pinnen. Het geheel heeft ook de I2C aansluit pinnen en soms ook uigevoerd met een mogelijk adresseerbaarheid. Als het een enkel register heeft, 8 uit/ingangen kan het een 74HC595 IC zijn om het LCD aan te sturen.
#include < Wire.h> // Wire library t.b.v. I2C
// MCP23017 registers (everything except direction defaults to 0)
#define IODIRA 0x00 // IO richting (0 = uitgang, 1 = ingang (standaard))
#define IODIRB 0x01
#define IOPOLA 0x02 // IO polariteit (0 = normal, 1 = contra)
#define IOPOLB 0x03
#define GPINTENA 0x04 // Interrupt on change (0 = disable, 1 = enable)
#define GPINTENB 0x05 //
#define DEFVALA 0x06 // Default comparison for interrupt on change (interrupts on opposite)
#define DEFVALB 0x07
#define INTCONA 0x08 // Interrupt control (0 = interrupt on change from previous, 1 = interrupt on change from DEFVAL)
#define INTCONB 0x09
#define IOCON 0x0A // IO Configuration: bank/mirror/seqop/disslw/haen/odr/intpol/notimp
//#define IOCON 0x0B // same as 0x0A
#define GPPUA 0x0C // Pull-up resistor (0 = disabled, 1 = enabled)
#define GPPUB 0x0D
#define INFTFA 0x0E // Interrupt flag (read only) : (0 = no interrupt, 1 = pin caused interrupt)
#define INFTFB 0x0F
#define INTCAPA 0x10 // Interrupt capture (read only) : value of GPIO at time of last interrupt
#define INTCAPB 0x11
#define GPIOA 0x12 // Port value. Write to change, read to obtain value
#define GPIOB 0x13
#define OLLATA 0x14 // Output latch. Write to latch output.
#define OLLATB 0x15

// adressering
#define I2Cadres 0x21 // 2x 8 bits in of uit 1e MCP23017 IC
#define B_I2Cadres 0x22 // 2x 8 bits in of uit 2e MCP23017 IC
// 1e byte is adres 4 bits voor de uit te lezen poort en 3 bits voor adres van het IC laatse bit om aa te geven of het lezen of schrijven is.
// 2e byte is voor input 0 :bit of er ook uitgestuurd moet worden: 2 bits istelling van de poort: 0: 1 bit automatisch optellen: 2 bit poort adres
// 3e byte is voor output 8 bits uit analoog signaal sterkte.


int bytewaarde[8];
void setup()
{
Wire.begin(); // start Wire library met adres
Serial.begin(57600);
// 1e IC
Wire.beginTransmission(I2Cadres); // I2C Adres chip
Wire.send(IOCON); // IOCON register
Wire.send(0x20); // Disable sequential addresses
Wire.endTransmission();

Wire.beginTransmission(I2Cadres);
Wire.send(IODIRA); // IODIRA register
Wire.send(0x00); // Allemaal 0, allemaal uitgangen
Wire.endTransmission();

Wire.beginTransmission(I2Cadres);
Wire.send(IODIRB); // IODIRB register
Wire.send(0xFF); // IODIRB, allemaal ingang
Wire.endTransmission();

Wire.beginTransmission(I2Cadres);
Wire.send(GPPUB); //pull up weerstanden inschakelen
Wire.send(0xFF); //voor alle B ingangen
Wire.endTransmission();

Wire.beginTransmission(I2Cadres);
Wire.send(IOPOLA); //polariteit omschakelen
Wire.send(0xFF); //voor alle B ingangen
Wire.endTransmission();
// 2e IC
Wire.beginTransmission(B_I2Cadres); // I2C Adres chip
Wire.send(IOCON); // IOCON register
Wire.send(0x20); // Disable sequential addresses
Wire.endTransmission();

Wire.beginTransmission(B_I2Cadres);
Wire.send(IODIRA); // IODIRA register
Wire.send(0x00); // Allemaal 0, allemaal uitgangen
Wire.endTransmission();

Wire.beginTransmission(B_I2Cadres);
Wire.send(IODIRB); // IODIRB register
Wire.send(0x00); // Allemaal 0, allemaal uitgang
Wire.endTransmission();
}
// 1e IC
void turnOnLED()
{
Wire.beginTransmission(I2Cadres);
Wire.send(GPIOA); // GPIOA = 1e groep van 8 I/O poorten.
Wire.send(B00111100);
Wire.endTransmission();
}
// IC 2
void turnOnLEDL()
{
Wire.beginTransmission(B_I2Cadres);
Wire.send(GPIOA); // GPIOA = 1e groep van 8 I/O poorten.
Wire.send(B11110000);
Wire.endTransmission();
}
// IC 2
void turnOnLEDR()
{
Wire.beginTransmission(B_I2Cadres);
Wire.send(GPIOA); // GPIOA = 1e groep van 8 I/O poorten.
Wire.send(B11110000);
Wire.endTransmission();
}
// IC 1
void turnOffLED()
{
Wire.beginTransmission(I2Cadres);
Wire.send(GPIOA); // GPIOA = 1e groep van 8 I/O poorten.
Wire.send(B11000011);
Wire.endTransmission();
}
// IC 2
void turnOffLEDL()
{
Wire.beginTransmission(B_I2Cadres);
Wire.send(GPIOA); // GPIOA = 1e groep van 8 I/O poorten.
Wire.send(B00001111);
Wire.endTransmission();
}
// IC 2
void turnOffLEDR()
{
Wire.beginTransmission(B_I2Cadres);
Wire.send(GPIOA); // GPIOA = 1e groep van 8 I/O poorten.
Wire.send(B00001111);
Wire.endTransmission();
}
//motor vooruit op 2e IC
void motor1V()
{
Wire.beginTransmission(B_I2Cadres);
Wire.send(GPIOB); // GPIOB = 2e groep van 8 I/O poorten.
Wire.send(B00000011);
Wire.endTransmission();
}
//motor achteruit
void motor1A()
{
Wire.beginTransmission(B_I2Cadres);
Wire.send(GPIOB); // GPIOB = 2e groep van 8 I/O poorten.
Wire.send(B00000101);
Wire.endTransmission();
}
//motor stop void motor1U()
{
Wire.beginTransmission(B_I2Cadres);
Wire.send(GPIOB);
Wire.send(B00000000);
Wire.endTransmission();
}
// motor stop
void motor2U()
{
Wire.beginTransmission(B_I2Cadres);
Wire.send(GPIOB);
Wire.send(B00000000);
Wire.endTransmission();
}

//data inlezen van 1e IC void ontvang()
{
Wire.requestFrom(I2Cadres,GPIOB);
int x = Wire.receive(); // ontvang byte als getal
//motoren gaan aansturen

// okee nu de data laten zien
//int x = Wire.receive(); // ontvang byte als getal
Serial.print("Arduino data van MCP x= ");
Serial.print(x); // toon de byte
Serial.print("=");
if (x>=128) {
x=x-128;
Serial.print("1");
}else{
Serial.print("-");
}
if (x>=64) {
x=x-64;
Serial.print("1");
}else{
Serial.print("-");
}
if (x>=32) {
x=x-32;
Serial.print("1");
}else{
Serial.print("-");
}
if (x>=16) {
x=x-16;
Serial.print("1");
}else{
Serial.print("-");
}
if (x>=8) {
x=x-8;
Serial.print("1");
}else{
Serial.print("-");
}
if (x>=4) {
x=x-4;
Serial.print("1");
}else{
Serial.print("-");
}
if (x>=2) {
x=x-2;
Serial.print("1");
}else{
Serial.print("-");
}
if (x>=1) {
x=x-1;
Serial.println("1");
}else{
Serial.println("-");
}
}
void loop()
{
turnOnLED();
ontvang();
delay(500); // tijdsduur leds aan
turnOffLED();
delay(500); // tijdsduur leds uit
}



Eerste versie is het aansturen en uitlezen via de I2C.
2x MCP23017 en 2x 8591 en 1x Real time clock
Adressen van de MCP wordt automatisch twintig en de zelf ingestelde waarde.
Adressen van de 8591 worden automatisch negentig en de zelf ingestelde waarde.
Adres van de klok is ??


Een voorbeeld met klokje.


#include < Wire.h>// Wire library t.b.v. I2C
#include < RTClib.h>
#include < LiquidCrystal.h> // voor het display

#define IODIRA 0x00 // IO direction (0 = output, 1 = input (Default))
#define IODIRB 0x01
#define IOPOLA 0x02 // IO polarity (0 = normal, 1 = inverse)
#define IOPOLB 0x03
#define GPINTENA 0x04 // Interrupt on change (0 = disable, 1 = enable)
#define GPINTENB 0x05 //
#define DEFVALA 0x06 // Default comparison for interrupt on change (interrupts on opposite)
#define DEFVALB 0x07
#define INTCONA 0x08 // Interrupt control (0 = interrupt on change from previous, 1 = interrupt on change from DEFVAL)
#define INTCONB 0x09
#define IOCON 0x0A // IO Configuration: bank/mirror/seqop/disslw/haen/odr/intpol/notimp
//#define IOCON 0x0B // same as 0x0A
#define GPPUA 0x0C // Pull-up resistor (0 = disabled, 1 = enabled)
#define GPPUB 0x0D
#define INFTFA 0x0E // Interrupt flag (read only) : (0 = no interrupt, 1 = pin caused interrupt)
#define INFTFB 0x0F
#define INTCAPA 0x10 // Interrupt capture (read only) : value of GPIO at time of last interrupt
#define INTCAPB 0x11
#define GPIOA 0x12 // Port value. Write to change, read to obtain value
#define GPIOB 0x13
#define OLLATA 0x14 // Output latch. Write to latch output.
#define OLLATB 0x15

// adressering
#define I2Cadres 0x21 // IC11
//
#define B_I2Cadres 0x22 // IC2
//
#define pcf8591_lees 0x90>>1 // om data te lezen
#define pcf8591_schrijf 0x91>>1 // instellingen te kunnen doen
#define pcf8591_A_in 0x01
#define pcf8591_B_in 0x02
#define pcf8591_C_in 0x03
#define pcf8591_D_in 0x04

RTC_DS1307 RTC;
LiquidCrystal lcd(12,11,10,5,4,3,2);
void tijd()
{
DateTime now = RTC.now();
lcd.setCursor(0,0);
lcd.print("Datum: ");
lcd.print(now.day(),DEC);
lcd.print("-");
lcd.print(now.month(),DEC);
lcd.print("-");
lcd.print(now.year(),DEC);
lcd.setCursor(0,1);
lcd.print("tijd : ");
lcd.print(now.hour(),DEC);
lcd.print(":");
lcd.print(now.minute(),DEC);
lcd.print(":");
lcd.print(now.second(),DEC);
}

void setup ()
{
lcd.begin(16,4);
//Serial.begin(57600);
Wire.begin();
RTC.begin();
Wire.begin(IODIRB); // start Wire library met adres
//Serial.begin(57600);

// 1e IC
Wire.beginTransmission(I2Cadres); // IC Adres chip
Wire.send(IOCON); // IOCON register
Wire.send(0x20); // Disable sequential addresses
Wire.endTransmission();

Wire.beginTransmission(I2Cadres);
Wire.send(IODIRA); // IODIRA register
Wire.send(0x00); // Allemaal 0, allemaal uitgangen
Wire.endTransmission();

Wire.beginTransmission(I2Cadres);
Wire.send(IODIRB); // IODIRB register
Wire.send(0xFF); // IODIRB, allemaal ingang
Wire.endTransmission();

Wire.beginTransmission(I2Cadres);
Wire.send(GPPUB); //pull up weerstanden inschakelen
Wire.send(0xFF); // voor alle B ingangen
Wire.endTransmission();
// 2e IC
Wire.beginTransmission(B_I2Cadres); // IC Adres chip
Wire.send(IOCON); // IOCON register
Wire.send(0x20); // Disable sequential addresses
Wire.endTransmission();

Wire.beginTransmission(B_I2Cadres);
Wire.send(IODIRA); // IODIRA register
Wire.send(0x00); // Allemaal 0, allemaal uitgangen
Wire.endTransmission();

Wire.beginTransmission(B_I2Cadres);
Wire.send(IODIRB); // IODIRB register
Wire.send(0x00); // Allemaal 0, allemaal uitgang
Wire.endTransmission();
}
// 1e IC A
void turnOnLED()
{
Wire.beginTransmission(I2Cadres);
Wire.send(GPIOA); // GPIOA = 1e groep van 8 I/O poorten.
Wire.send(B00111100);
Wire.endTransmission();
}
// IC 1 A
void turnOffLED()
{
Wire.beginTransmission(I2Cadres);
Wire.send(GPIOA); // GPIOA = 1e groep van 8 I/O poorten.
Wire.send(B11000011);
Wire.endTransmission();

}
// IC1 B
void turnOnLED1B()
{
Wire.beginTransmission(I2Cadres);
Wire.send(GPIOB); // GPIOA = 1e groep van 8 I/O poorten.
Wire.requestFrom(I2Cadres,1);
int Bdata=Wire.receive();
lcd.setCursor(4,3);
lcd.print(Bdata,BIN);
Wire.endTransmission();
}
void turnOnffLED1B()
{
Wire.beginTransmission(I2Cadres);
Wire.send(GPIOB); // GPIOA = 1e groep van 8 I/O poorten.
Wire.send(B10000001);
Wire.endTransmission();
}
// IC 2--------------------------
void turnOnLEDL()
{
Wire.beginTransmission(B_I2Cadres);
Wire.send(GPIOA); // GPIOA = 1e groep van 8 I/O poorten.
Wire.send(B11110000);
Wire.endTransmission();

}
// IC 2
void turnOnLEDR()
{
Wire.beginTransmission(B_I2Cadres);
Wire.send(GPIOA); // GPIOA = 1e groep van 8 I/O poorten.
Wire.send(B11110000);
Wire.endTransmission();
}

// IC 2
void turnOffLEDL()
{
Wire.beginTransmission(B_I2Cadres);
Wire.send(GPIOA); // GPIOA = 1e groep van 8 I/O poorten.
Wire.send(B00001111);
Wire.endTransmission();
}
// IC 2
void turnOffLEDR()
{
Wire.beginTransmission(B_I2Cadres);
Wire.send(GPIOA); // GPIOA = 1e groep van 8 I/O poorten.
Wire.send(B00001111);
Wire.endTransmission();
}
// IC 2 B
void turnOnLEDLB()
{
Wire.beginTransmission(B_I2Cadres);
Wire.send(GPIOB); // GPIOA = 1e groep van 8 I/O poorten.
Wire.send(B01101001);
Wire.endTransmission();
}
// IC 2 B
void turnOffLEDLB()
{
Wire.beginTransmission(B_I2Cadres);
Wire.send(GPIOB); // GPIOA = 1e groep van 8 I/O poorten.
Wire.send(B00001111);
Wire.endTransmission();
}
// 3e IC
void leesIC3(){
Wire.beginTransmission(pcf8591_schrijf);
Wire.send(0x04); // 4 poorten inlezen maar alleen het signaal van de eerste poort
Wire.send(0xFF); // waarde voor led 3e byte
Wire.endTransmission();

Wire.beginTransmission(pcf8591_schrijf); // I2C adres 1e byt2
Wire.send(pcf8591_A_in); // instellingen om te schrijven 2e byte analooginput aan
Wire.endTransmission();

Wire.requestFrom(pcf8591_lees, 1);
byte waardeCH0 = Wire.receive();
Wire.endTransmission();

//lees 2e poort
Wire.beginTransmission(pcf8591_schrijf); // I2C adres 1e byt2
Wire.send(pcf8591_B_in); // instellingen om te schrijven 2e byte analooginput aan
Wire.endTransmission();
//
Wire.requestFrom(pcf8591_lees, 1); // aantal bytes die we willen lezen
byte waardeCH1 = Wire.receive(); // receive a byte
Wire.endTransmission();
//
Serial.print(waardeCH1,HEX); // print the character
Serial.print("\t");
// lees 3e
Wire.beginTransmission(pcf8591_schrijf); // I2C adres 1e byt2
Wire.send(pcf8591_C_in); // instellingen om te schrijven 2e byte analooginput aan
Wire.endTransmission();
//
Wire.requestFrom(pcf8591_lees, 1); // aantal bytes die we willen lezen
byte waardeCH2 = Wire.receive(); // receive a byte
Wire.endTransmission();
//

//
Wire.beginTransmission(pcf8591_schrijf); // I2C adres 1e byt2
Wire.send(pcf8591_D_in); // instellingen om te schrijven 2e byte analooginput aan
Wire.endTransmission();
//
Wire.requestFrom(pcf8591_lees, 1); // aantal bytes die we willen lezen
byte waardeCH3 = Wire.receive(); // receive a byte
Wire.endTransmission();
//
lcd.setCursor(-4,2);
lcd.print("P1");
lcd.print("-");
lcd.print("P2");
lcd.print("-");
lcd.print("P3");
lcd.setCursor(-4,3);
lcd.print(waardeCH0,HEX);
lcd.print("-");
lcd.print(waardeCH1,HEX);
lcd.print("-");
lcd.print(waardeCH2,HEX);
}

void loop ()
{
tijd();
turnOnLED();
turnOnLEDL();
turnOnLEDLB();
turnOnLEDR();
leesIC3();
turnOnLED1B();
delay(100);
turnOffLED();
turnOffLEDL();
turnOffLEDLB();
turnOffLEDR();
delay(100);
}


Bronnen:
icstation input-output-expansion-board-mcp23017-interface-16bit-channel
best-microcontroller-projects.com mcp23017
leonvanderhorst.nl MCP23017