MCP23017 I2C I/O Port Expander

Auch wenn ein einfacher Arduino schon reichlich Ports hat, kann es doch mal sein das man entweder noch mehr Ports benötigt, ein Arduino Mega zu viel Platz wegnimmt oder man I/O Ports auslagern will. Mit dem MCP23017 Input-Output Port Expander ist das möglich.

MCP23017

Der MCP23017 besitzt insgesamt 16 wechselbare I/O Ports (8 auf jeder Seite) und es können durch die drei Hardware Adressen Pins (A0-A2) bis zu 8 Geräte an einem I2C Bus betrieben werden. Wie bei einem Arduino kann ein interner Pull-Up Widerstand aktiviert und so eine vereinfachte Schaltungen ermöglicht werden. Mit einem ULN2803A Darlington Transistor Array kombiniert, können sogar größere Lasten geschaltet werden.

MCP23017 I2C IO Port Expander - Pinbelegung

Die Schaltung

Zuerst verbinden wir die Pins für die Spannungsversorgung (Pin 9 VDD = +5V / Pin 10 VSS = GND), Reset (Pin 18 RESET = +5V) und für I2C (Pin 12 = SCL / Pin 13 = SDA) vom MCP23017 mit dem Arduino.

Arduino SDA SCL
Uno A4 A5
Mega 20 21
Micro Pro 2 3

Jetzt sollten noch die Pins für die Hardware Address (Pin 15 = A0 /Pin 16 = A1 /Pin 17 = A2) mit GND oder HIGH verbunden werden. Wenn alle grauen Kabel wie auf dem nachfolgenden Bild auf GND gesteckt sind, wird die erste mögliche Hardware Adresse 0x20 gewählt. Ich habe gelesen, wenn die Pins nicht auf GND oder +5V gelegt werden, sind die Pins im Zustand floating bzw. undefiniert und das kann zu Problemen führen.
MCP23017 I2C IO Port Expander - Steckplatine Minimum
Natürlich kann auch eine andere Adresse eingestellt werden. Der Status (GND = 0 / +5V = 1) der Hardware Address Pins ergeben folgende Adresse.

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

Library und Sketch

In dem nachfolgenden Beispiel habe ich zwei MCP23017 eingebaut. So kann man besser sehen wie die Ansteuerung eines weiteren MCP23017 Port Expander funktioniert.

MCP23017 I2C IO Port Expander - Steckplatine Beispiel

Es gibt diverse Beispiele wie man den MCP23017 direkt über I2C ansprechen kann, ich habe mich aber für die Adafruit MCP23017 Library entschieden. Damit lassen sich die einzelnen I/O Pins fast wie normale Pins ansteuern.

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

Adafruit_MCP23017 mcp1; // Create MCP 1
Adafruit_MCP23017 mcp2; // Create MCP 2

const uint8_t addr1 = 0; // Adresse 0x20 / 0
const uint8_t addr2 = 1; // Adresse 0x21 / 1
void setup() {  
  mcp1.begin(addr1);      // Start MCP 1
  mcp2.begin(addr2);      // Start MCP 2

  mcp1.pinMode(7, INPUT); // Define GPA7 on MCP1 as input
  mcp1.pullUp(7, HIGH);  // Activate Internal Pull-Up Resistor

  mcp1.pinMode(8, OUTPUT); // Define GPB0 on MCP1 as Output
  mcp2.pinMode(15, OUTPUT); // Define GPB7 on MCP2 as Output

} // End Setup

void loop() {
 // The LED on GPB0 will 'echo' the button on GPA7

  if (mcp1.digitalRead(7) == LOW)
  {
    mcp1.digitalWrite(8, HIGH);
    mcp2.digitalWrite(15, HIGH);
  }
  else
  {
    mcp1.digitalWrite(8, LOW);
    mcp2.digitalWrite(15, LOW);
  }
} // End loop

