ESP32

Liebe Freunde,

auf dieser Projektseite liefere ich euch ein paar interessante Details zum ESP32-Modul von Espressif.
Ich gehe im Speziellen auf das ESP32-Pico-Board ein, das der kleinere Bruder des ESP32 ist.

Hier eine kleine Übersicht über die Programmier-Themen auf dieser Seite:

Dieser Chip stellt eine logische Weiterentwicklung des ESP8266 dar. Mehr SRAM-Speicher, höhere CPU-Geschwindigkeit, Bluetooth-Kommunikation, eine größere Anzahl an Schnittstellen-Pin (GPIOs), Touch-Sensorik, A/D- bzw. D/A-Wandlung sind nur einige der Highlights des ESP32. Auf der folgenden Abbildung ist ein Entwicklerboard zu sehen, das über diesen ESP32-Chip verfügt.

Es handelt sich um das ESP32 Pico-Board V4. Werfen wir einen Blick auf das Board und sehen, über welche Komponenten die kleine Platine verfügt. Die folgende Abbildung ist mit den Beschriftungen der wichtigsten Bauteile versehen, die uns im Moment interessieren.

Welche Funktionen besitzen die hier markierten Bauteile:

  • Reset: Es handelt sich um einen Miktotaster, der mit der Beschriftung EN versehen ist und beim Drücken ein Reset des Systems durchführt. Es existiert zudem ein Pin mit der gleichen Bezeichnung, womit ein Reset über das Anlegen von Masse (LOW-Aktiv) ausgelöst werden kann
  • Boot: Auch hier haben wir es mit einem Mikrotaster zu tun, der die Beschriftung BOOT besitzt und in Verbindung mit dem EN-Taster für das Laden einer Firmware genutzt werden kann. Das ist für uns jedoch erst einmal nicht von Belang, denn das Hochladen der Firmware, die später auf das Board gespeichert werden soll, wird von der Arduino-Entwicklungsumgebung, die bei uns zum Einsatz kommt, gesteuert
  • Power-LED: Die kleine LED leuchtet, wenn das Board via USB oder externer Quelle mit Spannung versehen wurde
  • Antenne: Sie ist für die drahtlose Kommunikation erforderlich
  • ESP32: Es handelt sich um den Mikrocontroller ESP32-PICO D4
  • LDO: Da das Board respektive der ESP32 mit 3,3V betrieben werden, ist eine Spannungsregulierung von 5V des USB-Anschlusses auf 3,3V erforderlich, was über den sogenannten Low Dropout Voltage Regulator (LDO) erfolgt
  • USB-UART: Dieser Chip stellt die USB zu UART Kommunikation bereit, was eine Bridge zwischen USB und serieller Kommunikation ermöglicht. Die Transferrate beträgt 1 Mbps
  • USB: Hier handelt es sich um eine USB-Micro-Buchse für USB 2.0 zur Verbindung des Boards zum Computer

Die Verbindung der einzelnen Komponenten untereinander ist auf dem folgenden funktionellen Blockdiagramm gut zu erkennen.

Wir sollten jetzt einen Blick auf die einzelnen Pins des ESP-32 Pico Boards werfen, denn hier gibt es einiges zu beachten. Die folgende Abbildung zeigt die für unsere Belange bzw. bei der Verwendung des Elektor-Kits wichtigen Pins mit ihren Funktionen wie z.B. Spannungsversorgung, IO, ADC, I2C, und SPI.

Wir sehen, dass einige Pins über zwei Funktionen verfügen, die je nach Programmierung aktiviert werden können. Es gibt primäre und alternative Funktionen. Auf diese Weise wurde die Anzahl der Pins auf dem Board reduziert und dieses so klein wie möglich gehalten. Damit die Informationen gerade für einen Einsteiger nicht erschlagend wirken, habe ich nur die für uns im Moment wichtigsten Details in die Abbildung eingetragen. Viele der Pins verfügen über weitere Funktionalitäten, die für uns jedoch erst einmal nebensächlich sind. Wer sich dennoch dafür interessiert, kann sich unter der folgenden Internetadresse schlau machen.

https://esp-idf.readthedocs.io/en/latest/get-started/get-started-pico-kit.html

