Der WiFi Monitor überwacht die Erreichbarkeit eines Webservers und zeigt den Status mit einer bunten LED an.
Startseite

ESP8266 und ESP8285 WLAN Module

Mit Preisen ab 1,50 € sind diese Module eine sehr preisgünstige Netzwerk-Anbindung zum Basteln. Hier findest du eine Anleitung zum Einstieg, wie man damit Geräte baut und programmiert.

Die ESP8266 und ESP8285 Chips vom chinesischen Hersteller Espressif sind 32bit Mikrocontroller mit integrierter Wi-Fi Schnittstelle. Ihre Firmware basiert auf dem Lightweight IP stack von Adam Dunkels. Es werden zahlreiche handliche Module mit diesen Mikrochips verkauft.

Normalerweise werden die ESP-Module mit der AT-Firmware verkauft. Diese nimmt über eine serielle Schnittstelle Kommandos von einem anderen Mikrocontroller an. Man kann auch eigene Programme in die Module laden.

Datenblätter: ESP8266, ESP8285

Technische Daten

  1. Die minimale Spannung hängt vom Flash Speicher ab. 2,8 Volt gehen immer. Manche Module laufen sogar noch mit 2,5 Volt.
  2. Wenn der Funk-Kanal frei ist. Auf stark genutzten Funk-Kanälen sind Latenzen bis 200 ms normal.
  3. Die Basis Firmware enthält keine Router-Funktion. Im Soft-AP Modus können die WLAN Clients nur mit dem ESP kommunizieren, nicht miteinander und auch nicht mit dem Internet. Man kann sich den Router ggf. selbst programmieren.

Module und Boards

Der CHIP_EN Pin hieß früher mal CH_PD und CHIP_PU. Manche Board Hersteller nennen ihn ENABLE.

Viele I/O Pins sind nur eingeschränkt verwendbar. Beachte dazu die folgenden Beschreibungen der Module. Zur Erweiterung empfehle ich I/O Expander mit I²C Schnittstelle, wie MCP23017 und PCF8574. Für analoge Anwendungen benutze ich gerne ADS1115 und PCF8591.

Die Widerstände um den Chip herum sollten maximal 2,2 kΩ haben, denn hochohmige Widerstände sind für Funkwellen empfänglich. Beachte die Hinweise in den Hardware Design Guidelines, insbesondere Kapitel 1.6.2, was die Ausrichtung der Antenne angeht.

ESP-01 und ESP-1 Module

Diese kleinen Module sind primär als Netzwerk-Schnittstelle für andere Mikrocontroller gedacht.

Das ESP-01 Modul von der Firma AI-Thinker basiert auf dem ESP8266. Es wird mit 512 kByte Flash (in blau) oder 1 MByte (in schwarz) verkauft. Die rote Power-LED nimmt etwa 0,5 mA Strom auf, die blaue LED hängt am TXD Pin. Das ESP-01S oder ESP8266-01S von AZ-Delivery hat ebenfalls 1 MByte Flash. Es hat nur eine blaue LED an GPIO2, und einen zusätzlichen Pull-Up Widerstand am Enable Eingang. Das ESP-1 Modul von der Firma DOIT basiert auf dem ESP8285. Es hat 1 MByte Flash Speicher und einen Deckel zur Abschirmung. Es hat nur eine blaue LED am TXD Pin.

Die Minimal-Beschaltung zur Nutzung der AT-Firmware sieht so aus:


Pin Name Beschreibung
1 GPIO3 (RXD) serieller Eingang oder normaler I/O Pin. Wird beim Booten schwach auf HIGH gezogen.
2 VDD Spannungs­versorgung 3,3 V 500 mA
3 GPIO0 LOW beim Booten aktiviert Firmware-Upload, muss zum normalen Start offen sein oder schwach auf HIGH gezogen werden. Gibt beim Booten LOW Impulse aus.
4 RESET LOW=Reset, intern unterschiedlich beschaltet. Siehe folgende Zeichnungen.
5 GPIO2 (TXD1) Beim Booten serieller Ausgang, darf dabei nicht auf LOW gezogen werden. Kann nach dem Booten als normaler I/O Pin verwendet werden. Ist bei der "S" Version mit einer blauen LED verbunden, die bei LOW Pegel leuchtet.
6 CHIP_EN LOW=power down, HIGH=chip enabled, hat bei der "S" Version einen 12 kΩ Pull-Up Widerstand
7 GND Masse
8 GPIO1 (TXD) Beim Booten serieller Ausgang, darf dabei nicht auf LOW gezogen werden. Kann nach dem Booten als normaler I/O Pin verwendet werden. Ist bei der Version ohne "S" mit einer blauen LED verbunden, die bei LOW Pegel leuchtet.

Der Reset Eingang des ESP ist innerhalb der Module unterschiedlich beschaltet:

Reset ESP-01 blau Reset ESP-01 schwarz Reset ESP-01S

Die 8-Polige Stiftleiste im 2,54 mm Raster ist das auffälligste Merkmal dieser Module. Dadurch lassen sie sich leicht mit einem kurzen Flachkabel absetzen, um den Empfang zu optimieren.

Die Reichweite der primitiven Antenne (Leiterschleife) ist mit Smartphones vergleichbar.

Wer den Deep-Sleep Modus eines ESP-01 Moduls nutzen möchte, muss einen sehr dünnen Draht direkt an den Chip Pin 8 (GPIO16) anlöten und die Power-LED entfernen (falls vorhanden). Jemand berichtete allerdings dort, dass seine ESP-01S Module mit einen Flash-Chip (CT 580A-UGLI) ausgeliefert werden, der nicht für Deep-Sleep taugt.

Doku von AI-Thinker ESP-01, AZ-Delivery ESP-01S (mit falschem Foto), DOIT ESP-1.

ESP-07 und ESP-12 Module

Diese Module kommen alle von der Firma AI-Thinker. Sie enthalten nur den ESP8266 Chip und einen Flash-Speicher.

Das ESP-07 Modul hat 1 MByte Flash Chip, eine Keramikantenne und eine Steckbuchse für externe Antennen. Die rote Power-LED nimmt etwa 0,5 mA Strom auf, die blaue LED hängt an GPIO2.
Man soll den gezeigten Kondensator entfernen, wenn eine externe Antenne verwendet wird.
Das ESP-07S Modul hat 1 MByte Flash, keine LEDs und keine Antenne. Es muss mit einer externen Antenne betrieben werden. Die Modelle ESP-12S, ESP-12E und ESP-12F haben 4 MByte Flash und eine Leiterschleife als Antenne. Die blaue LED hängt an GPIO2, es gibt keine Power-LED.
Die Modelle 12E und 12F haben eine dritte Reihe mit nutzlosen Pins.

Die Minimal-Beschaltung zur Nutzung der AT-Firmware sieht für diese Module so aus:


Pin Name Beschreibung
1 RESET LOW=Reset, intern unterschiedlich beschaltet. Siehe folgende Zeichnungen.
2 ADC Analoger Eingang 0 bis 1 V
3 CHIP_EN Muss auf HIGH gezogen werden, damit der Chip arbeitet. LOW=power down, HIGH=chip enabled
4 GPIO16 Ist im Deep-Sleep Modus der Ausgang vom Wakeup-Timer. Gibt beim Booten einen HIGH Impuls aus.
5 GPIO14 (SCK) Normaler I/O Pin oder SPI Takt. Wird beim Booten schwach auf HIGH gezogen.
6 GPIO12 (MISO) Normaler I/O Pin oder SPI Daten. Wird beim Booten schwach auf HIGH gezogen.
7 GPIO13 (MOSI) Normaler I/O Pin oder SPI Daten. Wird beim Booten schwach auf HIGH gezogen.
8 VDD Spannungs­versorgung 3,3 V 500 mA
9 Reserviert. Diese Pins existieren nur beim ESP-12E und ESP-12F. Sie sind durch den Flash Speicher belegt.
10
11
12
13
14
15 GND Gemeinsame Masse
16 GPIO15 (CS) Normaler I/O Pin oder SPI Chip Select. Muss beim Booten auf LOW gezogen werden.
17 GPIO2 (TXD1) Beim Booten serieller Ausgang, darf dabei nicht auf LOW gezogen werden. Kann nach dem Booten als normaler I/O Pin verwendet werden. Ist mit der blauen LED verbunden, die bei LOW Pegel leuchtet.
18 GPIO0 LOW beim Booten aktiviert Firmware-Upload, muss zum normalen Start offen sein oder schwach auf HIGH gezogen werden. Gibt beim Booten LOW Impulse aus.
19 GPIO4 Normaler I/O Pin, frei verfügbar
20 GPIO5 Normaler I/O Pin, frei verfügbar
21 GPIO3 (RXD) serieller Eingang oder normaler I/O Pin. Wird beim Booten schwach auf HIGH gezogen.
22 GPIO1 (TXD) Beim Booten serieller Ausgang, darf dabei nicht auf LOW gezogen werden. Kann nach dem Booten als normaler I/O Pin verwendet werden.

Der Reset Eingang des ESP ist innerhalb der Module unterschiedlich beschaltet:

Reset ESP-07 Reset ESP-07S and 12S Reset ESP12E and 12F

Die Anschlussleisten der ESP-12 Module haben 2 mm Raster.

Die Reichweite der on-board Antenne ist mit Smartphones vergleichbar. Mit einer guten externen Antenne soll das ESP-07(S) sogar weiter kommen. Der Antennen-Stecker heisst SMT, U.FL oder IPEX. Achtung: die gibt es in unterschiedlichen Größen!

Die Module ESP-07S und alle ESP-12 sind eine gute Wahl für Batteriebetrieb mit Deep Sleep.

Technische Doku des Herstellers

NodeMCU Board

Das nachgemachte NodeMCU Board von Lolin besteht aus einem ESP-12 Modul mit Spannungsregler und USB-UART Interface (CH-340). Der Flash Speicher ist 4 Megabytes groß. Das originale NodeMCU Board wird nicht mehr hergestellt.


