MCP23017 I/O-Expander

Der MCP23017 ist ein 16-Bit I/O-Expander, der über das serielle Protokoll I²C angesteuert wird. Dieser IC besitzt 16 Pins, die als Ein- und Ausgänge unabhängig voneinander programmiert werden können. Die Betriebsspannung liegt zwischen 1,8V bis 5,5V, d.h. die Stromversorgung vom Arduino (3V bzw. 5V) kann benutzt werden. Die I²C-Schnittstelle kann ebenfalls auf einem 5V-Pegel betrieben werden.

MCP23017 16-Bit I/O-Expander

Spezifikationen des MCP23017

Betriebsspannung 1,8V bis 5,5V
Stromverbrauch (Leerlauf) 1mA
Stromverbrauch (Standby) 1µA
Max. Stromstärke des IC 150mA
Wenn der MCP23017 im Betrieb warm/heiß wird, könnte das ein Anzeichen sein, dass zuviel Strom durch den IC fließt!
Max. Stromstärke pro Pin 25mA
I²C-Addressen 0x20 bis 0x27

Anschlüsse des MCP23017

Alternativer Aufbau am Breadboard
Pin PDIP Pin type Function Arduino Uno
GPB0 1 I/O Bidirectional I/O pin. Can be enabled for interrupt-on-change and/or internal weak pull-up resistor. -
GPB1 2 I/O Bidirectional I/O pin. Can be enabled for interrupt-on-change and/or internal weak pull-up resistor. -
GPB2 3 I/O Bidirectional I/O pin. Can be enabled for interrupt-on-change and/or internal weak pull-up resistor. -
GPB3 4 I/O Bidirectional I/O pin. Can be enabled for interrupt-on-change and/or internal weak pull-up resistor. -
GPB4 5 I/O Bidirectional I/O pin. Can be enabled for interrupt-on-change and/or internal weak pull-up resistor. -
GPB5 6 I/O Bidirectional I/O pin. Can be enabled for interrupt-on-change and/or internal weak pull-up resistor. -
GPB6 7 I/O Bidirectional I/O pin. Can be enabled for interrupt-on-change and/or internal weak pull-up resistor. -
GPB7 8 I/O Bidirectional I/O pin. Can be enabled for interrupt-on-change and/or internal weak pull-up resistor. -
VDD 9 P Power 3V / 5V
VSS 10 P Ground GND
NC/CS 11 I NC (MCP23017), Chip Select (MCP23S17) -
SCL/SCK 12 I Serial clock input A5
SDA/SI 13 I/O Serial data I/O (MCP23017), Serial data input (MCP23S17) A4
NC/SO 14 O NC (MCP23017), Serial data out (MCP23S17) -
A0 15 I Hardware address pin. Must be externally biased. GND oder 5V (siehe Adressen)
A1 16 I Hardware address pin. Must be externally biased. GND oder 5V (siehe Adressen)
A2 17 I Hardware address pin. Must be externally biased. GND oder 5V (siehe Adressen)
RESET 18 I Hardware reset. Must be externally biased GND oder 5V
INTB 19 O Interrupt output for PORTB. Can be configured as active-high, active-low or open-drain. -
INTA 20 O Interrupt output for PORTA. Can be configured as active-high, active-low or open-drain. -
GPA0 21 I/O Bidirectional I/O pin. Can be enabledfor interrupt-on-change and/or internal weak pull-up resistor. -
GPA1 22 I/O Bidirectional I/O pin. Can be enabledfor interrupt-on-change and/or internal weak pull-up resistor. -
GPA2 23 I/O Bidirectional I/O pin. Can be enabledfor interrupt-on-change and/or internal weak pull-up resistor. -
GPA3 24 I/O Bidirectional I/O pin. Can be enabledfor interrupt-on-change and/or internal weak pull-up resistor. -
GPA4 25 I/O Bidirectional I/O pin. Can be enabledfor interrupt-on-change and/or internal weak pull-up resistor. -
GPA5 26 I/O Bidirectional I/O pin. Can be enabledfor interrupt-on-change and/or internal weak pull-up resistor. -
GPA6 27 I/O Bidirectional I/O pin. Can be enabledfor interrupt-on-change and/or internal weak pull-up resistor. -
GPA7 28 I/O Bidirectional I/O pin. Can be enabledfor interrupt-on-change and/or internal weak pull-up resistor. -

Adressen des MCP23017

Die I²C-Adresse des MCP23017 kann über die Pins A0, A1 und A2 variiert werden:

A0 A1 A2 Adresse
0 0 0 0x20
1 0 0 0x21
0 1 0 0x22
1 1 0 0x23
0 0 1 0x24
1 0 1 0x25
0 1 1 0x26
1 1 1 0x27

Pullup-Widerstände für SDA/SCL

Die I²C-Schnittstelle benötigt zwei Leitungen, über die die Daten und das Clock-Signal übertragen werden. Über SDA werden Daten vom Master zum Slave und in umgekehrte Reihenfolge gesendet. Aus diesem Grund müssen die Pins dieser Datenleitung sogenannte Open-Drain-Ausgänge (offener Kollektor) sein.
Damit die Leitungen trotzdem ein Spannungslevel besitzen, werden die Pullup-Widerstände (hier: 4,7 kΩ) benötigt. Werden diese Pullup-Widerstände nicht verwendet, dann wirken nur die internen Pullup-Widerstände des Arduinos. Dies hat zur Folge, dass das Signal nicht mehr ordentlich übertragen wird.