Es ist wichtig zu verstehen, dass das Board bzw. der ESP32-Mikrocontroller mit einer Betriebsspannung von 3,3V arbeitet. Alles, was darüber liegt, führt unweigerlich dazu, dass das Board zerstört wird. Die Betriebsspannung von 5V, die also z.B. beim Mikrocontrollerboard Arduino-Uno üblich ist, darf hier nicht zur Anwendung kommen.

Um mit der Außenwelt zu kommunizieren, verfügt das gezeigte Entwicklerboard über die schon genannten IO-Pins, wobei IO für Input/Output steht. Es können also einerseits Informationen an das Board geliefert und andererseits auch vom Board versendet werden. Auf der nachfolgenden Abbildung sehen wir ein einfaches Beispiel für diese beiden Datenflussrichtungen.

Der Pin mit der Bezeichnung IO21 wird als Ausgang genutzt und steuert über einen Vorwiderstand eine Leuchtdiode – auch LED genannt – an. In der entgegengesetzten Richtung wird der Pin mit der Bezeichnung IO22 genutzt, der zur Abfrage eines Schalters inklusive Pulldown-Widerstand als Eingang arbeitet. Wie das Ganze im Detail noch über die Programmierung konfiguriert werden muss, sehen wir später. Der Aufbau von elektronischen Schaltungen kann über verschiedene Ansätze erfolgen, wobei die Verwendung eines Steckbrettes – auch Breadboard genannt – die gängigste Variante ist. Auf der folgenden Abbildung sehen wir ein derartiges Breadboard mit unserem ESP32 Pico-Board und einigen Bauteilen zur Ansteuerung einer LED.

Die elektrischen Verbindungen zwischen ESP32 Pico-Board und den Bauteilen werden durch sogenannte flexible Steckbrücken hergestellt. Sie werden einfach in die kleinen Buchsen des Breadboards gesteckt und stellen damit eine entsprechende Verbindung her.

Das ESP32 Pico Discovery-Board

Eine weitere Variante besteht in der Verwendung des von mir entwickelten ESP32 Pico Discovery-Boards, was die ganze Sache mit der Herstellung der Verbindungen zu den unterschiedlichsten Bauteilen ungemein erleichtert. Mit Board-Bausatz zum Selberbau ist es möglich, bequem, zeitsparend und umfassend das ESP32 Pico-Board systematisch zu entdecken. Alle für einen geeigneten Einstieg erforderlichen Komponenten befinden sich an einem Ort und müssen nicht erst aus diversen Schubladen und Kisten zusammengesucht werden. Auf der folgenden Abbildung sehen wir die gleiche Schaltung, jedoch auf dem ESP32 Pico-Discovery-Board umgesetzt.

Das ESP32 Pico-Discovery-Board verfügt schon über diverse elektrische bzw. elektronische Grundelemente wie:

  • Eine Halterung für das ESP32 Pico-Board
  • ESP32 Pin-Schablone mit Buchsen zur besseren Orientierung und Verkabelung
  • 10 LEDs mit passenden Vorwiderständen und Anschlussbuchsen
  • 5 Mikrotaster mit entsprechenden Pulldown-Widerständen und Anschlussbuchsen
  • 1 Potentiometer
  • Eine Siebensegmentanzeige mit passenden Vorwiderständen und Anschlussbuchsen
  • Ein LC-Display zur Ansteuerung über den I2C-Bus und Anschlussbuchsen
  • Power-Rails für 3,3V und GND
  • Ein kleines Breadboard zur Aufnahme von weiteren elektrischen bzw. elektronischen Bauteilen

Im folgenden Video stelle ich das ESP32 Pico-Discovery-Board kurz vor.

Die Installation der Entwicklungsumgebung

Im DIY-Bereich ist der Arduino sehr verbreitet und mit der Arduino-Entwicklungsumgebung können nicht nur die hauseigenen Produkte von Arduino programmiert werden, sondern auch andere Boards. Somit ist es möglich, durch eine entsprechende Erweiterung auch das ESP32-Modul mit einzubinden. Es werden die gängigen Betriebssysteme wie Windows, Mac OSX und Linux unterstützt. Die Arduino-Entwicklungsumgebung kann unter der folgenden Internetadresse heruntergeladen und dann installiert werden.

https://www.arduino.cc/en/Main/Software

Im Anschluss muss der Arduino-Core für die ESP32-Unterstützung eingebunden werden. Die erforderlichen Schritte dazu sind unter der nachfolgenden Internetadresse nachzulesen.

https://github.com/espressif/arduino-esp32