J2 Label Name Beschreibung
1 VIN Spannungs­versorgung 5 bis 9 V 500 mA
2 G GND Gemeinsame Masse
3 RST RESET Hat 12 kΩ Pull-Up Widerstand
4 EN CHIP_EN LOW=power down, HIGH=chip enabled, hat 12 kΩ Pull-Up
5 3V VDD Spannungs­versorgung 3,3 V (Eingang 500 mA oder Ausgang max. 200 mA)
6 G GND Gemeinsame Masse
7 Reserviert, durch den Flash Speicher belegt.
8
9
10
11
12
13 Reserviert, Pinbelegung variiert je nach Board
14
15 A0 ADC Analoger Eingang für 0 bis 3,2 V weil mit Spannungsteiler 220 kΩ + 100 kΩ

J1 Label Name Beschreibung
1 3V VDD Spannungs­versorgung 3,3 V (Eingang 500 mA oder Ausgang max. 300 mA)
2 G GND Gemeinsame Masse
3 TX GPIO1 (TXD) Beim Booten serieller Ausgang, darf dabei nicht auf LOW gezogen werden. Ist mit dem USB-UART verbunden. Kann nach dem Booten als normaler I/O Pin verwendet werden.
4 RX GPIO3 (RXD) Serieller Eingang des ESP. Ist über 470 Ω mit dem USB-UART verbunden. Wird beim Booten schwach auf HIGH gezogen.
5 D8 GPIO15 (CS) Normaler I/O Pin oder SPI Chip Select. Muss beim Booten auf LOW gezogen werden. Hat 12 kΩ Pull-Down Widerstand.
6 D7 GPIO13 (MOSI) Normaler I/O Pin oder SPI Daten. Wird beim Booten schwach auf HIGH gezogen.
7 D6 GPIO12 (MISO) Normaler I/O Pin oder SPI Daten. Wird beim Booten schwach auf HIGH gezogen.
8 D5 GPIO14 (SCK) Normaler I/O Pin oder SPI Takt. Wird beim Booten schwach auf HIGH gezogen.
9 G GND Gemeinsame Masse
10 3V VDD Spannungs­versorgung 3,3 V (Eingang 500 mA oder Ausgang max. 300 mA)
11 D4 GPIO2 (TXD1) Beim Booten serieller Ausgang, darf dabei nicht auf LOW gezogen werden. Kann nach dem Booten als normaler I/O Pin verwendet werden. Ist mit der blauen LED verbunden, die bei LOW Pegel leuchtet. Hat 12 kΩ Pull-Up Widerstand.
12 D3 GPIO0 LOW beim Booten aktiviert Firmware-Upload, muss zum normalen Start offen sein oder schwach auf HIGH gezogen werden. Gibt beim Booten LOW Impulse aus. Hat einen 12 kΩ Pull-Up Widerstand und ist über 470 Ω mit einem Taster nach GND verbunden.
13 D2 GPIO4 Normaler I/O Pin, frei verfügbar
14 D1 GPIO5 Normaler I/O Pin, frei verfügbar
15 D0 GPIO16 Ist mit der blauen LED verbunden, die bei LOW leuchtet. Ist im Deep-Sleep Modus der Ausgang vom Wakeup-Timer. Gibt beim Booten einen HIGH Impuls aus.

Leider gibt es zu den Nachbauten keinen Schaltplan, so dass ich hier nur den Schaltplan des Originals zeigen kann. Bei den Nachbauten ist R7 leer, und dafür R3 mit 470 Ohm bestückt. Entsprechend ist der Taster als "Reset" (nicht "User Key") beschriftet.

In Arduino kann man die NodeMCU Labels nutzen, ich empfehle allerdings die GPIO Nummern zu verwenden.

Man kann das Board wahlweise am 3,3V Eingang mit 2,8 bis 3,6 V betreiben, oder am 5 V Eingang mit 5 bis 9 V, oder über das USB Kabel mit ungefähr 5 V. Eine Diode verhindert, dass Strom vom 5V Eingang zum USB Anschluss fließt. Der Spannungsregler auf den Nachbauten hat für externe Erweiterungen maximal 300 mA Leistungsreserve bei 5 V Eingangsspannung.

Für Batteriebetrieb eignet sich das Board eher nicht, da sein Spannungsregler eine Ruhestromaufnahme um 10 mA hat. Beim Original Board belastet zudem der USB-UART ständig die Batterie, während das "NodeMCU Lua Lolin V3" Board den Chip nur über das eigesteckte USB Kabel versorgt.

Auf einem Steckbrett läuft das Board zuverlässiger, wenn man die reservierten Stifte entfernt, die zum Flash Speicher führen.

Die Reset Leitung und GPIO0 können durch den USB-UART angesteuert werden. Damit aktiviert die Arduino IDE den Firmware-Upgrade Modus vollautomatisch:

DTR RTS RESET GPIO0
Aus Aus HIGH HIGH
Ein Ein HIGH HIGH
Ein Aus LOW HIGH
Aus Ein HIGH LOW

Alternativ kann man den Firmware-Upgrade Modus manuell aktivieren, indem man beide Tasten drückt und dann den Reset-Taster zuerst loslässt.

Wemos D1 Mini Board

Das Wemos D1 Mini Board gibt es in folgenden Versionen:

Version ESP Chip Flash MByte Antenne Extra
Wemos D1 Mini Lite v1 ESP8285 1 Leiter-schleife
Wemos D1 Mini v2 ESP-12 Modul
ESP8266
4 Leiter-schleife
Wemos D1 Mini v3 ESP8266 4 Leiter-schleife
Wemos D1 Mini Pro v1 (oder -16) ESP8266 16 Keramik und extern
Wemos D1 Mini Pro v2 ESP8266 16 Keramik und extern LiIo Lade-Regler

Die oberen vier Boards haben die gleichen Abmessungen, das letzte mit Laderegler ist etwas länger. Alle Versionen haben einen USB-UART (CH-340) und einem Low-Drop Spannungsregler. Alle freien I/O Pins des ESP Chips sind herausgeführt, aber nicht der CHIP_EN Pin.

Die Pinbelegung ist bei allen Wemos D1 Mini Boards gleich:

Pin Label Name Beschreibung
1 RST RESET Hat 10 kΩ Pull-Up Widerstand, einen Taster nach GND, und einen 100 nF Kondensator nach GND
2 A0 ADC Analoger Eingang für 0 bis 3,2 V weil mit Spannungsteiler 220 kΩ + 100 kΩ
3 D0 GPIO16 Ist im Deep-Sleep Modus der Ausgang vom Wakeup-Timer. Gibt beim Booten einen HIGH Impuls aus.
4 D5 GPIO14 (SCK) Normaler I/O Pin oder SPI Takt. Wird beim Booten schwach auf HIGH gezogen.
5 D6 GPIO12 (MISO) Normaler I/O Pin oder SPI Daten. Wird beim Booten schwach auf HIGH gezogen.
6 D7 GPIO13 (MOSI) Normaler I/O Pin oder SPI Daten. Wird beim Booten schwach auf HIGH gezogen.
7 D8 GPIO15 (CS) Normaler I/O Pin oder SPI Chip Select. Muss beim Booten auf LOW gezogen werden. Hat 10 kΩ Pull-Down Widerstand
8 3V3 VDD Spannungs­versorgung 3,3 V (Eingang 500 mA oder Ausgang max. 50 mA)
9 5V Spannungs­versorgung 4 bis 6,5 V 500 mA
10 G GND Gemeinsame Masse
11 D4 GPIO2 (TXD1) Beim Booten serieller Ausgang, darf dabei nicht auf LOW gezogen werden. Kann nach dem Booten als normaler I/O Pin verwendet werden. Alle außer Mini v2 haben eine blaue LED, die bei LOW Pegel leuchtet. Hat 10 kΩ Pull-Up Widerstand.
12 D3 GPIO0 LOW beim Booten aktiviert Firmware-Upload, muss zum normalen Start offen sein oder schwach auf HIGH gezogen werden. Gibt beim Booten LOW Impulse aus. Hat einen 10 kΩ Pull-Up Widerstand.
Achtung: Der Pin darf nur dann LOW ausgeben oder auf LOW gezogen werden, wenn die RTS Leitung vom USB-UART auf LOW steht. Sonst bekommt man einen Kurzschluss gegen den USB-UART Chip.
13 D2 GPIO4 Normaler I/O Pin, frei verfügbar
14 D1 GPIO5 Normaler I/O Pin, frei verfügbar
15 RX GPIO3 (RXD) Serieller Eingang des ESP. Ist über 470 Ω mit dem USB-UART verbunden. Wird beim Booten schwach auf HIGH gezogen.
16 TX GPIO1 (TXD) Beim Booten serieller Ausgang, darf dabei nicht auf LOW gezogen werden. Ist mit dem USB-UART verbunden. Kann nach dem Booten als normaler I/O Pin verwendet werden.

In Arduino kann man die NodeMCU Labels nutzen, ich empfehle allerdings die GPIO Nummern zu verwenden.

Man kann das Board wahlweise am 3,3V Eingang mit 2,8 bis 3,6 V betreiben, oder am 5 V Eingang mit 4 bis 6,5 V, oder über das USB Kabel mit ungefähr 5 V. Eine Diode verhindert, dass Strom vom 5V Eingang zum USB Anschluss fließt. Die Ruhestromaufnahme des Boardes liegt je nach Variante zwischen 200 und 1600 µA, so dass es für Batteriebetrieb nur bedingt geeignet ist. Der Spannungsregler reicht gerade für den WLAN Chip aus, er darf extern nur minimal belastet werden (50 mA bei 5 V). Um die Zuverlässigkeit zu verbessern, empfehle ich einen 100 µF Aluminium Elko zwischen 3,3V und GND.

Der Reset Taster zieht den Reset-Pin ohne Schutzwiderstand direkt auf GND. Das Wemos D1 Mini hat keinen "Flash" Taster. Die Boards besitzen die gleiche Reset-Automatik wie das NodeMCU Board.

Der Analoge Eingang A0 ist mit einem Spannungsteiler (220kΩ + 100kΩ) ausgestattet, damit man Spannungen bis zu 3,2 V messen kann.

Dokumentation des Herstellers.

WIFI Kit 8 Board

Das WIFI Kit 8 (alias Heltec HTIT-W8266 oder Wemos TTGO ESP8266) hat 4 MByte Flash Speicher, sowie ein winzig kleines 0,91" OLED Display für Grafiken mit 128x32 Pixeln (entsprechend 4x21 Zeichen Text). Der Display Controller vom Typ SSD1306 ist über I²C mit dem ESP8266 verbunden. Für die USB Buchse wurde der Chip CP2104 von Silabs verwendet.

