Kennen Sie das auch? Sie entwickeln auf Ihrer bevorzugten Plattform – aber es fehlen Ihnen I/O-Pins? Möchten Sie gerne mehr Eingänge einlesen oder Ausgänge ansteuern? Dieses - über den I²C-Bus angesteuerte - Breakout-Board erlaubt die Ansteuerung von bis zu 16 I/O-Pins pro Einheit (maximal 128 I/O-Pins pro I²C-Bus).

Es gibt immer wieder Situationen, in denen es notwendig ist, verschiedene Signale und Aktoren mit einem Mikrocontroller zu verwalten - der oft jedoch nicht über genügend I/O-Pins verfügt. In solchen Situationen ist es nützlich, auf sogenannte I/O-Expander zurückzugreifen. Deren Funktion besteht darin, eine bestimmte Anzahl von Eingangs- und Ausgangsleitungen zu serialisieren, um sie über einen einzigen I/O oder eine einzige Schnittstelle zu steuern. Das kann z.B. eine serielle Kommunikationsleitung wie der weit verbreitete I²C-Bus sein, der in vielen Mikrocontrollern und natürlich auch auf Arduino-Boards zu finden ist.

Um die Anzahl der I/O-Pins zu erhöhen, haben wir in diesem Projekt ein Breakout-Board auf Basis des Microchip MCP23017 entwickelt, welches wir in diesem Artikel vorstellen wollen. Es handelt sich um einen 16-Bit I/O-Expander mit minimaler externer Beschaltung (eigentlich nur ein dreipoliger DIP-Switch und ein paar Widerstände). Selbstverständlich zeigen wir Ihnen die Anwendungsmöglichkeiten eines I/O-Expanders anhand eines Praxis-Beispiels. Konkret soll es um die Ansteuerung von insgesamt acht Relais gehen, die entweder über TTL-Pegel oder Tasten angesteuert werden. Lassen Sie uns nun starten und einen Blick auf den Schaltplan werfen!

Abonnieren
Tag-Benachrichtigung zu Mikrocontroller jetzt abonnieren!

Der Schaltplan des Breakout-Boards

Wie in Bild 1 zu sehen, ist der Aufbau der Schaltung sehr einfach. Wir verwenden das IC MCP23017 im DIP-Gehäuse. Hierbei sind alle Pins im Raster von 2.54 mm angeschlossen, was einen späteren Anschluss von Flachbandkabeln vereinfacht. Auch die Montage auf anderen Leiterplatten oder Breadboards wird damit um vieles einfacher.

Die drei LSB der physikalischen Bus-Adresse werden über die DIP-Schalter in SW1 (Pins A0, A1, and A2 mit Pull-Up Widerständen R1_R3) eingestellt. Über die Pull-Up-Widerstände ist ein definierter Pegel (logisch „High“ bei offenem Schalter) garantiert.

 

Breakout board Schematic diagram MCP23017

Bild 1: Der Schaltplan des Breakout-Board.

Alle I/O-Pins der Register A und B wurden direkt auf Stiftleisten angeschlossen. Diese Pins wurden im Layout beidseitig angeordnet, so dass wir unsere Platine leicht anschließen können. Bei digitalen I/O-Pins müssen Sie allerdings die maximale Belastbarkeit (gemäß Datenblatt) beachten! Im Layout wurden nicht nur die Stiftleisten an der Seite implementiert, sondern auch eine Stiftleiste mit vier Pins („I2C“) an der Oberseite, an welchem der Bus direkt von oben angeschlossen werden kann (siehe Bild 4). Diese sind parallel zu den I2C-Pins an der Seite angeschlossen.

Zur einfachen Anwendung wurden die Ports A und B auf den gegenüberliegenden Seiten der Platine platziert. Die Anschlüsse des I²C-Bus wurden zusammen mit +5V und GND zu einer Stiftleiste (mit „I2C“ markiert) geroutet. Die Datenleitungen sind mit Pull-Up-Widerständen ausgestattet. Die Reset-Leitung wird nicht verwendet. Daher wird der Reset-Pin (18, RST) durch Anschluss an +5V (über Widerstand R4) deaktiviert.

Bei den seitlichen Anschlussleisten finden sich auch noch einmal GND und die +5V. Das Hauptelement der Schaltung ist natürlich der MCP23017 (U1) in seiner Funktion als „I²C Bus zu Parallel“-Konverter. Das IC, wie im Blockschaltbild in Bild 2 ersichtlich, funktioniert als Peripheriegerät (Slave) am I²C-Bus und verfügt sowohl über Eingabe- als auch Ausgabemodus. Im Ausgabemodus wird vom Master ein Byte pro Register geschrieben, um die Ausgänge zu steuern, im Eingangsmodus wird ein Byte pro Port an den Master zurückgeschickt.