Der Zeitaufwand für die Installation der Arduino-Entwicklungsumgebung beträgt ca. 5 Minuten, der für den Arduino-Core zur ESP32-Unterstützung ca. 30 Minuten. Wenn man sich strikt an die Vorgaben hält, ist das absolut kein Hexenwerk.

Ein paar grundlegende Programme

Wollen wir uns nun ein paar grundlegenden Programmen zuwenden, die mit der Arduino-Entwicklungsumgebung geschrieben wurden.

Ein GPIO als Eingang

Wir wollen einen GPIO-Pin als Eingang nutzen, was bedeutet, dass er von außen auf Signale in irgendeiner Weise reagieren soll. Die einfachste Art, einen Eingang zu nutzen, besteht im Anschluss eines Tasters oder Schalters. Auf der folgenden Abbildung sehen wir eine Schaltung, bei der ein GPIO-Pin mit einem Taster verbunden wurde, der beim Schließen 3,3V an diesen legt.

Es ist hier wieder darauf zu achten, dass nur 3,3V und nicht 5V beim Betätigen des Tasters an den betreffenden GPIO-Pin geleitet werden. Zudem befindet sich ein Widerstand in dieser Schaltung, der als sogenannter Pulldown-Widerstand arbeitet. In digitalen Schaltkreisen müssen Eingangs-Pins mit einem definierten Pegel versehen werden, da andernfalls äußere Störeinflüsse wie z.B. statische Aufladungen zu unvorhersehbaren Ereignissen führen können. Der Eingangspegel ist einmal HIGH und ein paar Millisekunden später LOW. und das in einem ständigen unbestimmbaren Wechsel. Ist der Taster nicht gedrückt, würde ein offener Eingang quasi in der Luft hängen und die beschriebenen Probleme bereiten. Durch den Einsatz eines Pulldown-Widerstandes von 10KΩ wird der Eingangsping IO22 bei offenem Taster gegen Masse gezogen. Wird der Taster gedrückt, fallen über diesem Widerstand die 3,3V der Betriebsspannung ab und liegen am IO22-Pin an. Der Code zur Abfrage des Tasterstatus schaut wie folgt aus:

#define Taster 22
 	 
void setup() {	 	 
  pinMode(Taster, INPUT); // Pin als Input	 	 
  Serial.begin(9600);     // Serial-Monitor	 	 
}	 	 

void loop() {	 	 
  byte tasterStatus = digitalRead(Taster);	 	 
  if(tasterStatus == HIGH)	 	 
    Serial.println("Taster gedrückt");	 	 
  else	 	 
    Serial.println("Taster nicht gedrückt");	 	 
  delay(500); // Kurze Pause	 	 
}

In Zeile 1 definieren wir den Taster-Pin, der später im Programm verwendet wird. Innerhalb der setup-Funktion, die einmalig nach Programmstart zur Ausführung kommt, wird in Zeile 4 über den Aufruf der pinMode-Funktion dieser Pin über das Schlüsselwort INPUT als Eingang konfiguriert. Für die Nutzung des Serial-Monitors muss dieser in Zeile 5 konfiguriert werden. Ich habe mich über den Aufruf der Serial.begin-Funktion für eine Übertragungsrate von 9600 Baud entschieden. Diese kann, je nach Wunsch, auch über die Liste mit den gängigen Baudraten, am unteren Ende des Serial-Monitors angepasst werden.

Innerhalb der loop-Funktion, die kontinuierlich zur Ausführung kommt, wird in Zeile 9 der Variablen tasterStatus der Status des Tasters über den Aufruf der digitalRead-Funktion zugewiesen. Über eine if-else Anweisung in den Zeilen 10 bis 13 kommt es zur Auswertung des Status einer entsprechenden Meldung über die Serial.println-Funktionen an den Serial-Monitor. Zeile 14 sorgt über den Aufruf der delay-Funktion für eine kurze Pause von 500ms. Das Fenster des Serial-Monitors wird über das kleine Symbol in der rechten oberen Ecke der Arduino-Entwicklungsumgebung geöffnet.

Die Ausgabe innerhalb des Serial-Monitors schaut dann je nach Drücken des Tasters wie folgt aus.