Viele Händler verkaufen diese Boards mit falsch beschrifteten Pins und falschen Anschlussplänen! Die folgenden Zeichnungen zeigen die richtige Pinbelegung, und in Klammern die Verbindungen zum Display:

Erkennungsmerkmal:

Erkennungsmerkmal:

Obere Stiftleiste:

Pin Name Beschreibung
1 GND Gemeinsame Masse
2 5 V Spannungs­versorgung 5 V 500 mA
3 3,3 V Spannungs­versorgung 3,3 V (Eingang 500 mA oder Ausgang max. 200 mA)
4 GND Gemeinsame Masse
5 CTS Clear-To-Send Eingang vom USB-UART, LOW aktiv
6 DTR Data-Terminal-Ready Ausgang vom USB-UART, LOW aktiv
7 A: GPIO5 (SCL)
B: GPIO5
A: I²C Takt zum Display mit 10 kΩ Pull-Up Widerstand
B: Normaler I/O Pin, frei verfügbar.
8 GPIO1 (TXD) Beim Booten serieller Ausgang, darf dabei nicht auf LOW gezogen werden. Ist mit dem USB-UART verbunden. Kann nach dem Booten als normaler I/O Pin verwendet werden.
9 GPIO3 (RXD) Serieller Eingang des ESP. Direkt mit dem Ausgang des USB-UART verbunden, daher nicht anders verwendbar.
10 RESET Hat 10 kΩ Pull-Up Widerstand und einen Taster nach GND
11 A: GPIO2 (TXD1)
B: GPIO4 (/RES)
A: Beim Booten serieller Ausgang, darf dabei nicht auf LOW gezogen werden. Kann nach dem Booten als normaler I/O Pin verwendet werden.
B: Setzt das Display bei LOW Pegel zurück.
12 CHIP_EN Muss auf HIGH liegen, damit der Chip arbeitet. Hat 10 kΩ Pull-Up Widerstand. LOW=Power Down, HIGH=Enabled

Untere Stiftleiste:

Stift Name Beschreibung
1 GND Gemeinsame Masse
2 5 V Spannungs­versorgung 5 V 500 mA
3 3,3 V Spannungs­versorgung 3,3 V (Eingang 500 mA oder Ausgang max. 200 mA)
4 GND Gemeinsame Masse
5 A: GPIO4 (SDA)
B: GPIO0
A: I²C Daten zum Display mit 10 kΩ Pull-Up Widerstand.
B: LOW beim Booten aktiviert Firmware-Upload, muss zum normalen Start offen sein oder schwach auf HIGH gezogen werden. Gibt beim Booten LOW Impulse aus. Hat einen 10 Ω Pull-Up Widerstand und ist mit einem Taster nach GND verbunden.
6 A: GPIO0
B: GPIO2 (SDA,TXD1)
A: LOW beim Booten aktiviert Firmware-Upload, muss zum normalen Start offen sein oder schwach auf HIGH gezogen werden. Gibt beim Booten LOW Impulse aus. Hat einen 10 kΩ Pull-Up Widerstand und ist mit einem Taster nach GND verbunden.
B: I²C Daten zum Display, mit 10 kΩ Pull-Up Widerstand. Beim Booten serieller Ausgang, darf dabei nicht auf LOW gezogen werden.
7 GPIO15 (CS) Normaler I/O Pin oder SPI Chip Select. Muss beim Booten auf LOW gezogen werden. Hat 10 kΩ Pull-Down Widerstand.
8 GPIO13 (MOSI) Normaler I/O Pin oder SPI Daten. Wird beim Booten schwach auf HIGH gezogen.
9 GPIO12 (MISO) Normaler I/O Pin oder SPI Daten. Wird beim Booten schwach auf HIGH gezogen.
10 GPIO14 (SCK) Normaler I/O Pin oder SPI Takt. Wird beim Booten schwach auf HIGH gezogen.
B: I²C Takt zum Display, mit 10 kΩ Pull-Up Widerstand
11 A: GPIO16 (/RES)
B: GPIO16
Ist im Deep-Sleep Modus der Ausgang vom Wakeup-Timer. Gibt beim Booten einen HIGH Impuls aus.
A: Setzt das Display bei LOW Pegel zurück.
12 ADC Analoger Eingang für 0 bis 3,2 V weil mit Spannungsteiler 220 kΩ + 100 kΩ.

Die Stromversorgung erfolgt wahlweise über USB, ein 3,3 V Netzteil oder ein 5 V Netzteil. Das Display nimmt zusätzlich zum ESP Chip ca. 30 mA auf. Der eingebaute Spannungsregler hat nur 50 mA Leistungsreserve für externe Erweiterungen. Da die USB Buchse direkt mit dem 5 V Anschluss verbunden ist, soll dort bei Nutzung von USB nicht gleichzeitig ein Netzteil angeschlossen werden.

Das Board eignet sich kaum für Akku-Betrieb. Die Ruhestromaufnahme beträgt etwa 7 mA. Unterhalb von 3,3 V Akku-Spannung fällt das Board aus und saugt dann den Akku mit 80 mA leer, bis er entweder kaputt geht oder seine integrierte Schutzschaltung (falls vorhanden) abschaltet. Beim Aufladen wird die Platine ziemlich warm, was für die Lebensdauer des Displays schlecht ist.

Die beiden Taster ziehen die Leitungen RESET und GPIO0 direkt ohne Schutzwiderstände auf LOW. Die Boards besitzen die gleiche Reset-Automatik wie das NodeMCU Board.

Zur Programmierung des Displays empfehle ich entweder meine schlanke OLED Klasse oder die Libraries SSD1306 und GFX von Adafruit.

Man sollte die geringe Lebensdauer des OLED beachten. Bei maximaler Helligkeit lässt die Leuchtkraft der betroffenen Bildpunkte schon nach einem Jahr deutlich nach.

Stromversorgung

Die häufigste Ursache von Fehlfunktionen ist eine zu schwache Stromversorgung. Der ESP Chip benötigt eine stabile Spannungsversorgung zwischen 2,8 und 3,6 Volt bei einer Stromaufnahme von 5 µA bis 430 mA. Innerhalb dieses Bereiches darf sich sich die Spannung nur langsam ändern. Es ist also ein schneller starker Spannungsregler erforderlich, der extreme Strom-Schwankungen ausregeln kann.

Ich empfehle zur Verbesserung der Zuverlässigkeit einen 100 µF Kondensator direkt an den Anschlüssen VDD und GND des ESP-Moduls. Beim NodeMCU Board ist dieser bereits vorhanden. Ohne diesen Kondensator liefen meine ESP-Module keine 4 Wochen fehlerfrei durch.

Die Leitungen der Stromversorgung sollen möglichst kurz sein und sternförmig an einem Verteil-Punkt zusammen kommen. Das gilt ganz besonders für GND. Steckbretter und Dupont Kabel sind aufgrund der hohen Kontaktwiderstände schlecht zur Stromversorgung geeignet.

Betrieb an Batterien/Akkus

Boards mit USB Schnittstelle eignen sich nicht gut für sparsamen Batteriebetrieb, da sie viel Ruhestrom aufnehmen. Hier sind minimale Module ohne Schnickschnack (wie das ESP-12F) die bessere Wahl. Ich empfehle dazu folgende Stromversorgung:

Dazu diese Spannungsregler:

Beide Spannungsregler gibt es wahlweise mit oder ohne Enable-Eingang.

Wenn der ESP Chip wegen Unterspannung ausfällt nimmt er ständig ca. 80 mA auf. Lithium- und Blei-Akkus müssen daher unbedingt mit einem Tiefentladeschutz ausgestattet werden. Manche Lithium-Akkus enthalten so eine Schutz-Schaltung bereits intern.

Die Spannungsregler MCP170x lehne ich ab, weil sie mit ihren 250 mA zu knapp ausgelegt sind. Der ESP braucht zeitweise 430 mA.

Deep-Sleep Modus

Im Deep-Sleep Modus wird die CPU samt Peripherie angehalten. Die GPIO Pins sind dann hochohmig. Nur die integrierte RTC Uhr läuft weiter, allerdings viel ungenauer als im Normalbetrieb (typisch 2 Minuten Abweichung pro Tag). Ein schlafender ESP ist über WLAN nicht erreichbar. Beim Wieder-Aufwachen muss der ESP wie nach einem Reset neu booten.

Im Deep-Sleep Modus beträgt die Stromaufnahme des ESP Chips (incl. Flash Speicher) etwa 20 µA.

Beim Arduino Framework aktiviert man den Deep-Sleep Modus so:

  ESP.deepSleep(60000000); 
  delay(100);

Als Parameter gibt man an, in wie vielen Mikrosekunden der Chip wieder aufwachen soll. Maximal 71 Minuten sind möglich. Der Wert 0 lässt den Chip für immer schlafen, oder bis zum nächsten externen Reset. Da der Timer von einem temperaturabhängigen R/C Oszillator getaktet wird, kann die Zeit zwei Prozent (das sind 30 Minuten pro Tag) vom Soll abweichen.

Wenn man den Wakeup-Timer benutzt, muss der Timer-Ausgang GPIO16 wie folgt mit dem RESET Eingang des Chips verbunden werden:

Wakeup Schaltung

Dadurch wird das Reset-Signal ein bisschen verzögert und verlängert. Schau in den Schaltplan von deinem Board bzw. Modul, denn diese Bauteile sind wahrscheinlich zumindest teilweise bereits vorhanden.

Weil die Firmware beim Aufwachen neu booted, geht der Inhalt des RAM verloren. Die RTC enthält jedoch 768 Byte zusätzlichen Speicher, der den Deep-Sleep Modus (jedoch nicht Power-Down) überlebt. Davon sind die ersten 256 Bytes allerdings reserviert.

Power-Down Modus

Im Power-Down Modus ist der Chip komplett abgeschaltet. Es fließt nur noch ein kleiner Leckstrom von etwa 5 µA (incl. Flash).

