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, der ursprünglich von Adam Dunkels entwickelt wurde. Es werden zahlreiche handliche Module mit diesen Mikrochips verkauft.
Normalerweise werden die kleinen ESP-Module mit der sogenannten "AT-Firmware" verkauft, die es ermöglicht, sie so ähnlich wie analoge Modems oder Bluetooth Module zu benutzen. Der seriell angeschlossene Mikrocontroller sendet dann Befehle an das Modul, um Verbindungen aufzubauen und Daten zu übertragen. In meinem Buch Einstieg in die Elektronik mit Mikrocontrollern habe ich gezeigt, wie man auf diese Weise einen kleinen Webserver zum Fernsteuern einer Lampe baut.
Man kann aber auch eigene Programme direkt durch den ESP Chip ausführen lassen. Mehr dazu weiter unten. Mit Preisen ab 1,50 € sind die ESP Module eine sehr preisgünstige Netzwerk-Anbindung zum Basteln.
Datenblätter: ESP8266, ESP8285
Die Minimal-Beschaltung zur Nutzung der AT-Firmware sieht so aus:
Modul Pin | Arduino Pin | Name | Beschreibung |
---|---|---|---|
1 | 3 | RxD (GPIO3) | serieller Eingang oder normaler I/O Pin |
2 | VCC | Spannungsversorgung 3,3 V 500 mA | |
3 | 0 | GPIO0 | Low beim Start aktiviert Firmware-Upload, muss zum normalen Start offen sein oder auf High liegen |
4 | RESET | Low=Reset | |
5 | 2 | GPIO2 (TxD1) | Ist mit der blauen LED verbunden, die bei LOW Pegel leuchtet. Flackert beim Start. Darf beim Start nicht auf Low gezogen werden. Ausgang vom zweiten UART, der nur Ausgabe kann. |
6 | CHIP_EN | Muss auf High gezogen werden, damit der Chip arbeitet. Low=Chip Power Down, High=Chip Enabled | |
7 | GND | Masse | |
8 | 1 | TxD (GPIO1) | serieller Ausgang oder normaler I/O Pin, ist mit der blauen LED verbunden, flackert beim Start, darf beim Start nicht auf Low gezogen werden |
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.
GPIO15 ist fest mit GND verbunden. Passe auf, dass du ihn nicht versehentlich als Ausgang programmierst, denn ein Kurzschluss kann den Pin möglicherweise so zerstören, dass der Chip nicht mehr startet.
Die Reichweite der primitiven Antenne (Leiterschleife) ist mit Smartphones vergleichbar.
Diese Module enthalten alle den ESP8266 Chip und einen Flash-Speicher. Mein persönlicher Favorit ist das ESP-12F.
Die Minimal-Beschaltung zur Nutzung der AT-Firmware sieht für diese Module so aus:
Modul Pin | Arduino Pin | ESP Name | Beschreibung |
---|---|---|---|
1 | RESET | Low=Reset, siehe die obigen Teil-Schaltpläne | |
2 | 17 | ADC | Analoger Eingang 0 bis 1 V |
3 | CHIP_EN | Muss auf High gezogen werden, damit der Chip arbeitet. Low=Chip Power Down, High=Chip Enabled | |
4 | 16 | GPIO16 | Im Deep-Sleep Modus: Ausgang vom Wakeup-Timer |
5 | 14 | GPIO14 (SCK) | Normaler I/O Pin oder SPI Takt |
6 | 12 | GPIO12 (MISO) | Normaler I/O Pin oder SPI Daten |
7 | 13 | GPIO13 (MOSI) | Normaler I/O Pin oder SPI Daten |
8 | VCC | Spannungsversorgung 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 | 15 | GPIO15 (CS) | Normaler I/O Pin oder SPI Chip Select, muss beim Start auf Low gezogen werden, flackert beim Start |
17 | 2 | GPIO2 (TxD1) | Ist mit der blauen LED verbunden, die bei LOW Pegel leuchtet. Flackert beim Start. Darf beim Start nicht auf Low gezogen werden. Ausgang vom zweiten UART, der nur Ausgabe kann. |
18 | 0 | GPIO0 | Low beim Start aktiviert Firmware-Upload, muss zum normalen Start offen sein oder auf High liegen |
19 | 4 | GPIO4 | Normaler I/O Pin |
20 | 5 | GPIO5 | Normaler I/O Pin |
21 | 3 | RxD (GPIO3) | serieller Eingang oder normaler I/O Pin |
22 | 1 | TxD (GPIO1) | serieller Ausgang oder normaler I/O Pin, flackert beim Start, darf beim Start nicht auf Low gezogen werden |
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!
Das NodeMCU Board besteht aus einem ESP-12 Modul mit Spannungsregler und USB-UART Interface. Der Flash Speicher ist 4 Megabytes groß. Für die erstem Programmierversuche ist das die ideale Ausstattung.
Das originale NodeMCU Board wird nicht mehr hergestellt, wohl aber zahlreiche Nachbauten.
Board J2 | NodeMCU Label | Arduino Pin | ESP Name | Beschreibung |
---|---|---|---|---|
1 | VIN | Spannungsversorgung 5 bis 9 V 500 mA | ||
2 | G | GND | Gemeinsame Masse | |
3 | RST | RESET | Hat 12 kΩ Pull-Up Widerstand und einen Taster mit 470 Ω nach GND | |
4 | EN | CHIP_EN | Low=Chip Power Down, High=Chip Enabled, hat 12 kΩ Pull-Up | |
5 | 3V | VCC | Spannungsversorgung 3,3 V (Eingang 500 mA oder Ausgang max. 300 mA) | |
6 | G | GND | Gemeinsame Masse | |
7 | Reserviert. Durch den Flash Speicher belegt. | |||
8 | ||||
9 | ||||
10 | ||||
11 | ||||
12 | ||||
13 | Reserviert | |||
14 | ||||
15 | A0 | 17 | ADC | Analoger Eingang für 0 bis 3,2 V weil mit Spannungsteiler 220 kΩ + 100 kΩ |
Board J1 | NodeMCU Label | Arduino Pin | ESP Name | Beschreibung |
---|---|---|---|---|
1 | 3V | VCC | Spannungsversorgung 3,3 V (Eingang 500 mA oder Ausgang max. 300 mA) | |
2 | G | GND | Gemeinsame Masse | |
3 | TX (D10) | 1 | TxD (GPIO1) | Serieller Ausgang des ESP über 470 Ω mit dem USB-UART verbunden, flackert beim Start, darf beim Start nicht auf Low gezogen werden |
4 | RX (D9) | 3 | RxD (GPIO3) | Serieller Eingang des ESP über 470 Ω mit dem USB-UART verbunden |
5 | D8 | 15 | GPIO15 (CS) | Normaler I/O Pin oder SPI Chip Select, muss beim Start Low sein, hat 12 kΩ Pull-Down Widerstand, flackert beim Start |
6 | D7 | 13 | GPIO13 (MOSI) | Normaler I/O Pin oder SPI Daten |
7 | D6 | 12 | GPIO12 (MISO) | Normaler I/O Pin oder SPI Daten |
8 | D5 | 14 | GPIO14 (SCK) | Normaler I/O Pin oder SPI Takt |
9 | G | GND | Gemeinsame Masse | |
10 | 3V | VCC | Spannungsversorgung 3,3 V (Eingang 500 mA oder Ausgang max. 300 mA) | |
11 | D4 | 2 | GPIO2 (TxD1) | Ist mit der blauen LED verbunden, die bei LOW Pegel leuchtet. Flackert beim Start. Muss beim Start high sein. Hat 12 kΩ Pull-Up Widerstand. Ausgang vom zweiten UART, der nur Ausgabe kann. |
12 | D3 | 0 | GPIO0 | Low beim Start aktiviert Firmware-Upload, hat 12 kΩ Pull-Up Widerstand und einen Taster mit 470 Ω nach GND, flackert beim Start |
13 | D2 | 4 | GPIO4 | Normaler I/O Pin |
14 | D1 | 5 | GPIO5 | Normaler I/O Pin |
15 | D0 | 16 | GPIO16 | Ist mit der blauen LED verbunden, die bei Low leuchtet. Im Deep-Sleep Modus: Ausgang vom Wakeup-Timer |
In Arduino kann man die NodeMCU Labels nutzen, ich empfehle allerdings, die Arduino Pin Nummern zu verwenden da sie den GPIO Nummern des Chips entsprechen.
Man kann es 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 Eingebaute Spannungsregler hat für externe Erweiterungen maximal 300 mA Leistungsreserve bei 5 V Eingangsspannung. Für Batteriebetrieb eignet sich das Board eher nicht, da es eine Ruhestromaufnahme von etwa 15 mA hat.
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 |
Aus | Ein | Low | High |
Ein | Aus | High | Low |
Dafür sind die beiden über Kreuz verbundenen Transistoren im Schaltplan des NodeMCU Boardes zuständig. Alternativ kann man den Firmware-Upgrade Modus manuell aktivieren, indem man beide Tasten drückt und dann den Reset-Taster zuerst loslässt.
Das Wemos D1 Mini Board gibt es in folgenden Versionen:
Version | ESP Chip | Flash MByte | LED an GPIO2 | Antenne | Lithium Laderegler |
---|---|---|---|---|---|
Wemos D1 Mini Lite v1 | ESP8285 | 1 | ja | Leiterschleife | nein |
Wemos D1 Mini v2 | ESP-12 Modul (=ESP8266) | 4 | nein | Leiterschleife | nein |
Wemos D1 Mini v3 | ESP8266 | 4 | ja | Leiterschleife | nein |
Wemos D1 Mini Pro v1 (oder -16) | ESP8266 | 16 | ja | Keramikantenne und ext. Antennenanschluss | nein |
Wemos D1 Mini Pro v2 | ESP8266 | 16 | ja | Keramikantenne und ext. Antennenanschluss | ja |
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:
Board Pin | NodeMCU Label | Arduino Pin | ESP Name | Beschreibung |
---|---|---|---|---|
1 | RST | RESET | Hat 10 kΩ Pull-Up Widerstand und einen 100 nF Kondensator nach GND | |
2 | A0 | 17 | ADC | Analoger Eingang für 0 bis 3,2 V weil mit Spannungsteiler 220 kΩ + 100 kΩ |
3 | D0 | 16 | GPIO16 | Im Deep-Sleep Modus: Ausgang vom Wakeup-Timer |
4 | D5 | 14 | GPIO14 (SCK) | Normaler I/O Pin oder SPI Takt |
5 | D6 | 12 | GPIO12 (MISO) | Normaler I/O Pin oder SPI Daten |
6 | D7 | 13 | GPIO13 (MOSI) | Normaler I/O Pin oder SPI Daten |
7 | D8 | 15 | GPIO15 (CS) | Normaler I/O Pin oder SPI Chip Select, muss beim Start Low sein, hat 10 kΩ Pull-Down Widerstand, flackert beim Start |
8 | 3V3 | VCC | Spannungsversorgung 3,3 V (Eingang 500 mA oder Ausgang max. 50 mA) | |
9 | 5V | Spannungsversorgung 4 bis 7 V 500 mA | ||
10 | G | GND | Gemeinsame Masse | |
11 | D4 | 2 | GPIO2 (TxD1) | Alle außer Mini v2 haben eine blaue LED, die bei Low Pegel leuchtet. Flackert beim Start. Muss beim Start high sein. Hat 10 kΩ Pull-Up Widerstand. Ausgang vom zweiten UART, der nur Ausgabe kann. |
12 | D3 | 0 | GPIO0 | Low beim Start aktiviert Firmware-Upload, hat 10 kΩ Pull-Up Widerstand, flackert beim Start |
13 | D2 | 4 | GPIO4 | Normaler I/O Pin |
14 | D1 | 5 | GPIO5 | Normaler I/O Pin |
15 | RX (D9) | 3 | RxD (GPIO3) | Serieller Eingang des ESP über 470 Ω mit dem USB-UART verbunden |
16 | TX (D10) | 1 | TxD (GPIO1) | Serieller Ausgang des ESP über 470 Ω mit dem USB-UART verbunden, flackert beim Start, darf beim Start nicht auf Low gezogen werden |
In Arduino kann man die NodeMCU Labels nutzen, ich empfehle allerdings, die Arduino Pin Nummern zu verwenden da sie den GPIO Nummern des Chips entsprechen.
Man kann es wahlweise am 3,3V Eingang mit 2,8 bis 3,6 V betreiben, oder am 5 V Eingang mit 4 bis 7 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 300 µA, so dass es für Batteriebetrieb 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).
Der Reset Taster zieht den Reset-Pin ohne Schutzwiderstand direkt auf GND. Außerdem besitzt das Board die gleiche Reset Schaltung wie das NodeMCU Board, zum automatischen Aktivieren des Firmware-Upgrade Modus. Das Wemos D1 Mini hat keinen "Flash" Taster.
Der Analoge Eingang A0 ist mit einem Spannungsteiler (220kΩ + 100kΩ) ausgestattet, damit man Spannungen bis zu 3,2 V messen kann.
Dokumentation des Herstellers.
Achtung: Es sind schlechte Nachbauten mit zu schwachem Spannungsregler im Umlauf.
Das WIFI Kit 8 (alias Heltec HTIT-W8266 oder Wemos TTGO ESP8266) aus China hat 4 MByte Flash Speicher, sowie ein winzig kleines 0,91" OLED Display mit 128x32 Pixeln. Darauf kann man Grafiken und 4x21 Zeichen Text ausgeben. 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:
![]() |
![]() |
![]() |
![]() ![]() |
Obere Stiftleiste:
Stift | Version A | Version B | Arduino Pin | Beschreibung |
---|---|---|---|---|
1 | GND | |||
2 | 5 V | Spannungsversorgung 5 V 500 mA | ||
3 | 3,3 V | Spannungsversorgung 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 | GPIO5 | 5 | Version A: I²C Takt zum Display mit 10 kΩ Pull-Up Widerstand Version B: Normaler I/O Pin. | |
8 | TxD (GPIO1) | 1 | Serieller Ausgang des ESP oder normaler I/O Pin, direkt mit dem USB-UART verbunden, flackert beim Start, darf beim Start nicht auf Low gezogen werden | |
9 | RxD ( | 3 | Serieller Eingang des ESP, direkt mit dem Ausgang des USB-UART verbunden, daher nicht als GPIO verwendbar. | |
10 | RESET | Hat 1,2 kΩ Pull-Up Widerstand und einen Taster nach GND | ||
11 | GPIO2 (TxD1) | GPIO4 | 2 bzw. 4 | Version A: Normaler I/O Pin, flackert beim Start, darf beim Start nicht auf Low gezogen werden. Ausgang vom zweiten UART, der nur Ausgabe kann. Version B: Reset Signal zum Display, Low aktiv. |
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 | Version A | Version B | Arduino Pin | Beschreibung |
---|---|---|---|---|
1 | GND | Gemeinsame Masse | ||
2 | 5 V | Spannungsversorgung 5 V 500 mA | ||
3 | 3,3 V | Spannungsversorgung 3,3 V (Eingang 500 mA oder Ausgang max. 200 mA) | ||
4 | GND | Gemeinsame Masse | ||
5 | GPIO4 | GPIO0 | 4 bzw. 0 | Version A: I²C Daten zum Display mit 10 kΩ Pull-Up Widerstand. Version B: Low beim Start aktiviert Firmware-Upload, hat 10 kΩ Pull-Up Widerstand und einen Taster nach GND, flackert beim Start |
6 | GPIO0 | GPIO2 (TxD1) | 0 bzw. 2 | Version A: Low beim Start aktiviert Firmware-Upload, hat 10 kΩ Pull-Up Widerstand und einen Taster nach GND, flackert beim Start. Version B: Normaler I/O Pin, flackert beim Start, darf beim Start nicht auf Low gezogen werden. Ausgang vom zweiten UART, der nur Ausgabe kann. |
7 | GPIO15 (CS) | 15 | Normaler I/O Pin oder SPI Chip Select, muss beim Start Low sein, hat 10 kΩ Pull-Down Widerstand, flackert beim Start | |
8 | GPIO13 (MOSI) | 13 | Normaler I/O Pin oder SPI Daten | |
9 | GPIO12 (MISO) | 12 | Normaler I/O Pin oder SPI Daten | |
10 | GPIO14 (SCK) | 14 | Version A: Normaler I/O Pin oder SPI Takt. Version B: I²C Takt zum Display mit 10 kΩ Pull-Up Widerstand | |
11 | GPIO16 | 16 | Version A: Setzt das Display bei Low Pegel zurück. Version A+B im Deep-Sleep Modus: Ausgang vom Wakeup-Timer | |
12 | ADC | 17 | Analoger Eingang für 0 bis 3,2 V weil mit Spannungsteiler 220 kΩ + 100 kΩ. In Arduino heißt der Pin A0 oder Nummer 17. |
Die Infos von Heltec passen zur Version A, sind aber unvollständig und fehlerhaft.
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 200 mA Leistungsreserve für Erweiterungen. Da der 5 V Anschluss direkt mit der USB Buchse verbunden ist, soll bei Nutzung von USB nicht gleichzeitig ein 5 V Netzteil verwendet werden.
Das Board eignet sich nur sehr bedingt für Akku-Betrieb, da seine Ruhestromaufnahme nie unter 6 mA fällt. 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 Reset Methode zum automatischen Aktivieren des Firmware-Upgrade Modus entspricht dem NodeMCU Board. Die beiden Taster ziehen die Leitungen RESET und GPIO0 direkt ohne Schutzwiderstände auf Low. Auch der USB-UART ist direkt mit den I/O Pins für TxD und RxD verbunden, deswegen kann man den RxD Pin (=GPIO3) nicht für andere Zwecke verwenden.
Ich hatte beim Experimentieren auf einem Steckbrett äußerst schlechten WLAN Empfang. Durch Verlängern der Anschlussbeine um 7 mm konnte ich das Problem beheben.
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.
Fertige Boards enthalten oft den AMS1117. Er ist schnell und stark, aber er hat eine hohe Ruhestromaufnahme und benötigt mindestens 10mA Last. In den Sleep und Power-Down Modi riskiert man, dass der Spannungsregler wegen zu wenig Last eine zu hohe Spannung ausgibt! Ich benutze daher lieber den LF33.
Egal woher die Stromversorgung kommt, empfehle ich dringend einen 100 µF Kondensator direkt an die Anschlüsse VCC und GND des ESP-Moduls zu löten. Beim NodeMCU Board ist dieser bereits vorhanden.
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 sind aufgrund der hohen Kontaktwiderstände schlecht zur Strom-Verteilung geeignet.
Die Widerstände um den Chip herum sollten maximal 2,2 kΩ haben, denn hochohmige Widerstände sind für die Funkwellen empfänglich. In der Nähe der Antenne sind Metallteile (auch Leiterbahnen) zu vermeiden, da sie den Empfang beeinträchtigen.
Ich empfehle dazu folgende Stromversorgung:
Für Batterien bis maximal 6 Volt empfehle ich den Spannungsregler HT7830 oder HT7833 mit 4 µA Ruhestrom. Gelegentlich wird der MCP1700 empfohlen, der ist mir mit seinen nominellen 250 mA aber zu knapp ausgelegt, denn der ESP braucht zeitweise 430 mA.
Alle drei Spannungsregler (und auch der weiter oben genannte LF33) haben gemein, dass sie bei zu geringer Eingangsspannung nicht gleich ausfallen, sondern eine entsprechend geringere Ausgangsspannung liefern. Beispielsweise sind bei 3,1 V Batteriespannung ungefähr 2,8 V Ausgangsspannung zu erwarten.
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.
Tipp: Es gibt zahlreiche andere Funktechniken, die wesentlich weniger Energie benötigen, als WLAN.
Beim Arduino Framework aktiviert den Deep-Sleep Modus so:
ESP.deepSleep(60000000); delay(100);
Wenn man den Wakeup-Timer benutzt, muss der Timer-Ausgang GPIO16 wie folgt mit dem RESET Eingang verbunden werden:
Dadurch wird das Reset-Signal ein bisschen verzögert und verlängert. Schau in den Schaltplan von deinem Board/Modul! Diese Bauteile sind wahrscheinlich zumindest teilweise bereits vorhanden.
Da der Timer von einem temperaturabhängigen R/C Oszillator getaktet wird, kann die Zeit zwei Prozent vom Soll abweichen. Das klingt nach wenig, sind aber 30 Minuten pro Tag!
Weil die Firmware beim Aufwachen neu startet, geht der Inhalt des RAM verloren. Die RTC enthält jedoch 512 Byte zusätzlichen Speicher, der den Deep-Sleep Modus (jedoch nicht Power-Down) überlebt. Davon sind die ersten 64 Bytes allerdings reserviert.
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.
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.
Die meisten 5 V Mikrocontroller (z.B. AVR) akzeptieren 3,3 V als gültigen High Pegel. Falls du den Signalpegel dennoch auf 5V erhöhen musst, kannst du das zum Beispiel so tun:
Diese Schaltung funktioniert mit jedem gewöhnlichen kleinen NPN Transistor. Im Handel gibt es bidirektionale Pegelwandler mit MOSFET zu kaufen, die sich auch eignen.
Der ESP8266 unterstützt folgende Zugriffsarten auf den Flash Speicher:
Welche der vier Varianten tatsächlich funktionieren, hängt vom eingebauten Speicherchip ab. Zum Ändern muss man den Quelltext der Firmware neu compilieren.
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.
CPU Freq. | Flash Freq. | Flash Mode | Antwortzeit | Rechenleistung |
---|---|---|---|---|
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-Upload:
GPIO1 und GPIO2 müssen beim Start auf HIGH Pegel liegen, was interne Pull-Up Widerstände erledigen. Der Bootloader gibt auf beiden seriellen Ports Meldungen mit 74880 Baud aus. Nach dem Start können alle vier Pins jedoch 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 gleichzeitig drücken und dann den Reset Taster zuerst loslassen. Der ESP Chip erwartet dann Kommandos und Daten vom PC.
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.
Es gibt zahlreiche grafische Programme zum hochladen der Firmware, aber die scheinen alle etwas zickig zu sein. Daher empfehle ich das Script esptool.py, welches meine beiden weiter unten bereitgestellten Firmware-Pakete enthalten. Zum Ausführen musst Du vorher Python installieren. Achte beim Ausführen der Installation darauf dass es zur PATH Variable hinzugefügt wird. Anschließend installiere die Library für serielle Ports, indem du im CMD Fenster (Eingabeaufforderung) pip install serial eingibst.
Anmerkung zu Linux:
Bei Debian/Ubuntu Linux installiert man die Library hingegen mit dem befehl sudo apt install python3-serial.
Außerdem heisst der bei Linux python3, nicht python.
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
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. Die Firma Espressif stellt ihre AT Firmware im bin Verzeichnis des SDK zur Verfügung. Dort befindet sich auch die Textdatei README.md, in der drin steht, welche Dateien abhängig von der Größe des Flash Speichers an welche Position geladen werden müssen.
Zum Testen von Netzwerkverbindungen empfehle ich das Kommandozeilen-Programm Netcat. 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
ATE0
AT+GMR
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
AT+RST
AT+CWLAP
+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"
AT+CWJAP?
+CWJAP:"Pussycat","5c:49:79:2d:5b:cd",7,-60 OK
AT+CIFSR
+CIFSR:STAIP,"192.168.0.111" +CIFSR:STAMAC,"5c:cf:7f:8b:a9:f1" OK
AT+CIPMUX=1
AT+CIPSERVER=1,5000
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!
AT+CIPSEND=0,9 > Welcome!
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
0,CLOSED OK
AT+CIPSTART=0,"TCP","mail.stefanfrings.de",25
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.
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
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.
AT+CIPSTART=0,"UDP","0",0,3002,2
AT+CIPSTART=0,"UDP","192.168.0.5",3001,3002,0
AT+CWMODE=2 AT+CWSAP="ESP-Modul","supersecret",5,3 AT+RST
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.
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.
Die Bastel-freundlichste Lösung ist meiner Meinung nach die ESP8266 Erweiterung für Arduino. Man programmiert dort in C++. Die Installation der Arduino IDE ist kinderleicht - kein Vergleich zum Espressif SDK.
Alle drei Varianten haben eines gemeinsam: Das Debuggen mit einer IDE ist nur sehr eingeschränkt möglich. In der Praxis wird man eher mit seriellen Log-Meldungen arbeiten, wie das bei Arduino ohnehin üblich ist.
Installation:
Falls deine Programme instabil laufen, versuche meine Bundles (Arduino IDE 1.8.13 mit ESP8266 Core 2.3.0): Linux Windows
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.
Lies die Dokumentation von Arduino und dem ESP8266 Core Version 2.3.0 / aktuelle Version. Die Doku von der Version 2.3.0 ist auch im obigen Bundle enthalten.
#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); }
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.
#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(); }
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
#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(); }
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
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:
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(); ... }
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.
ESP.deepSleep(1, WAKE_RF_DISABLED); delay(100);
So reaktiviert man die Schnittstelle wieder:
ESP.deepSleep(1, WAKE_RFCAL); delay(100);
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.
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. Außerdem rate ich dringend dazu, String Objekte zu meiden, weil sie davon intensiv Gebrauch machen. Mehr dazu hier.
Wenn man Daten sendet, wird aus jedem Client::print() und Client::write() Aufruf ein einzelnes Ethernet Paket. Viele kleine Pakete reduzieren die Performance, da sie genau so lange dauern, wie große Pakete. 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 Client::available() und Client::readBytes() einige Kilobytes am Stück zurück liefern, 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 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.
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:
Ich habe sowohl mit Netbeans als auch mit Qt-Creator gute Erfahrungen gemacht. Qt-Creator gefällt mir besser, weil es den Quelltext schon beim Tippen analysiert und auf mögliche Fehler hinweist.
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.
Verwende den Installer vom Qt SDK, um das Programm Qt-Creator zu installieren. Die optionalen Komponenten brauchst du nicht. Starte das Programm und gehe dann ins Menü Extras/Einstellungen/Kits/Compiler. Dort musst du den C Compiler und den C++ Compiler aus der ESP8266 Erweiterung für Arduino als Typ "MinGW" (unter Windows) bzw. "GCC" (unter Linux) hinzufügen. Bei mir sieht das unter Linux so aus:
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. Qt-Creator nutzt diese beiden Befehle, um die Standard-C Libraries automatisch zu finden.
Ganz unten in der Zeile "ABI" brauchst du nichts zu ändern, benutze dort einfach die Vorgabewerte, auch wenn sie bei Dir anders aussehen. Danach gehe in den "Kits" Reiter und lege dort ein neues Kit mit den gerade angelegten Compilern an:
Die CMAKE Konfiguration spielt keine Rolle, lasse sie einfach unverändert.
Anschließend kannst du das Arduino-Projekt über das Menü "Datei/Neu/Projekt importieren/Import eines existierenden Projekts" importieren. Gebe danach in der Datei "ProjektName.files" alle Dateien an, die du mit Qt-Creator editieren möchtest - also die *.ino, *.h und *.cpp Dateien.
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.13 deiner Arduino IDE an:
#define ARDUINO 010813
Nun kannst du deinen Sketch mit Qt-Creator editieren. Um ihn zu überprüfen (compilieren) und hochzuladen musst du weiterhin die Arduino IDE verwenden.
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:
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.
Der Hersteller hat sein SDK früh veröffentlicht, als es noch sehr instabil lief. Dennoch stieß es auf großes Interesse. Die SDK Version 1.5.3 (und der darauf aufbauende Arduino Core 2.3.0) waren die ersten Versionen auf die man sich ernsthaft verlassen konnte. Direkt danach wurde das Projekt mehrfach umstrukturiert und es brach eine Featuritis aus, die sich 3 Jahre lang negativ auf die Qualität ausgewirkt hatten.
Espressif hat seinen Chip lange Zeit mit beschönigten Zahlen als "besonders sparsam" beworben. Dabei gibt es von anderen Firmen ähnliche Produkte, die deutlich weniger Strom aufnehmen, insbesondere im Ruhezustand. Zum Beispiel Silabs AWM136 und Texas Instruments CC3120.
Das Datenblatt nennt einige Features (z.B. 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".
Beim Pin 7 CHIP_EN (der mehrfach umbenannt wurde) verheimlicht der Hersteller in seiner Dokumentation, dass dieser Eingang erst nach dem Start der Firmware richtig funktioniert.
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.
Nach einem Programmfehler (z.B. Stack Überlauf) blockiert der Chip manchmal. Der Watchdog erfüllt hier nicht immer seinen Zweck. Wenn der Chip hängt, reagiert er auch nicht mehr auf den CHIP_EN Eingang. Aber der Reset Eingang erfüllt seinen Zweck zuverlässig.
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 Framework egal.
Da die CPU in unregelmäßigen Abständen mit der WLAN Schnittstelle beschäftigt ist, ist es für Software 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 (WS2812 und ähnliche) muss man die serielle Schnittstelle oder I²S mit DMA missbrauchen, um ausreichend genaue Signale zu erzeugen.
Für Hobbyprojekte ist der Chip trotzdem interessant, vor allem wegen seines unschlagbaren Preises.