Der in der Schaltung vorhandene Pulldown-Widerstand ist auf dem ESP32 Discovery-Board schon in der Nähe der einzelnen Taster vorhanden und muss aus diesem Grund nicht mehr hinzugefügt werden. Falls dennoch einmal ein externer Taster zum Einsatz kommen sollte und gerade kein entsprechender Widerstand zur Hand sein ist, gibt es noch eine weitere Variante. Das ESP32-Mikrocontroller besitzt intern Pullup- bzw. Pulldown-Widerstände, über eine entsprechende Programmierung aktiviert werden können. Wir wollen im nächsten Beispiel einmal einen Pullup-Widerstand aktivieren und sehen, wie die Konfiguration ausschaut.

#define Taster 22

void setup() {
  pinMode(Taster, INPUT_PULLUP); // Pin als Input mit Pullup
  Serial.begin(9600); // Serial-Monitor
}

void loop() {
  byte tasterStatus = digitalRead(Taster);
  if(tasterStatus == LOW)
    Serial.println("Taster gedrückt");
  else
    Serial.println("Taster nicht gedrückt");
  delay(500); // Kurze Pause
}

In Zeile 4 wird bei der Konfiguration des GPIO-Pins statt INPUT der Modus INPUT_PULLUP gewählt. Eine weitere Anpassung des Codes ist erforderlich. In Zeile 10 wird nun für einen gedrückten Taster auf den Status LOW abgefragt. Warum ist das aber so? Die Antwort werden wir finden, in dem wir uns die Ansteuerung des Pins anschauen.

Wird der obere interne Pullup-Widerstand durch das Schlüsselwort INPUT_PULLUP aktiviert, wird die Betriebsspannung über diesen Widerstand an den Eingang des Prozessors geleitet. Um einen Statuswechsel zu bewirken, muss über einen externen Taster ein GND-Signal an den GPIO-Pin geleitet werden. Aus diesem Grund muss auch bei einem gedrückten Taster auf einen LOW-Pegel in Zeile 10 abgefragt werden. Hier nun der Schaltungsaufbau mit einem externen Taster.

Die Ausgabe des Taster-Status haben wir bisher immer mit dem Aufruf des Serial-Monitors kontrolliert. Das wollen wir gleich andern, denn auf dem ESP32 Pico-Discovery-Board befindet sich auch ein Anzeigeelement in Form eines LC-Displays – kurz LCD.

Ein GPIO als Ausgang

Die entgegengesetzte Datenflussrichtung ist natürlich ebenfalls möglich. Wir wollen einen GPIO-Pin als Ausgang konfigurieren und darüber eine Leuchtdiode mit entsprechendem Vorwiderstand ansteuern.

Die Leuchtdiode wird über den Vorwiderstand von 330Ω von IO21 angesteuert. In diesem Beispiel wollen wir die LED blinken lassen. Hier nun der Code zur Ansteuerung der LED.

#define LED 21

void setup() {
  pinMode(LED, OUTPUT); // Pin als Output
}

void loop() {
  digitalWrite(LED, HIGH);
  delay(1000);
  digitalWrite(LED, LOW);
  delay(1000);
}

Mithilfe des ESP32 Pico-Discovery-Boards geht die Sache wieder einfach von der Hand.

Kommen wir jetzt zu einem Thema, das eigentlich beide Datenflussrichtungen beinhaltet. Wir wollen einen Taster abfragen und dann den Status ausgeben. Der Status soll jedoch jetzt nicht im Serial-Monitor angezeigt werden, sondern im LC-Display des ESP32 Pico-Discovery-Boards. Das Interessante daran ist, dass die Ansteuerung des LC-Displays über ein Bus-System erfolgt. Was ist ein Bus-System und welches kommt hier zur Anwendung? Ein Bus stellt einen bestimmten Weg der Datenübertragung zwischen zwei oder mehreren Teilnehmern über einen gemeinsamen Übertragungsweg dar. Es gibt die unterschiedlichsten Bus-Systeme wie z.B. I2C oder SPI.

Die I2C-Unterstützung

Bleiben wir beim ersten Bus-System, dem I2C-Bus. I2C steht für Inter-Integrated Circuit und wird im Deutschen als I-Quadrat-C bezeichnet bzw. ausgesprochen. Da die Informationsübertragung über zwei Leitungen erfolgt, wird es auch TWI (Two-Wire-Interface) genannt. Unser LC-Display besitzt ein derartiges Interface, was die beiden Pins

  • SDA (Datenleitung)
  • SCL (Taktleitung)

zur Verfügung stellt. Werfen wir einen genaueren Blick auf das ESP32 Pico-Discovery-Board.