Dieser Modus wird durch eine fallende Flanke am CHIP_EN Eingang ausgelöst, aber erst nachdem die Firmware gestartet ist. Wenn CHIP_EN zu früh auf LOW gezogen wird, nimmt der Chip ca. 2,5 mA auf!

Die steigende Flanke am CHIP_EN Eingang bewirkt, dass der Power-Down Modus verlassen wird und die Firmware neu startet.

Leider enthalten viele Module einen Pull-Up Widerstand an diesem Pin, welcher die Stromaufnahme erheblich erhöht.

Stromaufnahme im Reset

Während der RESET Eingang auf LOW gehalten wird nimmt der Chip ca. 23 mA auf. Der RESET Eingang eignet sich daher nicht zum Strom-sparen.

USB-UART Kabel

Für die Module ohne USB Anschluss, brauchst du ein USB-UART Kabel oder Adapter, um es mit dem PC zu verbinden. Dabei ist wichtig, dass das Ding 3,3 V Pegel hat. Ich schleife in die Signal-Leitungen immer 1 kΩ Widerstände zur Strombegrenzung ein, falls eine Seite mal keine Spannungsversorgung hat.

Für USB-UART Produkte mit altem oder gefälschtem PL2303 Chip habe ich hier einen passenden alten Windows Treiber, denn der aktuelle Treiber mag diese Chips nicht. Den Treiber für die chinesischen CH340 und CH341 Chips kann man direkt von der Webseite des Herstellers downloaden.

Anschluss an 5 V Mikrocontroller

Der ESP Chip verträgt maximal 3,6 V an allen Pins. Die Signale von 5 V Mikrocontrollern kann man mit einem Spannungsteiler herabsetzen.

Für die Rückrichtung sind keine weiteren Maßnahmen notwendig, wenn dem Mikrocontroller 3,3 V als HIGH Pegel genügen (bei AVR ist das der Fall). Falls du den Signalpegel für die Rückrichtung dennoch auf 5V erhöhen willst oder musst, kannst du dazu zum Beispiel den 74LVC1G17 verwenden.

Flash Speicher

Der ESP82xx Chip kopiert seine Firmware blockweise von einem externen Flash Speicher in sein internes RAM. Von dort aus wird der Code dann ausgeführt. Der Chip kann bis zu 16 MByte Flash Speicher adressieren, davon jedoch nur maximal 1 MByte als Programmspeicher nutzen. Die Basis Firmware belegt ungefähr ein Viertel davon.

Der ESP8266 unterstützt folgende Zugriffsarten auf den Flash Speicher:

Welche der vier Varianten tatsächlich funktionieren, hängt vom eingebauten Speicherchip ab. Die meisten können DIO mit 40 Mhz. Zum Ändern der Zugrifssparameter muss man die Firmware modifizieren.

Der ESP8285 hat 1 MByte Flash intern, welcher nur DOUT mit 40 MHz unterstützt. Dafür hat der Chip zwei weitere I/O Pins frei, nämlich GPIO9 und GPIO10.

Beim Start gibt der Chip ein paar Diagnose-Meldungen mit 74880 Baud aus, noch bevor die Firmware gestartet wird. Im Fehlerfall lohnt es sich, diese Meldungen mit einem Terminal-Programm anzuzeigen.

Performance

Um einen Eindruck zu bekommen, wie stark sich die Varianten der Flash Anbindung auf die Gesamt-Performance auswirken, habe ich zwei Testreihen durchgeführt. Die erste Testreihe vergleicht die Netzwerk-Performance: beste Antwortzeit beim Empfangen+Senden von jeweils 1 kB. Die zweite Testreihe vergleicht die Rechenleistung: Anzahl von Multiplikationen in einem festen Zeitfenster.

CPU Freq. Flash Freq. Flash Mode beste Antwortzeit Rechen­leistung
160 MHz 80 MHz QIO und QOUT 4 ms 871
DIO und DOUT 4 ms 870
40 MHz QIO und QOUT 4 ms 870
DIO und DOUT 5 ms 870
80 MHz 80 MHz QIO und QOUT 4 ms 435
DIO und DOUT 4 ms 435
40 MHz QIO und QOUT 4 ms 434
DIO und DOUT 5 ms 434

Firmware Hochladen

Der ESP Chip enthält einen unveränderlichen Bootloader, welcher ein Firmware-Upgrade über den seriellen Port ermöglicht. Beim Reset startet immer zuerst dieser Bootloader. Er erwartet folgende Steuersignale:

Firmware-Upload:

Normaler Start:

Der Bootloader gibt auf GPIO1 und GPIO2 Meldungen mit 74880 Baud aus. Nach dem Start können alle vier Pins als frei programmierbare I/O Anschlüsse verwendet werden. Daraus ergibt sich die folgende sinnvolle Grundschaltung:

Um den ESP-Chip in den Firmware-Upload Modus zu versetzen, musst du beide Taster drücken und dann den Reset Taster zuerst loslassen. Es geht darum, dass GPIO0 beim Start auf LOW steht.

Der Widerstand vor GPIO0 schützt vor Kurzschluss, falls man den Pin als Ausgang programmiert. Der Wakeup-Jumper muss verbunden sein, wenn man den Deep-Sleep Modus mit Wakeup-Timer verwendet. Viele Boards haben die Reset-Schaltung von NodeMCU kopiert, mit der man sich das Drücken der Taster ersparen kann. Sie funktioniert allerdings nicht immer zuverlässig.

Auf der Download Seite kann man ein grafisches Tool zum Flashen bekommen. Leider ist das nur für Windows.

Alternativ bin ich immer gut mit dem Python Script esptool.py, klar gekommen, welches meine beiden weiter unten bereitgestellten Firmware-Pakete enthalten. Zum Ausführen musst Du vorher Python installieren, sowie die Library für serielle Ports:

In Ubuntu/Debian: sudo apt install python3 python3-serial
In Windows Python installieren, dann: pip install serial

Mit Hilfe des esptool kann man folgendermaßen die Größe des Flash Speichers anhand seiner ID Nummer ermitteln:

Windows: python  esptool.py --port COM6 flash_id
Linux:   python3 esptool.py --port /dev/ttyUSB0 flash_id
4013 512 kByte
4014 1 MByte
4015 2 MByte
4016 4 MByte

Der eigentliche Upload einer Firmware-Datei geschieht mit dem Befehl:

python esptool.py --port COM6 write_flash 0x000000 firmware.bin

In diesem Fall ist 0x000000 die Ziel-Adresse im Speicher und firmware.bin die Datei, die dorthin übertragen wird. Keine Angst: Wenn das Hochladen der Firmware (warum auch immer) fehlschlägt, kann man es einfach nochmal versuchen. Der Bootloader gibt im Fehlerfall eventuell hilfreiche Meldungen mit 74880 Baud aus.

Original AT-Firmware

Die AT-Firmware ermöglicht es, das Modul wie ein Modem zu benutzen. Durch das Absetzen von Befehlen auf der seriellen Schnittstelle konfiguriert man das Modul, baut Verbindungen auf und überträgt Daten. Das Modul dient also als Netzwerk-Adapter für einen angeschlossenen Mikrocontroller. Auf der Seite I/O Schnittstellen Module für WLAN stelle ich eine solche Beispiel-Anwendung vor, und im Buch Einstieg in die Elektronik mit Mikrocontrollern erkläre ich detailliert, wie man so etwas macht.

Die AT Firmware sendet und empfängt im 100 ms Raster, maximal 2048 Bytes pro Intervall.

Für Module mit nur 512 kByte Flash Speicher muss man die AT-Firmware 0.50.0.0 vom SDK 1.4.0 verwenden. Das ist die letzte Version, die noch dort hinein passt. Da die Firmware in mehrere Dateien aufgeteilt ist, muss man sie so installieren:

512 kByte python esptool.py --port COM6 write_flash 0x000000 noboot/eagle.flash.bin 0x040000 noboot/eagle.irom0text.bin 0x03e000 blank.bin 0x07e000 blank.bin 0x07c000 esp_init_data_default.bin

Für alle größeren Module habe ich mir die zuverlässige AT-Firmware 1.1.0.0 vom SDK 1.5.4 gesichert. Sie wird mit folgendem Befehl installiert:

1 MByte python esptool.py --port COM6 write_flash 0x000000 boot_v1.5.bin 0x001000 512+512/user1.1024.new.2.bin 0x0fc000 esp_init_data_default.bin 0x07e000 blank.bin 0x0fe000 blank.bin
2 MByte python esptool.py --port COM6 write_flash 0x000000 boot_v1.5.bin 0x001000 512+512/user1.1024.new.2.bin 0x01fc000 esp_init_data_default.bin 0x07e000 blank.bin 0x1fe000 blank.bin
4 MByte python3 esptool.py --port COM6 write_flash 0x000000 boot_v1.5.bin 0x001000 512+512/user1.1024.new.2.bin 0x03fc000 esp_init_data_default.bin 0x07e000 blank.bin 0x3fe000 blank.bin

Falls deine AT-Firmware älter als 0.50.0.0 ist, rate ich zu einem Upgrade, da frühere Versionen noch ziemlich instabil liefen.

AT Befehle

In diesem Kapitel beschreibe ich nur die Befehle, die mir wichtig sind. Sie funktionieren mindestens mit der AT-Firmware von Version 0.21.0.0 bis 3.0.2, vielleicht auch mit neueren. Beachte beim Programmieren, dass das Format der Antworten je nach Firmware Version etwas variiert.

Zum Testen von Netzwerkverbindungen empfehle ich das Kommandozeilen-Programm Netcat (nc) oder alternativ Nmap (ncat). Außerdem solltest Du Dir unbedingt das Programm Wireshark anschauen, falls du es noch nicht kennst. Als Terminalprogramm zur manuellen Eingabe der AT Befehle empfehle das Hammer Terminal, Putty oder Cutecom.

Die AT Firmware kommuniziert in der Regel mit 115200 Baud. Manche Module sind auf 57600 oder 9600 Baud vor-eingestellt. Das Format für Zeilenumbrüche ist CR+LF.

Nach dem Hardware-Reset zeigt das Terminal Programm einige unlesbare Zeilen an, und dann "ready". Danach kannst du Befehle eintippen. Sollten jedoch nur unlesbare Zeichen erscheinen, stelle die Baudrate auf 74880 um, dann kannst du die Fehlermeldungen des Bootloaders lesen.

Befehle:

AT

wird einfach mit "OK" beantwortet. Der Befehl hat keine weitere Funktion, er eignet sich prima, um die serielle Verbindung zu testen.

ATE0

schaltet das Echo der Befehle aus. Dieser Befehl kann die Programmierung vereinfachen und die Geschwindigkeit geringfügig verbessern. Mit der Zahl 1 schaltet man das Echo wieder an. Für manuelles Testen lässt man das Echo am besten eingeschaltet.

AT+GMR

Zeigt die Version der Firmware an, zum Beispiel:

AT version:1.1.0.0(May 11 2016 18:09:56)
SDK version:1.5.4(baaeaebb)
compile time:May 20 2016 15:06:44
OK

AT+CWMODE=1

stellt ein, dass das Modul sich in ein bestehendes WLAN Netz einbuchen soll.

AT+RST

löst einen Software-Neustart aus. Dies ist nach dem Wechsel von CWMODE notwendig.

AT+CWLAP

listet alle erreichbaren Access Points auf. Zum Beispiel:

+CWLAP:(4,"EasyBox-4D2D18",-72,"18:83:bf:4d:2d:b2",2,-46)
+CWLAP:(4,"UPC2827302",-63,"88:f7:c7:52:40:9d",6,-22)
+CWLAP:(0,"Unitymedia WifiSpot",-64,"8a:f7:c7:52:40:9f",6,-22)
+CWLAP:(3,"Pussycat",-45,"5c:49:79:2d:5b:cd",7,-4)
OK

AT+CWJAP="Pussycat","supersecret"

das Modul verbindet sich mit dem WLAN Netz "Muschikatze" und dem angegebenen WPA/WPA2 Passwort. Diese Einstellung wird automatisch dauerhaft gespeichert und beim nächsten Neustart aktiv. Das Passwort muss mindestens 8 Zeichen lang sein!

AT+CWJAP?

zeigt an, mit welchem Access Point das Modul gerade verbunden ist. Zum Beispiel:

+CWJAP:"Pussycat","5c:49:79:2d:5b:cd",7,-60
OK

AT+CIFSR

zeigt die IP-Adresse und MAC Adresse des Moduls an zum Beispiel:

+CIFSR:STAIP,"192.168.0.111"
+CIFSR:STAMAC,"5c:cf:7f:8b:a9:f1"
OK

AT+CIPMUX=1

Stellt ein, dass das Modul mehrere Verbindungen erlauben soll. In diesem Modus sind bis zu 5 gleichzeitige Verbindungen möglich. Die folgenden Beispiele setzen alle voraus, dass dieser Modus aktiviert wurde.
Das Gegenteil wäre der AT+CIPMUX=0, wo das Modul nur als Client und mit nur einer Verbindung genutzt werden kann. In diesem Fall entfällt bei den drauf folgenden Befehlen die Kanalnummer.

AT Firmware als TCP Server benutzen

AT+CIPSERVER=1,5000

dieser Befehl schaltet den Server ein, so dass er Verbindungen auf Port 5000 annimmt. Er kann danach (je nach Firmware Version) maximal 4 oder 5 Verbindungen gleichzeitig annehmen. Danach könntest du zum Beispiel mit Netcat eine Netzwerkverbindung zu diesem Mini-Server aufbauen:

nc 192.168.0.111 5000
Hello
World!

Am seriellen Port des Moduls erscheinen dabei folgende Meldungen:

0,CONNECT
+IPD,0,7:Hello
+IPD,0,8:World!

"0,CONNECT" bedeutet, dass der TCP Server eine Verbindung auf Kanal 0 angenommen hat.
"+IPD,0,7:" bedeutet, dass der Server auf Kanal 0 genau 7 Bytes (nämlich "Hello\r\n") empfangen hat.
Nach dem Doppelpunkt folgen genau diese 7 Bytes. Achtung: Wenn der empfangene Text nicht mit einem Zeilenumbruch endet, dann kommt die nächste +IPD Meldung direkt dahinter in der selben Zeile!

AT+CIPSEND=0,9
> Welcome!

Mit diesem Befehl sendest du eine Antwort an den Computer. Die 0 ist wieder die Kanalnummer und die 9 sind die Anzahl der zu sendenden Bytes (maximal 2048). Nachdem das Modul mit ">" Antwortet, gibst du die zu sendenden Zeichen (oder Bytes) ein. Das Modul bestätigt den Sendevorgang nach kurzer Zeit mit

SEND OK

Laut Dokumentation soll man nach diesem Kommando mindestens 1 Sekunde warten. Bei meinen Tests funktionierten aber 4 Kommandos pro Sekunde weitgehend zuverlässig.

AT+CIPCLOSE=0

mit diesem Befehl schließt du die Verbindung auf Kanal 0. Das Modul antwortet mit

0,CLOSED
OK

AT Firmware als TCP Client benutzen

AT+CIPSTART=0,"TCP","mail.stefanfrings.de",25

Kanal 0 baut eine TCP Verbindung zu dem angegebenen Server auf Port 25 auf. Anstelle des Hostnamens kannst du auch eine IP Adresse verwenden. Die Antwort lautet zum Beispiel:

0,CONNECT
OK
+IPD,0,96:220 wp039.webpack.hosteurope.de 
   ESMTP Host Europe Mail Service 
   Sat, 08 Apr 2017 23:37:19 +0200

Da dieser Mail-Server sofort antwortet, siehst du auch direkt eine +IPD Zeile. Der Text hinter dem Doppelpunkt ist die Antwort des Servers. Danach kann man mit AT+CIPSEND wie bereits oben beschrieben Daten an den Server senden. Mit AT+CIPCLOSE schließt man die Verbindung.

AT Firmware für UDP benutzen

Beim UDP Protokoll entfällt der Verbindungsaufbau, und damit auch die Begrenzung auf 5 gleichzeitige Verbindungen. Man sendet einzelne Nachrichten an die gewünschten Empfänger und hofft, dass sie zügig dort ankommen. Im Gegensatz zu TCP verzichtet das UDP Protokoll auf die Wiederholung von verlorenen Paketen. Es garantiert nicht einmal, dass alle Pakete in der richtigen Reihenfolge beim Empfänger ankommen (das passiert in lokalen Netzen allerdings praktisch nie).

UDP ist einfacher zu programmieren und nutzt die Übertragungsstrecke effizienter als TCP. Es eignet sich besonders gut zur regelmäßigen Übertragung von Messwerten, wenn einzelne Aussetzer tolerierbar sind (z.B. Temperaturfühler). Leider können Javascripte in Webseiten das UDP Protokoll nicht nutzen.

AT+CIPSTART=0,"UDP","0",0,3002,0

Nach diesem Befehl kann das Modul UDP Nachrichten auf Port 3002 von beliebigen Absendern empfangen. Es kann aber keine Nachrichten senden. Zum Test kannst du das Programm Netcat benutzen:

nc -u 192.168.0.111 3002
Lets start!

Wobei du die IP-Adresse deines WLAN Moduls angeben musst. Wenn Du dann in Netcat etwas zum senden eintippst, wird das Modul den Empfang der Nachricht mit +IPD signalisieren:

+IPD,0,12:Lets start!

AT+CIPSTART=0,"UDP","0",0,3002,2

Das Modul empfängt UDP Nachrichten auf Port 3002 von beliebigen Absendern, und es kann Antworten mit AT+CIPSEND zurück schicken. Die Antworten werden immer an den Computer gesendet, von dem zuletzt eine Nachricht empfangen wurde.

AT+CIPSTART=0,"UDP","192.168.0.5",3001,3002,0

Das Modul kann UDP Nachrichten auf Port 3002 von beliebigen Absendern empfangen. Mit dem AT+CIPSEND Befehl wird es Nachrichten an den Computer 192.168.0.5 Port 3001 senden.

Soft-AP Modus

Wo kein WLAN Netz existiert, kann das ESP-Modul selbst ein kleines provisorisches Netz aufspannen. Bis zu 4 andere Geräte können sich dann mit dem Modul verbinden, aber sie können sich nicht gegenseitig sehen. Der Soft-AP Modus eignet sich gut dazu, ESP Module untereinander zu verbinden. Die Nutzung mit Smartphones und Laptops kann ich nicht empfehlen, da sie bei vielen Geräten unzuverlässig funktioniert. Im Soft-AP Modus erreichst du das WLAN Modul mit der fest codierten IP-Adresse 192.168.4.1.

AT+CWMODE=2
AT+CWSAP="ESP-Modul","supersecret",5,3
AT+RST

Diese Befehlsfolge aktiviert den Soft-AP Modus, und stellt den Namen des Netzes und das Passwort ein. Die 5 gibt den WLAN Funk-Kanal an (0-13), und die 3 legt fest, dass WPA2 Verschlüsselung verwendet wird. Diese Einstellung wird automatisch dauerhaft gespeichert und beim nächsten Neustart aktiv. Das Passwort muss mindestens 8 Zeichen lang sein!

Es gibt auch einen Kombinierten Modus (AT+CWMODE=3), in welchem sich das Modul mit einem bestehenden WLAN Netz verbindet und außerdem ein eigenes zweites Netz aufspannt.

Möglichkeiten der Programmierung

Anstatt den ESP82xx wie ein Modem über AT-Befehle zu benutzen, kann man auch eigene Firmware schreiben, die direkt auf dem Mikrocontroller des ESP Moduls läuft. Der chinesische Hersteller Espressif stellt dazu ein Software Development Kit (SDK) bereit, das allerdings recht kompliziert anzuwenden ist.

Das NodeMCU Projekt bemüht sich darum, die Programmierung stark zu vereinfachen, indem man auf LUA Scripte setzt. Allerdings leidet dieser Lösungsansatz an notorischem Speichermangel. Das eigene LUA Script muss samt Daten (Variablen) in ca. 40 kByte RAM gequetscht werden. Scrolle auf der Projektseite nach unten, dort gibt es einen Link zu dem "custom firmware build service", wo man sich eine individuell zusammengestellte Firmware erzeugen lässt.

Es gibt einen Python Interpreter für den ESP8266, der ebenfalls schnell an die Grenzen des knappen Speichers stößt.

Die angenehmste Lösung ist meiner Meinung nach der ESP8266 Core für Arduino. Man programmiert dort in C++. Die Installation der Arduino IDE ist kinderleicht - kein Vergleich zum Espressif SDK.

Alle vier Varianten haben eines gemeinsam: Es gibt keinen Debugger. Man muss sich mit seriellen Textausgaben zufrieden geben..

Erste Schritte mit Arduino

Der Arduino Core kombiniert das SDK des Herstellers mit dem Arduino Framework, um die Programmierung in C++ zu erleichtern. Das damit erzeugte Compilat enthält daher immer die originale Firmware des Herstellers plus dein eigenes Anwendungsprogramm.

Installation:

Falls das nicht klappt oder deine Programme instabil laufen, versuche mein Bundle für Linux oder Windows. Das ist eine alte Kombination (aus Arduino IDE 1.8.16 mit ESP8266 Core 2.3.0), die ganz sicher zuverlässig funktioniert.

Anwendung:

Der Menüpunkt "Bootloader brennen" ist für den ESP8266 irrelevant, weil er einen fest installierten Bootloader hat, denn man nicht verändern kann.

Unter Linux funktioniert bei mir der serielle Monitor von der Arduino IDE manchmal nicht, aber mit einem externen Programm (z.B. Cutecom) geht es immer. Irgend etwas stimmt da bei der Umschaltung der Baudrate nicht.

In Arduino Quelltexten entsprechen die Pin Nummern den GPIO Nummern. Man schreibt digitalWrite(4,HIGH) um den GPIO4 auf HIGH zu setzen. Der analoge Eingang heisst in Arduino A0 oder 17.

Lies die Dokumentation von Arduino und dem ESP8266 Core in der aktuellen Version oder Version 2.3.0. Die Doku von der Version 2.3.0 ist auch im obigen Bundle enthalten.

Beispiel Sketche

Die Arduino IDE zeigt im Menü "Datei/Beispiele" Sketche an, welche die Verwendung des ESP8266 Core demonstrieren. Darüber hinaus zeige ich dir hier Sketche, die du für erste Versuche 1:1 in deine Arduino IDE kopieren kannst.

LED Blinker

Der erste Sketch lässt die blaue LED auf dem ESP-12 Modul blinken und gibt auf dem Seriellen Port immer abwechselnd "Tick" und "Tack" aus. Außerdem bucht er sich ins WLAN Netz ein, so dass da Modul mit einem Ping Befehl erreichbar ist.

#include <ESP8266WiFi.h>

//The ESP-12 has a blue LED on GPIO2
#define LED 2

// Name and password of the WLAN access point
#define SSID "Pussycat"
#define PASSWORD "supersecret"

/** Runs once at startup */
void setup() 
{
    Serial.begin(74880);
    pinMode(LED, OUTPUT);

    WiFi.mode(WIFI_STA);
    WiFi.begin(SSID, PASSWORD);
}

/** Main loop, executed repeatedly */
void loop() 
{
    digitalWrite(LED, LOW);
    Serial.println(F("Tick"));
    delay(500);

    digitalWrite(LED, HIGH);
    Serial.println(F("Tack"));
    delay(500);
}

Im Menü "Werkzeuge" kannst du Debug Meldungen aktivieren. Dazu muss das Programm erneut compiliert und hochgeladen werden. Den seriellen Port musst du aber selbst öffnen, wie im obigen Beispiel (mit Serial.begin). Wenn im "Debug Level" die Option "WiFi" ausgewählt wurde, bekommst du Meldungen über den Verbindungsaufbau zum WLAN Netz.

Für das Debugging ist die ungewöhnliche Baudate 74880 vorteilhaft, weil der Bootloader vor dem Programmstart ebenfalls Meldungen mit 74880 Baud ausgibt. Die kannst du dann auch lesen.

UDP Server

Der zweite Sketch empfängt UDP Nachrichten und sendet sie als Echo zurück:

#include <ESP8266WiFi.h>
#include <WiFiUDP.h>

// The ESP-12 has a blue LED on GPIO2
#define LED 2

// Name and password of the WLAN access point
#define SSID "Pussycat"
#define PASSWORD "supersecret"

// The server accepts connections on this port
#define PORT 5444
WiFiUDP udpServer;

// Buffer for incoming UDP messages
char udp_buffer[WIFICLIENT_MAX_PACKET_SIZE+1];


/** Receive UDP messages and send an echo back */
void process_incoming_udp()
{   
    if (udpServer.parsePacket()) 
    {
        // Fetch received message
        int len=udpServer.read(udp_buffer,sizeof(udp_buffer)-1);
        udp_buffer[len] = 0;
                
        // Display the message
        Serial.print(F("Received from "));
        Serial.print(udpServer.remoteIP());
        Serial.print(":");
        Serial.print(udpServer.remotePort());
        Serial.print(": ");
        Serial.println(udp_buffer);
        
        // Send echo back
        udpServer.beginPacket(udpServer.remoteIP(), udpServer.remotePort());
        udpServer.print(F("Echo: "));
        udpServer.print(udp_buffer); 
        udpServer.endPacket();
        
        // Execute some commands
        if (strstr(udp_buffer, "on"))
        {
            digitalWrite(LED, LOW);
            udpServer.println(F("LED is on"));
        }
        else if (strstr(udp_buffer, "off"))
        {
            digitalWrite(LED, HIGH);
            udpServer.println(F("LED is off"));
        }
    }    
}


/** Optional: Notify about AP connection status changes */
void check_ap_connection()
{
    static wl_status_t preStatus = WL_DISCONNECTED;
    
    wl_status_t newStatus = WiFi.status();
    if (newStatus != preStatus)
    {
        if (newStatus == WL_CONNECTED)
        {
            digitalWrite(LED, LOW);
            
            // Display the own IP address and port
            Serial.print(F("AP connection established, listening on "));
            Serial.print(WiFi.localIP());
            Serial.print(":");
            Serial.println(PORT);
        }
        else
        {
            digitalWrite(LED, HIGH);
            Serial.println(F("AP conection lost"));
        }
        preStatus = newStatus;
    }
}


/** Runs once at startup */
void setup()
{
    // LED off
    pinMode(LED, OUTPUT);
    digitalWrite(LED, HIGH);

    // Initialize the serial port
    Serial.begin(115200);
    
    // Give the serial monitor of the Arduino IDE time to start
    delay(500);

    // Use an external AP
    WiFi.mode(WIFI_STA);
    WiFi.begin(SSID, PASSWORD);

    // Start the UDP server
    udpServer.begin(PORT);
}


/** Main loop, executed repeatedly */
void loop()
{
    process_incoming_udp();
    check_ap_connection();
}

Wenn die Verbindung zum AP aufgebaut wurde, geht die blaue LED an. Auf dem seriellen Port gibt das Programm hilfreiche Statusmeldungen aus. So kannst du den Server mit Netcat testen:

nc -u 192.168.0.111 5444
Monkey see monkey do
Echo: Monkey see monkey do
off
Echo: off
LED is off
on
Echo: on
LED is on

Der UDP Service ist einfach zu programmieren, weil man sich darauf verlassen kann, dass Nachrichten 1:1 wie gesendet eintreffen, also weder zerstückelt noch zusammengefügt. Außerdem braucht man sich nicht um den Verbindungs-Aufbau kümmern. Der größte Nachteil ist, dass UDP Nachrichten manchmal unbemerkt verloren gehen - besonders in drahtlosen Netzen. In seltenen Fällen erreichen schnell aufeinander folgende Pakete ihren Empfänger in veränderter Reihenfolge.

TCP Server

Der dritte Sketch zeigt einen TCP Server, der mehrere Verbindungen gleichzeitig bedient:

#include <ESP8266WiFi.h>

// The ESP-12 has a blue LED on GPIO2
#define LED 2

// Name and password of the WLAN access point
#define SSID "Pussycat"
#define PASSWORD "supersecret"

// The server accepts connections on this port
#define PORT 5333
WiFiServer tcpServer(PORT);

// Objects for connections
#define MAX_TCP_CONNECTIONS 5
WiFiClient clients[MAX_TCP_CONNECTIONS];

// Buffer for incoming text
char tcp_buffer[MAX_TCP_CONNECTIONS][30];


/**
 * Collect lines of text.
 * Call this function repeatedly until it returns true, which indicates
 * that you have now a line of text in the buffer. If the line does not fit
 * (buffer to small), it will be truncated.
 *
 * @param source The source stream.
 * @param buffer Target buffer, must contain '\0' initiallly before calling this function.
 * @param bufSize Size of the target buffer.
 * @param terminator The last character that shall be read, usually '\n'.
 * @return True if the terminating character was received.
 */
bool append_until(Stream& source, char* buffer, int bufSize, char terminator)
{
    int data=source.read();
    if (data>=0)
    {
        int len=static_cast<int>(strlen(buffer));
        do
        {
            if (len<bufSize-1)
            {
                buffer[len++]=static_cast<char>(data);
            }
            if (data==terminator)
            {
                buffer[len]='\0';
                return true;
            }
            data=source.read();
        }
        while (data>=0);
        buffer[len]='\0';  
    }
    return false;
}


/** Optional: Notify about AP connection status changes */
void check_ap_connection()
{
    static wl_status_t preStatus = WL_DISCONNECTED;
    
    wl_status_t newStatus = WiFi.status();
    if (newStatus != preStatus)
    {
        if (newStatus == WL_CONNECTED)
        {
            digitalWrite(LED, LOW);
            
            // Display the own IP address and port
            Serial.print(F("AP connection established, listening on "));
            Serial.print(WiFi.localIP());
            Serial.print(":");
            Serial.println(PORT);
        }
        else
        {
            digitalWrite(LED, HIGH);
            Serial.println(F("AP conection lost"));
        }
        preStatus = newStatus;
    }
}


/** 
 * Put new connections into the array and
 * send a welcome message.
 */
void handle_new_connections()
{
    WiFiClient client = tcpServer.available();
    if (client)
    {
        Serial.print(F("New connection from "));
        Serial.println(client.remoteIP().toString());
        
        // Find a freee space in the array   
        for (int i = 0; i < MAX_TCP_CONNECTIONS; i++)
        {
            if (!clients[i].connected())
            {
                // Found free space
                clients[i] = client;
                tcp_buffer[i][0]='\0';
                Serial.print(F("Channel="));
                Serial.println(i);
                
                // Send a welcome message
                client.println(F("Hello World!"));
                return;
            }
        }
        Serial.println(F("To many connections"));
        client.stop();
    }
}


/** Receive TCP messages and send echo back */
void process_incoming_tcp()
{   
    static int i=0;
    
    // Only one connection is checked in each call
    if (clients[i].available())
    {
        // Collect characters until line break
        if (append_until(clients[i],tcp_buffer[i],sizeof(tcp_buffer[i]),'\n'))
        {        
            // Display the received line
            Serial.print(F("Received from "));
            Serial.print(i);
            Serial.print(": ");
            Serial.print(tcp_buffer[i]);

            // Send an echo back
            clients[i].print(F("Echo: "));
            clients[i].print(tcp_buffer[i]);
            
            // Execute some commands
            if (strstr(tcp_buffer[i], "on"))
            {
                digitalWrite(LED, LOW);
                clients[i].println(F("LED is on"));
            }
            else if (strstr(tcp_buffer[i], "on"))
            {
                digitalWrite(LED, HIGH);
                clients[i].println(F("LED is off"));
            }    
            
            // Clear the buffer to receive the next line
            tcp_buffer[i][0]='\0';
        }
    }
    
    // Switch to the next connection for the next call
    if (++i >= MAX_TCP_CONNECTIONS)
    {
        i=0;
    }
}


/** Executes once during start*/
void setup()
{
    // LED off
    pinMode(LED, OUTPUT);
    digitalWrite(LED, HIGH);

    // Initialize the serial port
    Serial.begin(115200);
    
    // Give the serial monitor of the Arduino IDE time to start
    delay(500);

    // Use an external AP
    WiFi.mode(WIFI_STA);
    WiFi.begin(SSID, PASSWORD);

    // Start the TCP server
    tcpServer.begin();
}


/** Main loop, executed repeatedly */
void loop()
{
    handle_new_connections();
    process_incoming_tcp();
    check_ap_connection();
}

Wenn die Verbindung zum AP aufgebaut wurde, geht die blaue LED an. Auf dem seriellen Port gibt das Programm hilfreiche Statusmeldungen aus. So kannst du die Anwendung mit Netcat testen:

nc 192.168.0.111 5333
Hello World!
I am Groot
Echo: I am Groot
off
Echo: off
LED is off
on
Echo: on
LED is on

Bei TCP kann man sich im Gegensatz zu UDP absolut sicher sein, dass innerhalb einer Verbindung keine Nachrichten verloren gehen und dass die Reihenfolge nicht durcheinander gerät. Aber eine Textzeile kommt unter Umständen zerteilt in mehreren Segmenten an, selbst wenn sie kurz ist. Oder ein Segment liefert zwei Textzeilen, die ursprünglich einzeln gesendet wurden.

Deswegen habe ich die Funktion append_until() entwickelt, die Eingaben Zeilenweise unabhängig von der Segmentierung einsammelt. Im Gegensatz zu Arduinos readStringUntil() hat sie folgende Vorteile:

WiFi Config Service

Bei den obigen Beispielen wurden die Zugangsparameter für den WLAN Access Point einfach fest in den Quelltext geschrieben. Für Nicht-Entwickler ist diese Vorgehensweise jedoch ungeeignet. Eigentlich wurde dazu WPS erfunden, doch das hat bei mir (auch auf anderen Geräten) so oft nicht funktioniert, dass ich es gar nicht mehr verwende.

Eine naheliegende Alternative wäre, ein provisorisches WLAN Netz zu erzeugen und dort eine Webseite zur Konfiguration bereit zu stellen. Mein kleines WiFi-Monitor Projekt enthält die Klasse ConfigService, welche genau das tut.

An dem folgenden verkürzten Quelltext siehst du, wie einfach der WiFi Config Service anzuwenden ist:

#include "ConfigService.h"

ConfigService configService(80);

void setup()
{
    configService.begin(5,"WiFi Monitor","");
    ...
}

void loop()
{
    configService.run();
    ...
}

Nach dem Einschalten der Stromversorgung aktiviert das Programm für 5 Minuten ein provisorisches Netz mit dem Namen "WiFi Monitor" ohne Passwort. Du kannst deinen Computer oder Smartphone mit diesem Netz verbinden und dann die Seite http://192.168.4.1 aufrufen:

Dort gibst du die Zugangsdaten deines Access Points (z.B. Fritz Box) ein. Wenn sie richtig sind, baut das Modul sofort eine Verbindung zu diesem Gerät auf. Das Hauptprogramm in diesem Beispielprojekt testet die Erreichbarkeit des konfigurierten Webservers und zeigt den Status anhand einer bunten LED an.

WLAN vorübergehend aus schalten

Ohne WLAN nimmt der Chip 10-15 mA Strom auf. Der analoge Eingang funktioniert in diesem Zustand viel besser. Um die WLAN Schnittstelle vorübergehend aus zu schalten, muss man den Wakeup-Timer einbeziehen:

  ESP.deepSleep(1, WAKE_RF_DISABLED); 
  delay(100);

Der Mikrocontroller legt sich sehr kurz schlafen und startet mit deaktiviertem WLAN neu durch.

So reaktiviert man die Schnittstelle wieder:

  ESP.deepSleep(1, WAKE_RFCAL); 
  delay(100);

Der Timer-Ausgang GPIO16 muss wie folgt mit dem RESET Eingang verbunden werden:

Wakeup Schaltung

Dadurch wird das Reset-Signal ein bisschen verzögert und verlängert. Schau in den Schaltplan deines Boardes! Diese Bauteile sind wahrscheinlich zumindest teilweise bereits vorhanden.

Fallstricke

Es ist wichtig, das die Firmware genügend Rechenzeit ab bekommt, sonst fällt das Modul aus. Alle eigenen Programmteile müssen spätestens nach 50 ms (empfohlen werden 20 ms) die Kontrolle an die Firmware abgeben, indem sie entweder die Funktion delay(ms) oder yield() aufrufen.

Für eigene Programme stehen nur ungefähr 4 kByte Stack zur Verfügung. Wenn lokale Variablen in Prozeduren mehr Platz belegen, stürzt das Programm ab. Größere Datenmengen (z.B. Puffer für Daten) sollen daher vorzugsweise global deklariert werden, damit sie außerhalb des Stack liegen.

Bedenke das String Objekte und Zeichenketten normalerweise im RAM liegen. Hier ist beschrieben, wie man sie stattdessen im Flash Speicher anlegt, um RAM zu sparen.

Dynamische Speicherverwaltung auf dem Heap verlangt besondere Sorgfalt, damit der Heap nicht fragmentiert wird. Sobald der eigene Code die Schlüsselwörter delete oder free enthält, sollte man die Langzeit-Stabilität der Anwendung gründlich überprüfen. String Objekte machen davon intensiv Gebrauch. Mehr dazu hier.

Wenn man Daten sendet, wird aus jedem print() und write() Aufruf ein einzelnes Ethernet Paket. Viele kleine Pakete reduzieren die Performance, verglichen mit wenigen großen Paketen. Wenn man jedoch in einem Aufruf zu viele Daten sendet, teilt die Firmware sie automatisch auf mehrere Pakete auf und wartet notfalls sogar darauf, dass Platz im Sendepuffer frei wird.

Da der Empfangspuffer mehrere Pakete aufnehmen kann, muss man bei der Programmierung davon ausgehen, dass readBytes() einige Kilobytes am Stück zurück liefert, vor allem wenn die Daten schnell aufeinander folgend eintreffen. Passe daher beim Auslesen der Daten auf, weder deine Puffer noch den Stack zu überladen.

Benutze die Methoden readString() und readStringUntil() am besten gar nicht, weil sie beliebig lange Strings ansammeln, die leicht einen Speicher-Überlauf auslösen. Besser geht es mit meiner append_until() Funktion aus dem obigen Beispiel-Sketch.

Verlasse dich nicht darauf, dass gesendete TCP Nachrichten den Empfänger in der gleichen Segmentierung erreichen, wie sie gesendet wurden. Die Netzwerk-Komponenten dürfen die Segmente des TCP Datenstromes zerlegen und neu zusammenfügen. In dieser Diskussion wurden die Effekte der Segmentierung schön erklärt.

Beim UDP Protokoll sendet und empfängt man Pakete mit der oben genannten maximalen Größe. Diese kann unter Umständen durch Netzwerk Komponenten (Router, Modems, etc.) noch weiter eingeschränkt sein.

Interrupt-Handler Routinen müssen mit dem Makro ICACHE_RAM_ATTR (vor Arduino core 3.0.0) oder IRAM_ATTR (ab Version 3.0.0) gekennzeichnet werden, sonst stürzt der Mikrocontroller ab. Innerhalb von Interruptroutinen darf man keine WLAN-Funktion benutzen, den ADC nicht auslesen und auch nicht delay() oder yield() benutzen. Ich rate davon ab, Interrupts überhaupt zu verwenden, weil es dabei oft zu unerwarteten Störungen kommt.

Wenn man den ADC zu oft hintereinander ausliest, dann fällt WLAN aus. Man muss zwischen den Zugriffen Pausen (z.B. 100 ms) einfügen.

Es wird empfohlen, nach ESP.deepSleep() immer einen delay(100) einzufügen, damit das Einschlafen zuverlässig funktioniert.

Jedes mal, wenn die Parameter der WLAN Verbindung verändert werden, findet ein Schreibzugriff auf den Flash Speicher statt. Die Einstellungen werden nämlich automatisch abgespeichert und beim nächsten Start wieder angewendet. Das betrifft die Funktionen:

Wenn diese Funktionen oft wechselweise oder mit anderen Parametern aufgerufen werden, kann der Flash Speicher frühzeitig kaputt gehen. Mit WiFi.persistent(false) verhindert man das automatische Speichern. Das Passwort muss entweder ein Leerstring ("") oder mindestens 8 Zeichen lang sein.

Andere IDE als besseren Text-Editor verwenden

Der Text-Editor von Arduino ist gelinde gesagt knapp ausgestattet. Andere Entwicklungsumgebungen sind viel komfortabler. Sie erkennen viele Fehler schon direkt während der Eingabe und helfen beim Tippen, indem sie Vorschläge anzeigen. Man kann direkt zu anderen Quelltext-Dateien springen, indem man mit gedrücker Strg-Taste auf einen Namen klickt.

In den folgenden Absätzen habe ich das Installationsverzeichnis der Arduino IDE mit <arduino> abgekürzt. Das <packages> Verzeichnis, wo die Erweiterungen instaliert sind, liegt normalerweise im persönlichen Ordner:

Bei einer portablen Installation befinden sich die Packages hingegen im Verzeichnis <arduino>/portable.

Gehe in der Arduino IDE in das Menü Datei/Voreinstellungen und schalte die Option "Externen Editor verwenden" ein.

Visual Studio Code

Visual Studio Code (VSCode) ist eine kostenlose Entwicklungsumgebung von Microsoft. In vielen Linux Distributionen ist sie als optionales Paket enthalten. Die Arduino Erweiterung für Visual Studio Code benötigt eine installierte Arduino IDE.

Qt-Creator

Qt Creator ist eine kostenlose IDE für C/C++ Projekte mit speziellen Features für das Qt Framework. Qt Creator hat von allen hier genannten IDEs die beste Quelltext-Analyse, was das Erkennen von potentiellen Fehlern betrifft. Qt Creator gibt es für Linux, Windows und macOS. Qt-Creator ist in C++ geschrieben, und läuft daher auf jedem Computer flott.

Du kannst das Arduino-Projekt über den Menü-Befehl "Datei/Neu/Projekt importieren/Import eines existierenden Projekts" importieren. In der Datei "ProjektName.files" kannst du angeben, welche Dateien du in Qt Creator bearbeiten willst.

In der Datei "ProjektName.includes" gibst du alle Verzeichnisse an, wo die Header Dateien der C-Bibliotheken gesucht werden sollen. Zum Beispiel:

<packages>/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include
<packages>/esp8266/hardware/esp8266/2.3.0/cores/esp8266
<packages>/esp8266/hardware/esp8266/2.3.0/variants/generic
<packages>/esp8266/hardware/esp8266/2.3.0/tools/sdk/include
<packages>/esp8266/hardware/esp8266/2.3.0/libraries/ESP8266WiFi/src
<packages>/esp8266/hardware/esp8266/2.3.0/libraries/EEPROM
<packages>/esp8266/hardware/esp8266/2.3.0/libraries/Wire
<packages>/esp8266/hardware/esp8266/2.3.0/libraries/SPI

In der Datei "ProjektName.config" gibst du die Version 1.8.16 deiner Arduino IDE an:

#define ARDUINO 010816

Nun kannst du deinen Sketch mit Qt-Creator editieren. Um ihn zu überprüfen (compilieren) und hochzuladen musst du weiterhin die Arduino IDE verwenden.

NetBeans

NetBeans benötigt ein Java Development Kit, weil die IDE in Java programmiert wurde. Sie war primär für Java Anwendungen gedacht, hat aber auch einen guten C/C++ Editor als Plugin.

Nach der Installation des Plugins, gehe ins Menü Tools/Options/Miscellaneous/Files. Wähle die Dateiendung C++ aus. Klicke dann auf den "New..." Knopf und füge die Endung "ino" hinzu. Danach erkennt NetBeans die *.ino Dateien als C++ Quelltext an.

Gehe ins Menü Tools/Options/C/C++/Build Tools. Füge eine neue "Tool Collection" mit dem Basis-Verzeichnis <esp8266>/tools/xtensa-lx106-elf-gcc hinzu. Darunter muss die "Tool Collection Family" auf "GNU MinGW" (unter Windows) bzw. "GNU" (unter Linux) eingestellt werden. Der Name für die neue Tool Collection soll "ESP8266" sein.

Der C-Compiler heißt xtensa-lx106-elf-gcc, und der C++ Compiler heißt xtensa-lx106-elf-cpp. Beide liegen irgendwo im <packages> Verzeichnis. Die anderen Programm-Felder darunter dürfen leer bleiben:

Wechsle dann zu dem Reiter "Code Assistance". Wähle bei "Tool Collection" die "ESP8266" aus und füge dann darunter beim C++ Compiler unter "Include Directories" alle Verzeichnisse ein, wo die Header Dateien der C-Bibliotheken gesucht werden sollen. Zum Beispiel:

Darunter fügst du eine "Macro Definition" mit dem Wert "ARDUINO=010816" ein, das ist die Versionsnummer 1.8.16 deiner Arduino IDE.

Erstelle in deinem Arduino Projektverzeichnis (wo sich die *.ino Datei befindet) eine leere Datei mit dem Namen "Makefile" (achte dabei auf die groß/klein-Schreibung). Gehe danach in NetBeans auf den Menüpunkt File/New Project. Wähle als Projekt-Typ "C/C++ with Existing Sources" aus. Im nächsten Dialog gibst du das Projektverzeichnis und die Tool Collection ist "ESP8266" an. Die Option "Use Build Analyzer" soll ausgeschaltet werden.

Nun kannst du deinen Sketch mit Netbeans editieren. Um ihn zu überprüfen (compilieren) und hochzuladen musst du weiterhin die Arduino IDE verwenden. Eventuell magst du dir diese Anleitung anschauen, wo die Bedienung des Editors erklärt wird.

Manchmal funktionieren die ganzen erweiterten Editor-Funktionen bei einzelnen Dateien nicht. Klicke dann in der Projekt-Ansicht mit der rechten Maustaste auf den Dateinamen und dann auf Properties. In dem folgenden Dialog musst du die Option "Add To Parse" einschalten, dann funktioniert es.

Kritik

Der ESP82xx Chip kann nur mit der Firmware des Herstellers genutzt werden, da viele wichtige Details der Hardware geheim gehalten werden. Wesentliche Teile der Firmware sind nur in Binärform ohne Quelltext veröffentlicht. Jede Anwendung ist somit zwangsläufig den Eigenheiten dieser Firmware ausgeliefert - auch Arduino, NodeMCU (Lua), und MicroPython.

Der Hersteller hat seine Software früh veröffentlicht, als sie noch sehr instabil lief. Dennoch stieß sie auf großes Interesse, besonders in der Arduino Community. Die letzte stabile Version ist das SDK 1.5.4 vom 20. Mai 2016. Beginnend mit Version 2.0 glich Espressif sein SDK an das besser strukturierte IDF des ESP32 an. Aber diese Sofware lief nie richtig stabil, und der Hersteller brach die Arbeit an dem Projekt ab. Die beiden letzten unvollendeten Varianten sind:

Das Datenblatt war anfangs eine Marketing Broschüre voller Angaben, die eher Wunschdenken als der Realität entsprachen. Über fast 10 Jahre verteilt wurden die Angaben dann schrittweise korrigiert und ergänzt. Achte daher darauf, mit einem aktuellen Datenblatt zu arbeiten.

Das Datenblatt nennt leider immer noch einige Features (I²C, PWM, IR Remote), die der Chip in Wirklichkeit nicht hat. Im Kleingedruckten dazu heißt es, dass man diese in Software implementieren "kann". Da die CPU in unregelmäßigen Abständen mit der WLAN Schnittstelle beschäftigt ist, ist es für Software jedoch unmöglich, Signale mit exakten Timings zu erzeugen. Dies äußert sich zum Beispiel in sichtbarem Flackern bei PWM gedimmten Lampen. Für die beliebten Neopixel LEDs (WS2812 und ähnliche) muss man die serielle Schnittstelle oder I²S mit DMA missbrauchen, um ausreichend genaue Signale zu erzeugen.

Ein mutmaßlicher Fehler im Design des Chips bewirkt, dass er sich beim Aufwachen aus dem Deep-Sleep Modus aufhängt. Deswegen muss der Timer Ausgang mit dem Reset Eingang verbunden werden, was einen kompletten Neustart der Firmware mit Verlust der Daten im RAM bewirkt.

Mit einem fehlerfreien Programm läuft der Chip sauber ohne Neustarts durch. Ich habe das zwei Jahre lang erfolgreich mit dem Arduino Core 2.3.0 durch getestet. Fehlerhafte Programme (z.B. mit Stack Überlauf) können den Chip jedoch dermaßen blockieren, dass sogar der Watchdog versagt. Auch der CHIP_EN Eingang funktioniert dann nicht mehr. Ein externer Reset funktioniert jedoch immer.

Der ADC Eingang taugt nur als grobes Schätzeisen, weil er nicht linear arbeitet und sich vom RF Interface stören lässt. Laut einer sehr gut versteckten Info im Datenblatt sind bis zu 20 % Abweichung möglich!

Die RTC läuft im Deep Sleep Modus so ungenau, dass sie praktisch unbrauchbar ist. Daher ist mir die fehlende Unterstützung im Arduino Core egal.

Bei all der Kritik möchte ich jedoch hervorheben, dass ich ESP8266 Module sehr gerne in Kombination mit dem Arduino Framework benutze. Sie sind billig und funktionieren zuverlässig, sofern man die hier genannten Macken berücksichtigt.

Nachfolger

Ich habe mich mit den nachfolgenden Chips von Espressif nur sehr wenig beschäftigt, weil ich ehrlich gesagt keine Lust habe, mich erneut mit mangelhafter Dokumentation und Software auseinander zu setzen.

Als direkten Nachfolger empfiehlt Espressif seit 2021 den ESP8684. Das ist ein abgespeckter ESP32-C2 mit einem RISC-V CPU Kern, Bluetooth und integrierten Flash Speicher. Allerdings kann er (Stand Feb. 2024) immer noch nicht mit Arduino programmiert werden.

Alle paar Monate kommen neue ESP32 Modelle auf den Markt, während andere entfallen. Die meisten ESP32 haben Bluetooth und mehr I/O Pins mit mehr Funktionen. Einige haben 2 CPU Kerne. Höhere Komplexität bezahlt man mit mehr Geld, Strom und Einarbeitungszeit. Programmiert werden sie primär mit dem ESP32 IDF in der Programmiersprache C. Für einige Modelle gibt es alternativ den einfacheren Arduino Core, womit nicht alle Funktionen nutzbar sind.

Ein zentraler Teil der Firmware ist weiterhin nur in Binärform ohne Quelltext verfügbar. WLAN und Bluetooth kann man bei den ESP32 nicht gleichzeitig benutzen.