Block diagram of the MCP23017: the SPI variant, which distinguishes MCP23017 from MCP23017, is also shown.
Bild 2: Block-Diagramm des MCP23017. Auch die SPI-Variante, die den MCP23017 vom MCP23017 unterscheidet, ist zu sehen.

Der MCP23017

Das Herz unseres Breakout-Boards ist ein I/O-Expander mit 16 Bits, aufgeteilt auf zwei Ports mit jeweils acht Bit, der über einen I²C-Bus angesteuert wird. Wir können also mit nur zwei Signalen (auf Masse bezogen) den Zustand von bis 16 Leitungen einlesen - oder bis zu 16 Ausgänge kontrollieren. Die technischen Spezifikationen sind:

  • Highspeed I²C-Schnittstelle, die mit 100 kHz, 400 kHz oder 1.7 MHz getaktet wird
  • I²C-Addresse einstellbar (acht Einstellmöglichkeiten)
  • Interrupts einstellbar: Änderung des Pin-Zustands oder über eine Logik-Funktion
  • Einstellbarer Interrupt-Ausgan

Für die Eingänge gilt:

  • Externer Reset-Eingang
  • Polaritäts-Einstellung
  • Standby-Strom von maximal 1 μA
  • Versorgungs-Spannungsbereich von 1.8-5.5 V

Das IC MCP23017 bietet eine 16-Bit, serielle oder parallele, I/O-Erweiterung und kann in zwei Versionen bestellt werden: die hier verwendete Variante mit I²C-Bus (MCP23017) oder als MCP23S17 mit SPI-Bus. Dieses IC ist ein 16-Bit I/O-Expander, aufgeteilt in zwei Ports mit jeweils acht Bit. Mit nur zwei Pins (auf Masse referenziert) kann also der Eingangszustand von maximal 16 Pins eingelesen werden (Input Mode) oder es kann der Zustand von maximal 16 Ausgängen eingestellt werden. Ohne Programmierung (Default) sind alle Pins als Eingänge konfiguriert.

Der MCP23017 verfügt über mehrere Register (alle acht Bit breit) für Eingang, Ausgang und Polaritäts-Einstellung. Der I²C-Master kann die I/O-Ports als Ein- oder Ausgänge über die entsprechenden Konfigurations-Bits einstellen (IODIRA/B). Die Daten für die jeweiligen Ein- oder Ausgänge werden im Ein- oder Ausgangsregister gespeichert. Bei Eingängen kann die Polarität der Eingange über das „Polarity inversion register“ invertiert werden. Natürlich kann der Zustand aller Register vom Master ausgelesen werden. Die Struktur des 16-Bit I/O-Ports besteht aus zwei Ports mit je acht Bits (Port A und Port B), welche über Pins 28-21 bzw. Pins 1-8 nach außen geführt werden. Das IC MCP23X17 kann sowohl für 8-Bit oder für den 16-Bit-Modus eingestellt werden. Weiterhin gibt es zwei Interrupt-Pins (INTA und INTB), welche entweder mit den jeweiligen Ports verknüpft werden (INTA für Port A und INTB für Port B) oder mit einer logischen ODER-Funktion verknüpft werden (in diesem Fall wird ein Interrupt auf Port A oder Port B beide Interrupt-Pins aktivieren).

Der Interrupt-Ausgang kann bei einer der folgenden Bedingungen triggern:
  • Wenn sich der Zustand eines Eingangs von seinem Eingangs-Register abweicht. Hiermit wird dem Master (unabhängig vom Protokoll) mitgeteilt, das sich der Zustand einer der Eingänge geändert hat.
  • Wenn der Eingang von einem voreingestellten Wer abweicht (DEFVAL-Register).

Die Interrupt-Leitungen INTA und INTB können als Active-High, Active-Low oder Open-Drain konfiguriert werden. Das Interrupt-Capture-Register erfasst die Werte der Ports zum Zeitpunkt der Auslösung des Interrupts und speichert so die Bedingung, die den Interrupt ausgelöst hat. Der Power-On-Reset (POR) setzt die Register auf ihre Standardwerte und initialisiert die State-Machine. Die Notwendigkeit des Bidirektionalität ergibt sich aus der Tatsache, dass jedes I²C-Bus-Peripheriegerät in der Lage sein muss, sowohl zu lesen (z.B. Befehle) als auch erfasste Daten über den Bus zu senden.

