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. Dabei steuert man sie über eine serielle Schnittstelle mit Kommandos (wie analoge Modems und Bluetooth Module). Man kann auch eigene Programme in die Module laden.
Datenblätter: ESP8266, ESP8285
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.
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 | VCC | Spannungsversorgung 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, hat bei der "S" Version einen 12 kΩ Pull-Up Widerstand und einen 1µF Kondensator |
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. |
Doku von AI-Thinker ESP-01, AZ-Delivery ESP8266-01S, DOIT ESP-1.
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.
Das Modul eignet sich nicht für den Deep-Sleep Modus, weil GPIO16 nicht herausgeführt ist.
Die Reichweite der primitiven Antenne (Leiterschleife) ist mit Smartphones vergleichbar.
Diese Module kommen alle von der Firma AI-Thinker. Sie enthalten nur den ESP8266 Chip und einen Flash-Speicher.
Die Minimal-Beschaltung zur Nutzung der AT-Firmware sieht für diese Module so aus:
Pin | Name | Beschreibung |
---|---|---|
1 | RESET | LOW=Reset, siehe die obigen Teil-Schaltpläne |
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 | 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 | 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. |
Technische Doku des Herstellers
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.
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 | Spannungsversorgung 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 | VCC | Spannungsversorgung 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 | VCC | Spannungsversorgung 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 | VCC | Spannungsversorgung 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 |
Aus | Ein | LOW | HIGH |
Ein | Aus | 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.
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:
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 | VCC | Spannungsversorgung 3,3 V (Eingang 500 mA oder Ausgang max. 50 mA) |
9 | 5V | Spannungsversorgung 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. |
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. |
Dokumentation des Herstellers.
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 Kondensator 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.
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 | 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 | 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 |
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 | 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 | A: GPIO4 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 (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 | 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.
Fertige Boards enthalten oft den AMS1117, welcher mindestens 10 mA Last benötigt. Das heißt: Den Deep-Sleep Modus aktiviert man bei diesen Boards besser nicht.
Ich empfehle zur Verbesserung der Zuverlässigkeit einen 100 µF Kondensator direkt an den Anschlüssen VCC und GND des ESP-Moduls. Beim NodeMCU Board ist dieser bereits vorhanden. Ohne 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.
Dazu diese Spannungsregler:
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.
Im Deep-Sleep Modus beträgt die Stromaufnahme des ESP Chips (incl. Flash Speicher) etwa 20 µA.
Um die Stromaufnahme weiter zu minimieren würde ich einen zweiten Mikrocontroller (z.B. ATtiny45) direkt an die Batterie hängen, welcher die Hauptarbeit macht. Dieser würde das ESP Modul nur bei Bedarf mit Strom versorgen. So kommst du locker unter 2 µA Ruhestromaufnahme.
Beim Arduino Framework aktiviert man 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 des Chips verbunden werden:
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.
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.
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.
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.
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.
CPU Freq. | Flash Freq. | Flash Mode | beste Antwortzeit | Multiplikationen |
---|---|---|---|---|
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:
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
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:
+IPD,0,12:Lets start!
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.
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 die ESP8266 Erweiterung 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..
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 Version 2.3.0 bzw. die 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. 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:
In Kombination mit Arduino nutze ich am liebsten Visual Studio Code, weil es sich dank des Plugins weitgehend selbst konfiguriert.
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.
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.
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 mehrere Jahre lang negativ auf die Software-Qualität auwirkte.
Espressif hat seinen Chip lange Zeit mit falschen Zahlen als "besonders sparsam" beworben. Tatsächlich ist seine Stromaufnahme sogar etwas höher als beim Silabs AWM136 und Texas Instruments CC3120, um nur zwei Alternativen zu nennen. Jedoch ist WLAN generell recht energieaufwändig.
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". 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 (WS2812 und ähnliche) muss man die serielle Schnittstelle oder I²S mit DMA missbrauchen, um ausreichend genaue Signale zu erzeugen.
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. Mit einem fehlerfreien Programm und den oben genannten Software Versionen läuft er jedoch 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.
Für Hobbyprojekte sind ESP Module trotzdem interessant, vor allem wegen des unschlagbaren Preises.