Verwendete Bauteile

Basis-Schaltung

Das folgende Schaltbild zeigt die Basis-Schaltung zwischen Arduino und dem MCP23017. Die I/O-Pins werden hier noch nicht verwendet.

Basis-Schaltung zwischen Arduino Uno und MCP23017

Direkte Ansteuerung über Register

Ausgabe (Output)

GPA0 bis GPA7 (=A-Register) bzw. GPB0 bis GPB7 (=B-Register) bilden geweils ein Register, welches durch die Wire.h-Library angesprochen werden kann. Um alle Pins des A- und B-Registers auf OUTPUT zu setzen, kann man folgenden Code verwenden (normalerweise im setup():

Wire.beginTransmission(0x20);
Wire.write(0x00); // IODIRA register
Wire.write(0x00); // set all of port A to outputs
Wire.endTransmission();
Wire.beginTransmission(0x20);
Wire.write(0x01); // IODIRB register
Wire.write(0x00); // set all of port B to outputs
Wire.endTransmission();

Will man nun beispielsweise im loop() einige der Output-Pins schalten verwendet man folgenden Code:

Wire.beginTransmission(0x20);
Wire.write(0x12); // address port A
Wire.write(??);  // value to send
Wire.endTransmission();
Wire.beginTransmission(0x20);
Wire.write(0x13); // address port B
Wire.write(??);  // value to send
Wire.endTransmission();

Die ?? werden durch die gewünschten Binär-, Hexadezimal. oder Dezimal-Werte ersetzt. Man kann sich sozusagen jeden Pin als ein Bit vorstellen, welches mit 0 (LOW) und 1 (HIGH) beschaltet werden kann. Alle zusammen als Zahl zusammengefasst werden nun an den MCP23017 geschickt. Will man z.B. Pin 7 und Pin 1 mit HIGH ansteuern, so muss die Zahl 10000010 lauten, was in hexadezimal 0x82 und in dezimal 130 ist.

Eingabe (Input)

Der MCP23017 ist standardmäßig schon auf Eingabe gesetzt, daher müssen keine zusätzlichen Einstellungen vorgenommen werden.
Im folgenden Beispiel verwenden wir die oben beschriebene Basis-Schaltung und ergänzen sie mit 4 Mikrotastern, welche an den Pins GPB0, GPB1, GPB2 und GPB3 verbunden werden.

#include "Wire.h"
byte inputs=0;

void setup()
{
    Serial.begin(9600);
    Wire.begin(); // wake up I²C bus
}

void loop()
{
    Wire.beginTransmission(0x20);
    Wire.write(0x13); // set MCP23017 memory pointer to GPIOB address
    Wire.endTransmission();
    Wire.requestFrom(0x20, 1); // request one byte of data from MCP20317
    inputs = Wire.read(); // store the incoming byte into "inputs"
    if (inputs > 0) {
        // if a button was pressed
        Serial.println(inputs, BIN); // display the contents of the GPIOB register in binary
        delay(200); // for debounce
    }
}

Da ja gleichzeitig alle Pins gelesen werden, kann auch das Drücken mehrerer Knöpfe zur selben Zeit ermittelt werden.

Schaltung mit Library Adafruit-MCP23017

Ex. 1

Der folgende Sketch benutzt die Library Adafruit_MCP23017 und läßt alle 16 Pins abwechselnd blinken:

#include <Wire.h>
#include <Adafruit_MCP23017.h>

Adafruit_MCP23017 mcp;

void setup()
{
    mcp.begin(0); // Init MCP23017 at address 0x20
    for (byte i=0; i<16; i++) {
        mcp.pinMode(i, OUTPUT);
    }
}

void loop()
{
    for (byte i=0; i<16; i++) {
        mcp.digitalWrite(i, HIGH);
    }
    delay(500);

    for (byte i=0; i<16; i++) {
        mcp.digitalWrite(i, LOW);
    }
    delay(500);
}

Ex. 2

Man kann über verschiedene Adressen auch mehrere MCP23017-ICs pro Arduino ansteuern, dies soll der folgende Schaltplan und Sketch demonstrieren. Wiederum blinken alle Output-Pins diesmal von zwei MCP-Chips:

Schaltplan für den Betrieb von zwei MCP23017 mit dem Arduino Uno
Abb.: Schaltplan für den Betrieb von zwei MCP23017 mit dem Arduino Uno
#include <Wire.h>
#include <Adafruit_MCP23017.h>

Adafruit_MCP23017 mcp1;
Adafruit_MCP23017 mcp2;

void setup()
{
    mcp1.begin(0); // Init MCP23017 at address 0x20
    mcp2.begin(1); // Init MCP23017 at address 0x21

    for (byte i=0; i<16; i++) {
        mcp1.pinMode(i, OUTPUT);
        mcp2.pinMode(i, OUTPUT);
    }
}

void loop()
{
    for (byte i=0; i<16; i++) {
        mcp1.digitalWrite(i, HIGH);
        mcp2.digitalWrite(i, HIGH);
    }
    delay(500);

    for (byte i=0; i<16; i++) {
        mcp1.digitalWrite(i, LOW);
        mcp2.digitalWrite(i, LOW);
    }
    delay(500);
}
zurück