Wie alle IC für den I²C-Bus ermöglicht auch der MCP23017 die Einstellung seiner Adresse in einem Bereich von 8 Adressen und verfügt zu diesem Zweck über die Pins A0, A1, A2. Diese ermöglichen die Einstellung der Adressen der Slave-Einheit. Jede dieser Adress-Leitungen wird über den Dip-Schalter SW1 eingestellt: Bei geschlossenem Dip-Schalter wird der jeweilige Pin auf „Null“ gesetzt, während umgekehrt ein offener Dip-Schalter eine logische „Eins“ darstellt.. Da wir hiermit acht Adressen definieren können, können maximal acht I/O-Expander auf demselben Bus adressiert werden - und somit maximal 128 I/O-Pins mit nur drei Leitungen gesteuert werden!

Die gesamte Schaltung wird über 5V gespeist (im Layout doppelt vorhanden: Kontakte 1 und 15 in den Längsreihen), die auf Masse/GND bezogen sind (ebenfalls doppelt vorhanden, Kontakte 2 und 23 in den Längsreihen). Nun wird bei Empfang eines Datenstrings auf der SDA-Leitung (getaktet durch die SCL-Leitung) das enthaltene Kommando ausgeführt. In diesem Beispiel werden 16 Bits als Ausgangswerte geschrieben. Dabei werden die 8 Bit eines jeden Byte 1:1 am Ausgang wiedergegeben (bei IOA0÷IOA7 entspricht IOA0 dem Zustand des ersten Bits im Byte, IOA1 dem des zweiten usw.). Dasselbe gilt für IOB0÷IOB7.



Die Umwandlung und Darstellung an den Ausgängen erfolgt natürlich nur unter der Voraussetzung, dass der empfangene String die richtige I²C-Bus-Adresse enthält (die der mit den DIP-Schaltern von SW1 für U1 eingestellten Adresse entspricht). Beim Empfang jedes Strings aktualisiert der MCP23017 den Status seiner Ausgänge und über die Logikpegel wird bestimmt, ob die LEDs der Anzeigesegmente eingeschaltet werden (oder ausgeschaltet bleiben) Wenn anschließend kein String gesendet wird, behält die Anzeige die angezeigte Zahl bei, da die Ausgänge des MCP23017-Integrators über Latches verfügen. Das gilt für den Ausgabemodus, d.h. das Schreiben des Status der beiden I²C-Bus-Bytes in die Ausgaberegister A und B. Wird jedoch der vom Befehl „Lesen“ durch den MCP23017 empfangen, wird der E/A-Status jedes Registers erfasst. Es werden zwei Bytes als Antwort geschickt, wobei das erste den Status von IOA0÷IOA7 und das zweite den logischen Zustand von IOB0÷IOB7 enthält. Tabelle 1 enthält die Kombinationen des DIP-Schalters für verschiedene Adressen (je nach Anwendung kann es nötig sein, eine spezielle Adresse einzustellen)

230469-006-94-ORIGINAL-tabella 1.png
Tabelle 1: Einstellung der Adresse des MCP23017

Praktische Umsetzung

Nach dem Schaltplan wollen wir uns nun den Verdrahtungsplan ansehen. Dann geht es mit dem Aufbau weiter. Wie immer stehen Layout-Daten zum Download verfügbar. Es handelt sich um eine doppelseitige Leiterplatte, die nach dem Ätzen und Bohren bestückt wird. Es handelt sich nur um wenige Komponenten (ohne Ausnahme Through-Hole für diejenigen unter uns, die keine SMD-Fans sind). Zunächst werden die Widerstände eingesetzt und gelötet, dann kommt der Sockel (mit der Kerbe Richtung C1) und der DIP-Switch (mit Switch 1 nach links zeigend).

Schließlich fügen Sie die 4-polige Leiste mit der Aufschrift I²C in die entsprechenden Löcher ein und verlöten sie. Auf den gegenüberliegenden Seiten der Platine löten Sie die zwei 12-poligen Stiftleisten ein. Damit können wir Sie auf einem Breadboard montieren (um sie mit dem Arduino über klassische Jumperkabel zu verbinden) oder auf andere Platinen stecken. Nach dem Abschluss aller Lötarbeiten setzen Sie den MCP23017 in den Sockel ein. Hierbei unbedingt beachten, das die Kerbe in Richtung von C1 zeigt (wie im Montageplan zu sehen). Damit ist das Breakout-Board bereit für Experimente oder Prototypen.

230469-002-94-ORIGINAL-fig. 2.png
Bild 3: Verdrahtungsplan für die Applikation, bei der wir Relais über Taster steuern
Abonnieren
Tag-Benachrichtigung zu Arduino jetzt abonnieren!

Nun kommt die Anwendung mit dem Arduino

Unser Breakout-Board wurde für den Anschluss an einen Mikrocontroller entwickelt. I/O-Expander werden typischerweise an Geräten verwendet, die über einen I²C-Bus verfügen. Da Arduino diesen Bus unterstützt, laden Sie den Beispiecode für den I/O des MCP23017 herunter, damit Sie ihn über die IDE auf Ihr Board schreiben können Mit diesem Sketch wird Port A als Ausgang angesprochen, wobei die Steuerung über Port B als Eingang erfolgt. Am Ausgang haben wir ein Relais-Board angeschlossen, welches mit seinen acht Steuerleitungen (und GND/+5V) an unser Board angeschlossen wird. Ein weiteres Board mit acht Tastern (NO) ist an Port B angeschlossen. Um den Beispielcode zu nutzen, müssen alle Komponenten wie in Bild 3 gezeigt, angeschlossen werden. Bild 4 zei erfügen, wurden die internen Pull-Up-Widerstände des MCP23017 aktiviert. Dadurch erhalten wir unterscheidbare Eingangszustände.

Listing 1 zeigt einen einfachen Arduino-Sketch, der unter Zuhilfenahme der Adafruit-Bibliothek erstellt wurde:

#include <Adafruit_MCP23X17.h>.
#include <Adafruit_MCP23X17.h>
Adafruit_MCP23X17 mcp;
int i = 0;
int OUT[] = {7,6,5,4,3,2,1,0};   //Represents MCP23017 PIN (A7...A0)
int IN[] = {8,9,10,11,12,13,14,15}; //Represents MCP23017 PIN (B0...B7)
int STATO[] = {0,0,0,0,0,0,0,0}; ◦ //For each output, every toggle the status is being saved

void setup()
{
Serial.begin(9600);
Serial.println("MCP23017 INPUT/OUTPUT");
if (!mcp.begin_I2C(0x20)) //0x20 is MCP23017's address with A0=A1=A2 > ON(GND)
{
Serial.println("MCP Error!"); //If MCP is not found, the error is visualized
while (1);
}
//bank A Pin set as outputs and B bank as inputs
//The STATO variable to 0 to indicate idling outputs
for (i=0; i<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<8; i=i+1)
{
//If button pressed or output not activated, I activate it
if ((mcp.digitalRead(IN[i])==0) && (STATO[i]==0))
{
STATO[i] = 1;
Testo_Debug = "Pulsante" + String(i+1) + "premuto";
Serial.println(Testo_Debug);
mcp.digitalWrite(OUT[i], HIGH);
}
//If button released and output is active, I deactivate it
if ((mcp.digitalRead(IN[i])==1) && (STATO[i]==1))
{
STATO[i] = 0;
Testo_Debug = "Pulsante" + String(i+1) + "rilasciato";
Serial.println(Testo_Debug);
mcp.digitalWrite(OUT[i], LOW);
 }
}
delay(10);
}

Bevor wir den Code in den Programmspeicher unseres Arduino-Boards laden, ist es wichtig, die Bibliothek von Adafruit herunterzuladen und sie mit dem in der IDE enthaltenen Bibliotheksmanager zu installieren. Oder Sie entpacken den Inhalt der ZIP-Datei und kopieren dann den gesamten Ordner Adafruit_MCP23017_Arduino_Library in das Bibliotheksverzeichnis zu kopieren. Dieses befindet sich normalerweise im Betriebssystem unter dem Pfad Documents\Arduino\libraries. Nachdem die Bibliothek geladen wurde, reicht es aus, unseren Beispielcode zu laden und ihn in das Board zu laden, nachdem der richtige COM-Port im Menü Tools der IDE ausgewählt wurde.

Im Code wird ein Byte mit dem Zustand der Taster über das MCP23017 angefragt. Die empfangenen Daten werden verarbeitet und in das Ausgaberegister geschrieben. Bis zum nächsten Refresh wird Port A mit den Daten gesetzt. Um mit dem IC kommunizieren zu können, müssen die DIP-Schalter richtig eingestellt sein. In der Software ist die Basis-Adresse 0x20 eingestellt. Dafür müssen die Adress-Leitungen A0, A1 und A2 auf Masse gezogen werden. Die Adresse des Breakout-Boards kann gemäß Tabelle 1 geändert werden – muss dann aber natürlich auch im Sketch angepasst werden.

Breakout board article: The hardware for testing the example sketch.
Bild 4: Die Hardware zum Test des Sketches

Bestückungsliste

  • Widerstände R1-R6: 4.7 kΩ
  • Kondensator C1: 100nF, keramisch
  • Halbleiter U1: Microchip MCP23017-E/SP
  • Verschiedene: SW1 3-Pin Dip-Switch 14-Pin DIL-Sockel, 2 × 12-Pin Header, male 1 × 4-Pin Header, male, 1 × Leiterplatte (siehe Text)

Anmerkung der Redaktion: Dieses Projekt erschien ursprünglich in Elettronica IN