Ich habe es schon erwähnt, dass die GPIO-Pins mehrere Funktionen innehaben, was ja die Bezeichnung GPIO schon aussagt. Wir können die GPIO-Pins IO21 und IO22 nicht nur als digitale Ein- bzw. Ausgänge nutzen, sondern sie besitzen in unserem Fall eine sogenannte alternative Funktionalität für den I2C-Bus. Wie auf der Abbildung zu erkennen ist, habe ich das LC-Display mit diesen beiden Pins verbunden. Kommen wir jetzt zur Ansteuerung des Displays. Dazu ist eine besondere Library erforderlich, welche den I2C-Bus des Displays unterstützt. Sie kann unter der folgenden Internetadresse heruntergeladen werden.

https://funduino.de/nr-19-i%C2%B2c-display

Dort befinden sich auch weitere Informationen der Installation bzw. Nutzung der Library. Die eigentliche Unterstützung des I2C-Busses ist standardmäßig in der Arduino-Entwicklungsumgebung implementiert und erfolgt durch das Einbinden der Wire-Library. Für ein ordnungsgemäßes Funktionieren des I2C-Buses muss dieser mit Pullup-Widerständen versehen werden, die sich im Bereich zwischen 1KΩ und 4,7KΩ bewegen sollten. Die Schaltung schaut dann wie folgt aus.

Es sei erwähnt, dass der ESP32 intern über Pullup-Widerstände verfügt, die bei der Nutzung der I2C-Funktionalität über den Treiber automatisch aktiviert werden. Doch sind diese recht schwach und das Ganze funktioniert auch ohne zusätzliche Pullup-Widerstände, doch falls mehrere I2C-Geräte am Bus angeschlossen werden, ist es auf jeden Fall erforderlich, diese Pullup-Widerstände zu verwenden. Was wollen wir jetzt in unserem Beispiel erreichen? Es soll der Taster-Status im LC-Display zur Anzeige gebracht werden. Der Arduino-Code dazu schaut wie folgt aus.

#include <Wire.h> // Wire Bibliothek einbinden
#include <LiquidCrystal_I2C.h> // I2C Bibliothek einbinden
#define Taster 19 // Taster-Pin
LiquidCrystal_I2C lcd(0x27, 16, 2); // I2C-Adresse und Format festlegen

void setup() {
  pinMode(Taster, INPUT); // Pin als INPUT
  lcd.begin(); // Die Initialisierung des LCD
}

void loop() {
  byte tasterStatus = digitalRead(Taster); // Taster-Status lesen
  lcd.setCursor(0, 0); // Cursor auf Spalte, Zeile positionieren
  lcd.print("*ESP32 Pico-V4*");
  lcd.setCursor(0, 1); // Cursor auf Spalte, Zeile positionieren
  if(tasterStatus == HIGH)
    lcd.print("Taster: HIGH"); // lcd.print zeigt Text an
  else
    lcd.print("Taster: LOW "); // lcd.print zeigt Text an
}

Je nach Taster-Status ändert sich die Anzeige im LC-Display.

Und jetzt bei gedrücktem Taster:

Das LC-Display besitzt standardmäßig eine I2C-Adresse von 0x27 (Angabe in hexadezimal). Falls es einmal Probleme bei der Ansteuerung mit der LC-Display geben sollte, kann ein sogenannter I2C-Scanner verwendet werden, um zu sehen, ob ein I2C-Device vom System erkannt wird. Der Scanner ist unter der folgenden Internetadresse zu finden.

https://playground.arduino.cc/Main/I2cScanner

Wenn man die Schaltung ohne das ESP32 Pico-Discovery-Board aufbauen möchte, ist sicherlich der Schaltplan dazu hilfreich.

Ein Roulette-Spiel

Mit dem ESP32 kann man in Verbindung mit einem Port-Expander MCP23017 wunderbar ein Roulette-Spiel umsetzen.Natürlich ist der Port-Expander nicht unbedingt erforderlich, denn das ESP32-Board verfügt über genügend IO-Ports, doch die Realisierung mit dem MCP23017 hat einfach Spaß gemacht und kann hinsichtlich weiterer LEDs sehr einfach erweitert werden. Das folgende Video zeigt das Spiel in Aktion.

Nachfolgend ein Link zu Erklärungen der Befehle, die verwendet werden:

https://www.arduino.cc/reference/en/