49 Gedanken zu „MCP23017 I2C I/O Port Expander“

  1. mcp1.pinMode(7, INPUT); Define GPA7 on MCP1 as input ist leider falsch

    … mcp1.pinMode(7, INPUT); // Define GPA7 on MCP1 as input

      1. Hallo Stefan , danke für dein Tutorial
        Mein deutsch ist nicht so gut,ich hätte eine Frage .
        Ich habe von — Adafruit MCP23017 Library– heruntergeladen
        jetz versuche ich den Sketch, auf mein arduino uno aufzuspielen,
        haber er gibt mier die fehlermeldung
        //
        Arduino: 1.6.8 (Windows 10), Board: “Arduino/Genuino Uno”
        Bibliothek Wire in Version 1.0 im Ordner: C:UsersSalvatoreAppDataLocalArduino15packagesarduinohardwareavr1.6.17librariesWire wird verwendet
        //

        danke

        1. Hallo Salvatore,

          das sieht mir mehr nach einer Info und nicht nach einem Fehler aus? Wird noch mehr ausgegeben?

          Viele Grüße
          Stefan

          1. Hallo Stefan,entschuldigung für meine späte rückmeldung, ich habe das
            problem gelöst. Ich hätte eine andere Frage mit den Arduino 2560 Mega kann man nur
            maximum mit acht MCP23017 komunizieren , oder gibt es ein andere
            möglichkeit das man mer als acht MCP23017 mit Arduino 2560 komunizieren
            kann?

            Viele Grüße
            Salvatore

    1. Hallo David,

      ich habe die Links zu Aliexpress gelöscht, da der erste schon nicht mehr funktioniert. Ein paar Beispiele und Libraries findet man zwar, aber die Unterstützung der beiden I2C Chips PCF8574 (8 I/O Pins) und PCF8575 (16 I/O Pins) die auf den Platinen verbaut sind, könnte sicherlich besser aussehen.

      Du musst aber schauen ob die Spezifikationen für dein Projekt ausreichend sind. Für mich war beim MCP23017 unter anderem wichtig, dass interne Pull-Up Widerstände vorhanden sind und ausreichend Leistung für ULN2803 vorhanden ist. Ob einer der beiden I2C Chips für dich passt, kann ich dir leider nicht sagen. Ich habe bisher noch keine Erfahrung damit gesammelt.

      Viele Grüße
      Stefan

  2. Hallo,

    ich benutze folgenden Code für ein mcp:

    #include
    #include “Adafruit_MCP23017.h”

    Adafruit_MCP23017 mcp;

    void setup() {
    mcp.begin(0); // use default address 0
    mcp.pinMode(7, INPUT);
    mcp.pinMode(8, OUTPUT);
    mcp.pinMode(9, OUTPUT);

    }

    void loop() {
    if (mcp.digitalRead(7) == HIGH)
    {
    mcp.digitalWrite(8, HIGH);
    mcp.digitalWrite(9, HIGH);

    }
    else
    {
    mcp.digitalWrite(8, LOW);
    mcp.digitalWrite(9, LOW);
    }

    }

    Das Problem ist, dass 8 und 9 sehr lange brauchen (20 Sek) bis die von High auf Low wechseln (Wenn ich also 7 von High auf Low wechsle) Woran liegt das?

    1. Hallo Thomas,

      kann es sein das dein Taster kein sauberes LOW zurück gibt? Ich kenne deinen Aufbau nicht aber wenn du den Taster direkt gegen GND verbindest, benötigst du noch folgende Zeile damit der Interne Pull-Up Widerstand aktiviert wird.

      mcp.pullUp(7, HIGH); // Activate Internal Pull-Up Resistor

      Melde dich gerne nochmal ob es dein Problem gelöst hat.

      Viele Grüße
      Stefan

  3. Hallo Stefan
    Habe Dein Beispiel problemlos auf 3 MCP23017 erweitert.
    Danke für Deine verständlichen Erläuterungen.
    Setze es für mein Projekt Rolladensteuerung ein.
    Wenn interesse könnt Ihr Euch ja melden.
    Grüße Reinhold

    1. Hallo Reinhold,

      freut mich das es bei dir so gut geklappt hat! Habe dir direkt eine Mail geschickt.

      Ich habe um dich vor Spam zu schützen deine E-Mail Adresse aus dem Kommentar entfernt. Du bekommst aber aktuell automatisch (wie von dir eingestellt) eine Info wenn sich jemand zu diesem Beitrag meldet.

      Viele Grüße
      Stefan

      1. Hallo Stefan,
        Habe versucht MCP23017 an arduino pro mini anzuschliessen,
        dabei habe ich a2 , a3 für SCL und SDA genommen. Bei Arduino uno sind es ja
        A4, A5. Hat nicht geklappt. Hast Du vielleicht eine Idee????
        Grüße Reinhold

        1. Hallo Reinhold,

          beim Arduino Pro Mini sollten es die Pins A4 und A5 sein?! Diese sind nicht beschriftet und es kann schnell zu einer Verwechslung kommen. Schräg über Pin A2 liegt A4 (SDA) und über Pin A3 liegt A5 (SCL).

          Viele Grüße
          Stefan

          1. Super danke werde noch 2 Pins einlöten und dann testen, müßte funktionieren.
            Ist meinen Augen geschuldet, dass ich es nicht gesehen habe.

    2. Hallo Reinhold,

      wie kann man sich denn an dich wenden?
      Bin auch gerade am Planen an einer zentralen Rolladensteuerung und Beleuchtung über Arduino.

      1. Hallo Marc,

        wenn Reinhold mir das OK gibt, gebe ich gerne seine E-Mail Adresse an dich weiter! Habe es gerade schon im Kommentar an Chris geschrieben, es gibt demnächst noch Beitrage zu meiner kleinen Steuerung mit den I2C I/O Platinen und einem Wemos D1 in der Werkstatt.

        Viele Grüße
        Stefan

  4. Hallo,

    ich habe ein kleines Problem:
    Mein Nano hat auf den Adafruit offensichtlich keine Lust.
    Folgende Fehler: (Es sei gesagt, dass ich alle Librarys habe)
    hat einer vielleicht eine Idee???? Vielen Dank schon einmal

    ccOlqtoZ.ltrans0.o:(.text.startup+0x8c): undefined reference to `Adafruit_MCP23017::begin(unsigned char)’

    ccOlqtoZ.ltrans0.o:(.text.startup+0x98): undefined reference to `Adafruit_MCP23017::pinMode(unsigned char, unsigned char)’

    ccOlqtoZ.ltrans0.o:(.text.startup+0xa4): undefined reference to `Adafruit_MCP23017::pinMode(unsigned char, unsigned char)’

    ccOlqtoZ.ltrans0.o:(.text.startup+0xb4): undefined reference to `Adafruit_MCP23017::digitalWrite(unsigned char, unsigned char)’

    ccOlqtoZ.ltrans0.o:(.text.startup+0xc0): undefined reference to `Adafruit_MCP23017::digitalWrite(unsigned char, unsigned char)’

    ccOlqtoZ.ltrans0.o:(.text.startup+0x11a): undefined reference to `Adafruit_MCP23017::digitalWrite(unsigned char, unsigned char)’

    ccOlqtoZ.ltrans0.o:(.text.startup+0x126): undefined reference to `Adafruit_MCP23017::digitalWrite(unsigned char, unsigned char)’

    collect2.exe: error: ld returned 1 exit status

    exit status 1

    1. Hallo Chris,

      hast du mal versucht ein mitgeliefertes Example aufzuspielen oder einfach mal einen Uno auszuwählen (es gibt nur eine Meldung das dieser nicht erreichbar ist) und geschaut was dann passiert? So könntest du deinen Sketch und den Nano ausschließen.
      Ich glaube aber eher das es an deiner Umgebung liegt. Verschiebe doch mal den libraries Ordner, erstelle einen neuen Ordner und installiere nur die Adafruit_MCP23017. Vielleicht ist es wirklich nur ein Konflikt zwischen zwei Libraries?!

      Viele Grüße
      Stefan

      1. Hallo Stefan,

        vielen Dank. Ich habe alles ausprobiert….nichts geht, auch die Beispiele nicht.
        Immer die selbe Fehlermeldung.
        Mit der Lib von kasperskaarhoj/MCP23017-Arduino-Library
        scheint es zu gehen….aber so Dinge wie mit Button arbeiten sind wohn nicht möglich.
        PullUp gibt es in der Lib nicht.
        Vielleicht noch eine Idee??

        Danke und Grüße
        Chris

        1. Hallo Chris,

          wirklich sehr seltsam! Du glaubst mir sicherlich auch ohne Screenshots das bei mir das Button Beispiel der Adafruit_MCP23017 Library für den Arduino Nano erfolgreich kompiliert wird?!

          Wenn du alles (andere Libraries entfernen und Board wechseln) ausprobiert hast, kann es eigentlich nur noch an deinem System liegen?! Wenn du die Möglichkeit hast, prüfe es doch mal an einem anderen Gerät. Ich bin mir sicher da funktioniert es!

          Viele Grüße
          Stefan

    1. Hallo Claudius,

      da ich bisher noch mit keinem Teensy gearbeitet habe, kann ich dir dazu leider keine genaueren Infos geben. Nach einer kurzen Google Recherche würde ich sagen, dass es sogar mit der Adafruit Library funktionieren sollte.

      Viele Grüße
      Stefan

  5. Hallo Stefan, Hallo Reinhold,
    ich bin auch gerade dabei mir eine Rollo/Raffstore-Steuerung zu bauen.
    Aber es scheitert leider an meinen Programmier-Kenntnissen.
    @Reinhold, kannst du mir vielleicht Tipps geben wo ich ein Skript finde welches ich mir anschauen könnte. Ich würde nämlich auch gerne verstehen wie die Zusammenhänge sind.
    Ich hätte es gerne so, dass ich die Rollos über das Handy steuern kann – mittels HTML-Seite auf meinem Raspberry. Wenn ich dann am Handy auf Rollo_Wohnzimmer_hoch klicke, soll dann eben das entsprechende Pin und somit das Relais schalten. Mein großes Problem ist eigentlich das einzelne Ansteuern der einzelnen PIN’s.
    Danke und Grüße
    Ben

    1. Hi Aakash,

      i think the mcp23s17 (SPI Version from mcp23017) is also possible. I haven`t testet it so far but found some examples.

      Best regards
      Stefan

      1. Will the same code work for spi23s17?
        If no then can you please suggest anything how to code with that? Because i found that SPI is faster and efficient than I2C. Please reply.

  6. o_O hi

    ich komme bei der “pinMode(…” nicht so klar, da Pin 7 des MCP23017 doch GB6 ist, oder verstehe ich da was falsch? GPA7 ist doch auf Pin 28 oder ist die Pinbelegung von Adafruit völlig anders deklariert?

    LG Maya

    1. Hallo Maya,

      ich musste mich auch erst kurz wieder einlesen, aber eigentlich ist es ganz einfach. Du zählst einfach von GPA0 (0) bis GPA7 (7) und dann weiter mit GPB0 (8) bis GPB7 (15) durch. Die Zahlen in den Klammern sind die, die du auch in der Arduino IDE für die MCP23017 Adafruit Library benötigst. Pin 28 ist GPA7, die Zahl wird aber nicht verwendet. Es ist nur eine Beschriftung.

      Viele Grüße
      Stefan

  7. Hilfe…

    Mein Arduino Nano V3 will das Programm nicht.
    Wenn ich den Sketch, so wie er hier ist, erst überprüfe und dann hochladen will, kommen nur fehlermeldungen :
    “Arduino: 1.8.3 (Windows XP), Board: “Arduino Nano, ATmega328″
    sketch_aug05a:109: error: stray ‘302’ in program

        mcp3.digitalWrite(15, LOW);
    sketch_aug05a:109: error: stray ‘240’ in program
    sketch_aug05a:109: error: stray ‘302’ in program
    sketch_aug05a:109: error: stray ‘240’ in program
    sketch_aug05a:109: error: stray ‘302’ in program
    sketch_aug05a:109: error: stray ‘240’ in program
    sketch_aug05a:3: error: expected unqualified-id before numeric constant
    #define mcp1 0x20 // I2C Adresse des 1. Portexpanders MCP23017
    Adafruit_MCP23017 mcp1; // Create MCP 1
    sketch_aug05a:4: error: expected unqualified-id before numeric constant
    …”

    …ich weiss net weiter….

  8. …”und plötzlich drohte Thors Hammer…” funtzt…

    ??? keine Ahnung wieso, aber ich hab im sketch die Wire.h Library entfernt, weil ich “schritt für schritt” erstmal nur einen MCP und dann weitere zufügen wollte. Da das Projekt (LED Uhr mit 72 einzelne LEDs) einen RTC (DS23..) nutzt und daher neben den Adafruit MCP.. libary auch die Wire benötigt.
    Zusätzlich klemmte ich den nano ab und einen mega 2560 dran.
    Warum läuft das jetzt mit dem mega 2560 und ohne Wire.h? Verstehe ich nicht….

    PS: dein Captcha zeigt keine Wörter an… (nur nach mehreren versuchen)

  9. Hallo,
    ich würde gerne 4 Stück verwenden, komm aber nicht weiter bei der Verdrahtung.
    Bei allen Beispieln werden immer nur ein oder zwei angeklemmt.#
    Hat da jemand Erfahrung?

    Gruß Robin

    1. Hallo Robin,

      womit genau hast du denn Probleme? Kommst du mit der Adressierung nicht weiter oder werden nicht alle MCP23017 richtig erkannt? Die Adressierung von bis zu 8 Modulen ist als Tabelle im Beitrag oder im Datasheet zu finden. Grundsätzlich solltest du A0, A1 und A2 entweder mit GND oder +5V verbinden und nicht unbeschaltet lassen. Wenn du 0x20 bis 0x23 für deine 4 Module vergeben hast, solltest du am besten nochmal mit einem I2C Scanner Sketch prüfen welche erreichbar sind.

      Viele Grüße
      Stefan

      1. Hallo Stefan,
        ich habe heute morgen den Artikel nochmal gelesen und gemerkt, dass ich mich nur blöd angestellt habe. Habe jetzt gesehen, dass nur mit drei Pins der Binärcode geschaltet wird.
        Wer lesen kann ist halt klar im Vorteil 😉

        Gruß Robin

  10. Ich habe das Beispiel mit den zwei ICs versucht und es spielt auf aber leuchtet nicht. Wie würde man denn da denn mit Debuggen weiter machen? Serieller Port?

    1. Hallo Benjamin,

      starte am besten erstmal nur mit einem MCP23017 und nehme einen zweiten dazu, wenn der erste funktioniert. Da jeder seine eigene I2C Adresse haben sollte, kannst du die Erreichbarkeit mit einem I2C Scanner Sketch (https://playground.arduino.cc/Main/I2cScanner) überprüfen. Wenn das nicht funktioniert, ist sicherlich etwas falsch verdrahtet?!

      Wenn beide Geräte richtig verdrahtet sind, kannst du dem eigentlichen Sketch anfangen. Hier solltest du dann zur Kontrolle die Ausgabe auf den Serial Monitor einbauen.

      Viele Grüße
      Stefan

  11. Hallo Stefan,
    danke für den Tipp mit dem I2C Scanner. Das Problem war dann wohl dass der Nano auf A4 und A5 keine Pull-Up-Widerstände hat, die musste ich noch dazwischen hängen, jetzt geht es.
    Viele Grüße,
    Benjamin

    1. Hallo Rob,

      im Beitrag ist ein einfaches Beispiel enthalten oder welches meintest du? Ein komplexes Beispiel, welches du auf den MCP23017 umbauen könntest, findest du im Beitrag I2C WLAN Gateway.

      Viele Grüße
      Stefan

      1. Hi Stefan,
        wusste nicht dass die Antwort immer ganz unten angehangen wird….
        ich bezog mich auf den Kommentar von

        REINHOLD
        14. Juli 2016 um 00:58 Uhr
        Hallo Stefan
        Habe Dein Beispiel problemlos auf 3 MCP23017 erweitert.
        Danke für Deine verständlichen Erläuterungen.
        Setze es für mein Projekt Rolladensteuerung ein.
        Wenn interesse könnt Ihr Euch ja melden.
        Grüße Reinhold

        mich interessiert die einbindung von mehreren MCPs als DI.

        hast Du sein Beispiel sketch da?

        grüße

        1. Hallo Reinhold,

          ich habe auf einem Pi schon eine Rollosteuerung laufen. Jetzt möchte ich alles auf einen Wemos D1 umstellen. Kann man deinen Code als Grundgerüst bekommen?

          Bei mir arbeiten zur Zeit 6 MCPs für Taster und Rollos. Jetzt sollen auch noch Fensterkontakte hinzukommen.

          Gruß Matthias

  12. Hi Stefan!
    Beim Kompilieren des Beispielfiles aus Deiner Seite über den MCP23017 I/O Port Expander erreiche ich beim Kompilieren immer nur die folgende Fehlermeldung.
    C:UsersThomas NoackDocumentsArduinoTest210321Test210321.ino: In function ‘void setup()’:
    Test210321:8:15: error: call of overloaded ‘begin(int)’ is ambiguous
    mcp1.begin(0); // Start MCP 1 on Hardware address 0x20
    ^
    In file included from C:UsersThomas NoackDocumentsArduinoTest210321Test210321.ino:2:0:
    C:UsersThomas NoackDocumentsArduinolibrariesAdafruit_MCP23017_Arduino_Library/Adafruit_MCP23017.h:26:8: note: candidate: void Adafruit_MCP23017::begin(uint8_t, TwoWire*)
    void begin(uint8_t addr, TwoWire *theWire = &Wire);
    ^~~~~
    C:UsersThomas NoackDocumentsArduinolibrariesAdafruit_MCP23017_Arduino_Library/Adafruit_MCP23017.h:27:8: note: candidate: void Adafruit_MCP23017::begin(TwoWire*)
    void begin(TwoWire *theWire = &Wire);
    ^~~~~
    C:UsersThomas NoackDocumentsArduinoTest210321Test210321.ino: At global scope:
    Test210321:35:1: error: expected declaration before ‘}’ token
    }
    ^
    exit status 1
    call of overloaded ‘begin(int)’ is ambiguous

    Kann ich von Dir einen Tip bekommen, was da wohl falsch läuft? Ich verwende einen recht neuen NUK mit Win10 drauf. Und dummerweise taugt mein 40 Jahre altes Schulenglisch recht wenig…
    Ach so: wenn ich bei “begin()” anstelle der 0 eine 2 setze, dann läßt sich der sketch kompilieren.
    Vielen Dank für Deine Mühe!
    Thomas

    1. Hallo Thomas,

      seit der Version 1.2 der Library ist es scheinbar nicht mehr erlaubt, die Adresse so anzugeben. Wenn du die 0 weglässt und einfach mcp1.begin() für die Default Adresse 0x20 schreibst, müsste es klappen. Ich habe das Beispiel auf eine ausführlichere Version umgeschrieben, auch so müsste es funktionieren. Kompilieren klappt bei beiden Varianten, nur richtig testen konnte ich es leider nicht. Ich und andere Leser würden sich daher sicherlich über ein kurzes Feedback von dir freuen!

      Viele Grüße
      Stefan

  13. Guten Abend,
    ich benutze sehr gerne den MCP 23017. Jetzt bin ich aber auf der Suche nach einer Lösung für folgendes Problem.
    Den MCP nutze ich als Ein und Ausgang an einem Arduino. Nun wollte ich noch einen 2. Arduino als Slave daran anschließen. Wenn ich alles ohne den MCP betreibe sendet der MAster die Daten an den Slave. Mit dem MCO kommt aber nicht mehr am Slave an. Die I2C-Adressen habe ich schon überprüft.
    Haben Sie noch eine Idee was da flasch laufen könnte oder geht das an sich nicht.

    einen schönen Abend

    U. Dittmar

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert