ESP-01 Porterweiterung

Über den Beitrag

In meinem letzten Beitrag hatte ich über die Programmierung des ESP-01 Moduls geschrieben. Oft liest man, dass dieses Modul zwei GPIOs hat. Es sind aber vier, da man auch TX und RX als GPIO1 bzw. GPIO3 ansprechen kann. Trotzdem kann das für viele Projekte knapp werden. Ist das der Fall, dann ist es sicherlich die einfachste Möglichkeit auf den großen Bruder, den ESP-12, auszuweichen. Alternativ, z.B. wenn das auch nicht reichen würde, kann man zu den zahlreichen Möglichkeiten der ESP-01 Porterweiterung greifen. Drei davon möchte ich in diesem Beitrag vorstellen:

  • der I2C 16-Bit I/O Expander MCP23017 
  • der I2C 8-Bit I/O Expander PCF8574
  • das Schieberegister 74HC595

Die ersten beiden werden über I2C angesprochen und benötigen deshalb zwei GPIOS. Für das Schieberegister werden drei GPIOs benötigt.

In einem separaten Beitrag werde ich zeigen, wie man einen Counter IC als Porterweiterung „missbraucht“.

Der MCP23017

Der MCP23017 ist von den drei Bauteilen mit Abstand am vielseitigsten verwendbar. Für den „normalen“ Breadboard- und Rasterplatinenbastler empfiehlt sich die Ausführung MCP23017-E/SP. Man kann diesen Baustein mit seinen 28 Beinchen bei Conrad, Reichelt und Co für ca. einen Euro das Stück bekommen.

Der MCP23017 besitzt zwei Ports (A und B) mit je acht programmierbaren Ein-/Ausgängen. Er bietet darüber hinaus umfangreiche Möglichkeiten zur Interruptprogrammierung, auf die ich in diesem Beitrag allerdings nicht im Detail eingehen werden. Das werde ich in einem separaten Beitrag nur über dieses interessante Bauteil nachholen. 

Der MCP23017 ist für Spannungen zwischen 1.8 und 5.5 Volt ausgelegt. Im Standbymodus verbraucht er maximal 1µA. 

Neben dem MCP23017 gibt es noch den MCP23016, MCP23018 und den MCP23008. Letzterer ist im Grunde der kleine Bruder des MCP23017 mit nur acht Ein-/Ausgängen. Der MCP23016 und der MCP23018 haben wie der MCP23017 sechzehn Ein-/Ausgänge. Ich würde den MCP23016 nicht empfehlen, da er komplexer zu beschalten ist und dabei keine Vorteile bietet. Der MCP23018 wiederum ist nicht so weit verbreitet und deswegen stelle ich hier den MCP23017 vor. Eine kompakte Zusammenfassung der Unterschiede der MCP23xxx Familienmitglieder findet ihr hier.

Und hier findet ihr ein Datenblatt zum MCP23017.

Die Pinbelegung

Pinout des MCP23017
Pinout des MCP23017

Neben den 16 I/O Pins, den Pins SDA und SCL für die I2C Kommunikation und den Pins für die Spannungsversorgung besitzt der MCP23017 folgende Ein- bzw. Ausgänge:

  • A0, A1, A2: Adresspins
  • RESET: low-aktiver Resetpin
  • INTA, INTB: Interruptausgänge für PORT A und B, zusammenschaltbar

Die Schaltung für die Steuerung durch ESP-01

Als einfaches Anwendungsbeispiel für die ESP-01 Porterweiterung nehme ich das An- und Ausschalten von sechzehn LEDs. Um das Schema nicht zu unübersichtlich werden zu lassen, habe ich nur einen kleinen Teil der Leitungen zu den LEDs eingezeichnet. Auch auf die Stromversorgung von 3.3 Volt habe ich im Schaltplan verzichtet. Den Upload von Sketchen auf das ESP-01 Modul habe ich in meinem letzten Beitrag erklärt und gehe deswegen nicht mehr darauf ein. Die wesentlichen Punkte der Schaltung sind: 

  • CH_PD des ESP-01 an 3.3 V
  • Resetpin des ESP-01 über Taster an GND
  • GPIO0 an SDA
  • GPIO2 and SCL
  • Die Adresspins an GND –> Adresse ist dann 0x20
    •  das Schema ist 1 0 0 A2 A1 A0
    •  hier also: 1 0 0 0 0 0 = 32 = 0x20
  • Resetpin des MCP23017 an 3.3 V
  • VSS des MCP23017 an GND
  • VDD des MCP23017 an 3.3 V

 

Schaltplan für die ESP-01 Portwerweiterung mit dem MCP23017
ESP-01 Porterweiterung mit dem MCP23107

Hinweis: Man könnte versucht sein das ESP-01 Modul und den MCP23017 separat mit Strom zu versorgen, insbesondere wenn man an den MCP23107 Bauteile hängt, die 5 Volt benötigen. Das Problem ist dabei, dass ein HIGH Signal an SDA/SCL mindestens 80 Prozent von VDD betragen muss. Da bin ich schon drauf reingefallen. Der Fehler war schwer zu finden weil es nicht gar nicht klappte sondern nur unzuverlässig. Will man so etwas realisieren, muss noch einen Level Konverter in die beiden Kommunikationsleitungen einbauen. 

Tabelle mit Mindestspannungen für HIGH Signale am MCP23017
Mindestspannung für HIGH Signale am MCP23017

Die MCP23017 Bibliothek

Der MCP23017 hat eine ganze Menge an Registern, die ihn sehr flexibel machen, was aber auch die Programmierung etwas aufwendiger gestaltet. Ich habe deswegen eine Bibliothek geschrieben, die ihr hier auf Github herunterladen könnt. Wie schon erwähnt werde ich noch einen Beitrag nur über den MCP23017 bringen und dort werde ich dann auch die Bibliothek im Detail erklären. Hier beschränke ich mich auf das An- und Abschalten von Ausgängen. 

Im folgenden Beispielsketch wird zunächst ein MCP23017 Objekt erzeugt. Die Funktionalität des Resets sparen wir uns hier. Mit Wire.begin(0,2); werden GPIO0 und GPIO2 als SDA bzw. SCL festgelegt. myMCP.Init(); legt einige Registerinhalte fest. Die Anweisung myMCP.setPinMode() legt – vergleichbar mit der Arduino pinMode Anweisung – fest, ob die Pins als Input oder Output fungieren. Mit myMCP.setPort(); werden die HIGH/LOW Zustände für einen ganzen Port übergeben. myMCP.setPin(); schaltet einzelne Pins. myMCP.togglePin(); schaltet von HIGH auf LOW bzw. umgekehrt. 

#define MCP_ADDRESS 0x20 // (A2/A1/A0 = LOW) 
#include <Wire.h>
#include <MCP23017.h>  
MCP23017 myMCP(MCP_ADDRESS,3); // 3= ResetPin, nicht weiter wichtig hier 

void setup(){ 
  Wire.begin(0,2); //SDA = GPIO0 / SCL = GPIO2
  myMCP.Init();
  myMCP.setPortMode(B11111111,A);
  myMCP.setPortMode(B11111111,B);
  myMCP.setPort(B00000000, A); // alles auf LOW 
  myMCP.setPort(B00000000, B); delay(1000); 
} 

void loop(){ 
  myMCP.setPin(1,A,ON); 
  delay(1000); 
  myMCP.setPin(1,B,ON); 
  delay(1000); 
  myMCP.setPin(1,A,OFF); 
  delay(1000); 
  myMCP.setPin(1,B,OFF); 
  delay(1000); 
  myMCP.setPort(B10101010,B00011000,A,B); 
  delay(1000); 
  for(int i=0; i<=7; i++){ 
    myMCP.togglePin(i,A); 
  } 
  delay(1000); 
  myMCP.setPort(B00000000, A); 
  myMCP.setPort(B00000000, B); 
  delay(1000); 
}

 

Der PCF8574

Der PCF8574 ist wie der MCP23017 ein über I2C zu steuernder I/O Expander mit Interruptausgang. Allerdings hat er nur acht Ein- bzw. Ausgänge, einen einzigen Interruptausgang und verfügt nicht über die vielen Optionen des MCP23017. Dafür ist er sehr leicht auch ohne spezielle Bibliothek oder langes Studium von Registern ansteuerbar. 

Es gibt den PCF8574 in verschiedenen Ausfertigungen, z.B. die DIP16 Varianten PCF8574P, PCF8574N oder PCF8574AN. Diese haben dieselbe Pinbelegung und unterscheiden sich nach meinen Recherchen im Wesentlichen in den I2C Adressen. Ich habe für diesen Beitrag die „N“-Variante verwendet. 

Der PCF8574 kann in einem Bereich von 2,5 bis 6 Volt betrieben werden. Ein Datenblatt gibt es z.B. hier.

Eine Besonderheit des PCF8574 ist, dass die Pins im HIGH Zustand nur einige hundert Mikroampere Strom liefern. Will man z.B. LEDs steuern, so muss man die Pins als Eingang (LOW) verwenden. Das wird weiter unten bei der Schaltung und dem Sketch klarer werden. 

Die Pinbelegung

Pinout des PCF8574
Pinout des PCF8574

Die Adresse wird wie beim MCP23017 durch die Beschaltung der Adresspins A0, A1 und A2 nach dem Schema „1 0 0 A2 A1 A0“ festgelegt. Zumindest gilt das für die von mir eingesetzte Variante N. P0 bis P7 sind die Ein-/Ausgänge, INT ist der low-aktive Interruptausgang und der Rest sollte klar sein. 

Schaltung für die Steuerung durch den ESP-01

Auch hier nehme ich als Anwendungsbeispiel für die ESP-01 Porterweiterung die Steuerung von LEDs. Der fundamentale Unterschied zum MCP23017 ist die Stromrichtung: er fließt über die LEDs in den PCF8574 nach GND. Ansonsten gilt noch zu beachten:

  • CH_PD des ESP-01 an 3.3 V
  • Resetpin des ESP-01 über Taster an GND
  • GPIO0 an SDA
  • GPIO2 and SCL
  • Adresspins an LOW –> Adresse: 0x20
  • Die SDA und SCL Leitungen brauchen einen Pull-up (10 kOhm)
  • Nutzt man den Interruptausgang, dann braucht auch diese Leitung einen Pull-up

Hinweis: auch beim PCF8574 muss ein HIGH Signal ein gewisses Level überschreiten, um als solches erkannt zu werden (Vmin,HIGH = 0,7 x VDD). Also aufgepasst wenn ihr am PCF8574 mit 5 Volt arbeiten wollt und einen 3.3V ESP-01 verwendet. Das geht nur mit einem Levelkonverter. 

 

ESP-01 Porterweiterung mit dem PCF8574 - Schaltplan
ESP-01 Porterweiterung mit dem PCF8574

Ein einfacher Beispielsketch

Zunächst einmal muss man umdenken: nur wenn ein Pin im LOW Zustand ist, kann gemäß der oben abgebildeten Schaltung Strom über ihn fließen. Sprich: 0 –> LED an, 1 –> LED aus. Im Beispielsketch wird damit ein bisschen gespielt. In der Schleife gehen alle LEDs der Reihe nach an und wieder aus. Wer mit Bitoperationen nicht vertraut ist, mag sich über die Zeile state &= ~(1<<i); wundern. Wenn „i“ z.B. gleich 3 ist, heißt das: verschiebe die 1 um 3 Stellen nach links (00000100), führe ein bitweise Negation durch (11111011) und führe ein logisches UND aus (11111011).

Wichtig ist, dass man bei Verwendung des ESP-01 bei Wire.begin() die Pinnummern für SDA und SCL übergibt. 

Auch wenn im Sketch kein Read durchgeführt wird, habe ich der Vollständigkeit halber eine Readfunktion integriert, welche den Zustand der Pins abfragt.  

#include <Wire.h> 
#define PCF8574N 0x20 // Adresse, wenn A0/A1/A2 = LOW 

void setup(){ 
  Wire.begin(0,2); 
} 

void loop(){ 
  switchPCF8574N(B11111111); 
  delay(1000); 
  switchPCF8574N(B10101010); 
  delay(1000); 
  switchPCF8574N(B01010101); 
  delay(1000); 
  for(int i=0; i<=7; i++){ 
    byte state = B11111111; 
    state &= ~(1<<i); 
    switchPCF8574N(state); 
    delay(500); 
    } 
  } 
  
void switchPCF8574N(byte datenByte){ 
  Wire.beginTransmission(PCF8574N); 
  Wire.write(datenByte); 
  Wire.endTransmission(); 
}

byte readPCF8574N(){
  byte data;
  Wire.requestFrom(PCF8574N,1);
  data = Wire.read();
  return data;
}

 

Das Schieberegister 74HC595

Das Schieberegister unterscheidet sich von den beiden anderen Bauteilen zur ESP-01 Porterweiterung im Wesentlichen durch:

  • es hat acht „nur-Ausgänge“
  • kein Interruptausgang
  • es benötigt drei Leitungen zur Ansteuerung 
  • der Microcontroller muss über kein spezielles Bussystem wie I2C oder SPI verfügen 
    • das macht ihn z.B. für den ATtiny85 sehr interessant

Auch das Schieberegister 74HC595 gibt es mit unterschiedlichen Bezeichnungen. Dabei ist es egal, ob man einen „74HC595“, einen „M74HC595“ oder einen „SN74HC595“ hat. Wichtiger ist: wenn hinten noch ein „N“ dranhängt, dann handelt es sich um die DIP16 Variante.  

Der 74HC595 lässt sich in einem Bereich von 2 bis 6 Volt betreiben. Ein Datenblatt gibt es zum Beispiel hier.

Die Pinbelegung

Pinout des 74HC595
Pinout des 74HC595

Eine detaillierte Erklärung der Funktionsweise eines Schieberegisters würde den Rahmen dieses Beitrages sprengen. Eine sehr gute Darstellung habe ich hier gefunden. Nur soviel: der Name des Bauteils rührt von seiner Funktionsweise her, nämlich dass die zu übertragenden Daten bitweise in das Shift Register geschoben werden. Jedes ankommende Bit verschiebt die schon Vorhandenen um eine Stelle (wie ein Magazin, das man mit Patronen befüllt – Entschuldigung für diesen martialischen Vergleich). Vom Shift Register wird das vollständige Datenbyte dann „in einem Rutsch“, also parallel, in das Storage Register (Ausgangsregister) übertragen.

Die Pins haben folgende Funktion:

  • Q0….Q7 sind die Ausgänge
  • DS = Datenpin; hierüber werden die Daten ins Shift Register geschoben
  • SHCP = Shift Register Clock Pin; hier wird der Takt für das Weiterschieben ins Shift Register vorgegeben
  • STCP = Storage Register Clock Pin; hier wird der Takt für das Übertragen in das Storage Register vorgegeben
  • OE = Output Enable (low aktiv); aktiviert die Ausgänge Q0…Q7
  • MR = Master Reset (low aktiv); löst einen Reset aus
  • Q7S = Serieller Output; werden mehr als 8 Bit in das Shift Register geschoben, fallen sie hier quasi wieder raus
    • wird DS eines weiteren 74HC595 hier angeschlossen, kann man so zwei dieser Bausteine (oder mehr) hintereinanderschalten. 

 

Schaltung für die Steuerung durch den ESP-01

Auch hier nehme ich wieder das einfache Beispiel einer LED Ansteuerung. Dabei möchte ich aber auch gleich zeigen, wie man zwei 74HC595 hintereinander schaltet. Die wesentliche Punkte sind:

  • CH_PD des ESP-01 an 3.3 V
  • Resetpin des ESP-01 über Taster GND
  • GPIO0 an SHCP beider MCP23017
  • GPIO2 an STCP beider MCP23017
  • GPIO1 (TX) an DS eines MCP23017
  • MR an 3.3 Volt, OE an GND
  • Q7S des ersten 74HC595 an DS des zweiten 74HC595

 

ESP-01 Porterweiterung mit dem 74HC595.
ESP-01 Porterweiterung mit dem 74HC595 (nicht alle Leitungen zu den LEDs sind eingezeichnet)

Ein einfacher Beispielsketch

Der Beispielsketch zeigt wie die Ansteuerung funktioniert. Der Zustand der 16 Ausgänge wird als 16 Bit Zahl (word) dargestellt. „0“ ist LOW, „1“ ist HIGH. Mit den zwei „shiftOut“ Befehlen überträgt man zunächst das untere und dann das obere Byte der 16 Bit Zahl. Um die 16 Bit Zahl in zwei Bytes aufzuteilen, kommen wieder Bitoperatoren zum Einsatz. pinData&255 schneidet das obere Byte ab, pinData>>8 isoliert das obere Byte. 

Ich habe „LSBFIRST“ als Parameter im „shiftOut“ Befehl gewählt, das heißt die bitweise Übertragung beginnt mit dem untersten Bit (LSB = least significant bit). Die Alternative ist „MSBFIRST“ (MSB = most significant bit). Damit kann man spielen, wenn die Anordnung der LEDs nicht so ist, wie man sie haben will. Wenn der Storage Pin, der an STCP liegt, von LOW auf HIGH geht, werden die Daten vom Shift Register in das Storage Register übertragen und die LEDs werden entsprechend geschaltet. 

int clockPin = 0; //SHCP
int storagePin = 2; //STCP
int dataPin = 1; //DS

void setup() {
  pinMode(clockPin, OUTPUT);
  pinMode(storagePin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  sendOutData(0b0000000000000000);
  delay(1000);
  sendOutData(0b1110101010101010);
}

void loop() {
}

void sendOutData(word pinData){
  digitalWrite(storagePin, LOW);
  shiftOut(dataPin, clockPin, LSBFIRST, (pinData&255));
  shiftOut(dataPin, clockPin, LSBFIRST, (pinData>>8)); 
  digitalWrite(storagePin, HIGH);    
}

 

Ausblick

So, das war ein kleiner Überblick über die gängigsten Methoden der ESP-01 Porterweiterung. In einem zukünftigen Beitrag gehe ich nochmal detaillierter auf den MCP23017 mit seinen vielen Funktionen ein. Und in einem weiteren Beitrag über Counter ICs werde ich nochmal auf die Porterweiterung zurückkommen.  

Schreibe einen Kommentar

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