ESP8266 ESP-12F standalone flashen: WLAN-Modul ohne Dev-Board in eigene Projekte einbauen
Auf jedem NodeMCU und jedem Wemos D1 Mini sitzt dasselbe silberne Blechkästchen: das ESP-12F. Der Rest der Platine ist nur Zubehör – USB-Chip, Spannungsregler, zwei Taster. Wenn du dein Projekt fest verbaust, brauchst du dieses Zubehör nicht mehr. Ein ESP-12F direkt auf der Lochrasterplatine ist kleiner, günstiger und zieht im Schlaf einen Bruchteil des Stroms. Dieser Artikel zeigt dir die komplette Minimalbeschaltung, warum genau diese fünf Widerstände nötig sind und wie du das Modul ohne USB-Buchse flashst.
Warum überhaupt das nackte Modul?
Ein fertiges Entwicklungsboard ist zum Ausprobieren unschlagbar. Sobald ein Projekt aber in ein Gehäuse wandert und dort jahrelang laufen soll, kippen die Argumente:
| Kriterium | NodeMCU / D1 Mini | ESP-12F pur |
|---|---|---|
| Grundfläche | ca. 48 × 26 mm bzw. 34 × 25 mm | 24 × 16 mm |
| Deep-Sleep-Strom | 0,3 – 9 mA (Regler + USB-Chip) | ca. 20 µA |
| Versorgung | 5 V über USB, Regler an Bord | 3,3 V, du musst selbst regeln |
| Flashen | USB anstecken, fertig | USB-TTL-Adapter + Boot-Pins |
| Nutzbare GPIOs | herausgeführt, teils belegt | alle, inklusive GPIO9/GPIO10 |
💡 Der Deep-Sleep-Wert ist das eigentliche Argument. Ein D1 Mini im Tiefschlaf zieht durch Regler und USB-Chip oft mehr Strom als ein ESP-12F im Betrieb pausiert. Für einen Batteriesensor, der einmal pro Stunde aufwacht, entscheidet genau das über „drei Wochen" oder „acht Monate" Laufzeit. Wie du das ausrechnest, steht weiter unten.
Die Pins, die du nicht frei wählen darfst
Das ESP-12F hat 22 Anschlüsse, aber sechs davon haben beim Start eine feste Bedeutung. Der ESP8266 liest beim Reset drei Pins ein und entscheidet daraus, ob er den Sketch startet oder auf neue Firmware wartet:
| Pin | Muss beim Start | Warum | Danach nutzbar als |
|---|---|---|---|
| EN (CH_PD) | HIGH über 10 kΩ | Chip-Enable, ohne Pullup startet nichts | – |
| RST | HIGH über 10 kΩ | Reset-Eingang, low-aktiv | – |
| GPIO15 | LOW über 10 kΩ | zwingt Boot aus dem Flash | Ausgang (z. B. LED, Relais) |
| GPIO0 | HIGH = normal, LOW = Flash-Modus | wählt die Boot-Quelle | freier GPIO, aber vorsichtig |
| GPIO2 | HIGH über 10 kΩ | muss beim Start high sein | Ausgang, interne LED |
| GPIO16 | frei | einziger Pin mit Wakeup-Fähigkeit | Brücke zu RST für Deep Sleep |
⚠️ Ohne den Pulldown an GPIO15 startet gar nichts. Das ist der häufigste Fehler beim ersten Standalone-Aufbau: Die Beschaltung sieht korrekt aus, der serielle Monitor zeigt nur wirres Zeug bei 74880 Baud, und man vermutet ein defektes Modul. In Wahrheit fehlt ein einziger 10-kΩ-Widerstand nach Masse. Alle fünf nötigen Widerstände findest du im 600er Widerstands-Sortiment.
⚠️ GPIO9 und GPIO10 sind eine Falle. Sie sind am ESP-12F herausgeführt, aber bei den üblichen Modulen mit QIO-Flash intern belegt. Nutzbar werden sie nur, wenn du den Flash-Modus auf DOUT stellst – und selbst dann läuft GPIO9 bei vielen Chargen nicht stabil. Plane sie nicht fest ein.
ℹ️ Die Boot-Meldung kommt mit 74880 Baud. Der ESP8266 gibt beim Start eine Zeile mit dem Boot-Modus aus – aber mit einer krummen Baudrate, die vom internen Oszillator abhängt. Stell den seriellen Monitor kurz auf 74880 um: Steht dort boot mode:(3,x), ist alles richtig verdrahtet. (1,x) bedeutet Flash-Modus, also GPIO0 liegt auf Masse.
Das brauchst du
Zusätzlich brauchst du einen USB-zu-Seriell-Adapter mit 3,3 V Signalpegel und einen 100-µF-Elko sowie einen 100-nF-Keramikkondensator direkt an den Versorgungspins. Wer keinen Adapter hat, kann auch einen UNO R3 zweckentfremden – dazu unten mehr.
1Die Minimalbeschaltung aufbauen
Sechs Verbindungen und fünf Widerstände – mehr braucht das Modul nicht, um zu laufen:
| ESP-12F Pin | Verbindung | Bauteil |
|---|---|---|
| VCC | 3,3 V | 100 µF Elko + 100 nF direkt am Pin |
| GND | Masse | – |
| EN (CH_PD) | 3,3 V | 10 kΩ Pullup |
| RST | 3,3 V | 10 kΩ Pullup, optional Taster nach GND |
| GPIO15 | GND | 10 kΩ Pulldown |
| GPIO0 | 3,3 V | 10 kΩ Pullup, Taster nach GND zum Flashen |
| GPIO2 | 3,3 V | 10 kΩ Pullup |
Und so kommt der USB-TTL-Adapter dran:
| USB-TTL | ESP-12F | Hinweis |
|---|---|---|
| TX | RXD (GPIO3) | gekreuzt! |
| RX | TXD (GPIO1) | gekreuzt! |
| GND | GND | gemeinsame Masse ist Pflicht |
| 3V3 | nicht verbinden | meist zu schwach – siehe Warnung |
⚠️ Versorge das Modul nicht aus dem USB-TTL-Adapter. Der ESP8266 zieht beim Verbindungsaufbau Stromspitzen von 300 bis 400 mA. Die 3,3-V-Ausgänge der meisten Adapter liefern 50 bis 150 mA. Das Ergebnis: Der Chip startet, bootet zur Hälfte, die Spannung bricht ein, er startet neu – eine Endlosschleife, die im Monitor wie ein defektes Modul aussieht. Nutze ein eigenes Netzteil oder den LM2596S und verbinde nur die Masse mit dem Adapter.
⚠️ 5 V zerstören das Modul. Weder VCC noch die GPIOs sind 5-V-tolerant. Ein Adapter, der mit 5-V-Pegeln sendet, killt den RX-Pin. Prüfe den Jumper am Adapter, bevor du ihn ansteckst – oder setze einen Spannungsteiler 1 kΩ / 2 kΩ in die TX-Leitung.
Zum Flashen ist die Reihenfolge entscheidend: GPIO0 auf GND halten → Reset auslösen (RST kurz auf GND) → GPIO0 loslassen → Upload starten. Danach einmal Reset ohne GPIO0, und der Sketch läuft.
2Erster Sketch: Lebenszeichen und Chip-Daten
Bevor du WLAN anfasst, prüfe die Grundlagen. Dieser Sketch verrät, ob Flash-Größe und Boot-Modus stimmen:
#include <ESP8266WiFi.h>
#define LED_PIN 2 // interne LED am ESP-12F, low-aktiv
void setup() {
Serial.begin(115200);
delay(200);
Serial.println();
Serial.println(F("--- ESP-12F Standalone Check ---"));
Serial.print(F("Chip-ID : 0x"));
Serial.println(ESP.getChipId(), HEX);
Serial.print(F("Flash-ID : 0x"));
Serial.println(ESP.getFlashChipId(), HEX);
Serial.print(F("Flash real : "));
Serial.print(ESP.getFlashChipRealSize() / 1024);
Serial.println(F(" kB"));
Serial.print(F("Flash im IDE : "));
Serial.print(ESP.getFlashChipSize() / 1024);
Serial.println(F(" kB"));
Serial.print(F("Freier RAM : "));
Serial.println(ESP.getFreeHeap());
Serial.print(F("Reset-Grund : "));
Serial.println(ESP.getResetReason());
if (ESP.getFlashChipRealSize() != ESP.getFlashChipSize()) {
Serial.println(F("ACHTUNG: Flash-Groesse in der IDE stimmt nicht!"));
}
pinMode(LED_PIN, OUTPUT);
WiFi.mode(WIFI_OFF); // Funk aus, spart im Test rund 70 mA
}
void loop() {
digitalWrite(LED_PIN, LOW); // LED an
delay(100);
digitalWrite(LED_PIN, HIGH); // LED aus
delay(900);
}
ℹ️ Board-Einstellung in der Arduino IDE: Wähle Generic ESP8266 Module, Flash Size 4MB (FS:2MB OTA:~1019KB), Flash Mode DOUT und Crystal Frequency 26 MHz. DOUT statt QIO ist wichtig – viele ESP-12F-Chargen booten mit QIO gar nicht. Zeigt der Sketch oben eine andere reale Flash-Größe als eingestellt, wird dein Dateisystem später überschrieben.
💡 Kein USB-TTL-Adapter zur Hand? Ein UNO R3 funktioniert als Notlösung: RESET des UNO fest auf GND legen (damit der ATmega schweigt), dann UNO-TX an ESP-TXD und UNO-RX an ESP-RXD – bei dieser Beschaltung nicht gekreuzt, weil du die Signale durchschleifst. Den 5-V-TX-Pfad unbedingt mit einem Spannungsteiler entschärfen.
3WLAN-Sensor mit Deep Sleep und GPIO16-Brücke
Jetzt der eigentliche Zweck: Der Sensor wacht auf, misst, sendet und schläft wieder. Damit das funktioniert, muss GPIO16 mit RST verbunden sein – nur GPIO16 kann den Chip aus dem Tiefschlaf holen:
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClient.h>
#include <DHT.h>
#define DHT_PIN 4 // GPIO4 = SDA-Position
#define DHT_TYP DHT22
#define SENSOR_PWR 5 // GPIO5 versorgt den Sensor - spart Schlafstrom
const char* SSID_NAME = "DeinWLAN";
const char* SSID_PASS = "DeinPasswort";
const char* ZIEL_URL = "http://192.168.1.50:8080/messwert";
const uint64_t SCHLAF_US = 15ULL * 60ULL * 1000000ULL; // 15 Minuten
DHT dht(DHT_PIN, DHT_TYP);
bool wlanVerbinden(uint16_t timeoutMs) {
WiFi.persistent(false); // spart Flash-Schreibzyklen
WiFi.mode(WIFI_STA);
WiFi.begin(SSID_NAME, SSID_PASS);
uint32_t start = millis();
while (WiFi.status() != WL_CONNECTED) {
if (millis() - start > timeoutMs) return false;
delay(50);
}
return true;
}
void schlafen() {
Serial.println(F("-> Deep Sleep"));
Serial.flush();
WiFi.disconnect(true);
ESP.deepSleep(SCHLAF_US, WAKE_RF_DEFAULT);
delay(100); // deepSleep braucht einen Moment
}
void setup() {
Serial.begin(115200);
delay(50);
pinMode(SENSOR_PWR, OUTPUT);
digitalWrite(SENSOR_PWR, HIGH); // Sensor einschalten
dht.begin();
delay(2000); // DHT22 braucht Anlaufzeit
float t = dht.readTemperature();
float h = dht.readHumidity();
digitalWrite(SENSOR_PWR, LOW); // Sensor sofort wieder aus
if (isnan(t) || isnan(h)) {
Serial.println(F("Sensorfehler - schlafe kurz und probiere neu"));
ESP.deepSleep(30ULL * 1000000ULL, WAKE_RF_DEFAULT);
delay(100);
return;
}
Serial.printf("T=%.1f C H=%.1f %%\n", t, h);
if (!wlanVerbinden(12000)) {
Serial.println(F("Kein WLAN - Wert verworfen"));
schlafen();
return;
}
WiFiClient client;
HTTPClient http;
http.begin(client, ZIEL_URL);
http.addHeader("Content-Type", "application/json");
char body[96];
snprintf(body, sizeof(body),
"{\"temp\":%.1f,\"hum\":%.1f,\"rssi\":%d}",
t, h, WiFi.RSSI());
int code = http.POST(body);
Serial.printf("HTTP %d\n", code);
http.end();
schlafen();
}
void loop() {
// bleibt leer - nach dem Aufwachen laeuft immer setup()
}
⚠️ Die GPIO16-Brücke muss zum Flashen weg. Liegt GPIO16 fest auf RST, stört der Pin den Reset-Vorgang beim Upload. Praktische Lösung: einen Jumper oder eine Steckbrücke aus dem JST-Sortiment vorsehen, statt die Verbindung fest zu löten. Alternativ eine Diode (Kathode an RST) verwenden – dann zieht GPIO16 den Reset nur nach unten, blockiert ihn aber nicht.
⚠️ Maximale Schlafzeit beachten. Der ESP8266 schläft mit dem internen Timer maximal etwa 3 Stunden 35 Minuten am Stück (2^32 Mikrosekunden). Wer länger schlafen will, muss mehrfach aufwachen und mitzählen – oder einen DS3231 als externen Wecker einsetzen.
💡 WiFi.persistent(false) ist bei Deep-Sleep-Projekten Pflicht. Ohne diese Zeile schreibt der ESP8266 die WLAN-Zugangsdaten bei jedem Verbindungsaufbau erneut in den Flash. Bei 96 Aufwachvorgängen pro Tag sind das nach zwei Jahren rund 70.000 Schreibzyklen auf demselben Sektor – genug, um den Flash zu ruinieren.
4Batteriespannung messen: die 1-Volt-Falle am TOUT
Das ESP-12F hat genau einen Analogeingang, den Pin ADC (TOUT). Anders als beim NodeMCU sitzt hier kein Spannungsteiler auf der Platine – der Eingang verträgt maximal 1,0 V:
ADC_MODE(ADC_VCC); // Variante A: misst die eigene Versorgungsspannung
// --- Variante A: Versorgung ohne externe Bauteile messen ---
// Der ADC-Pin muss dabei UNBESCHALTET bleiben!
void zeigeVcc() {
uint16_t mv = ESP.getVcc(); // liefert Millivolt
Serial.print(F("Vcc: "));
Serial.print(mv / 1000.0, 3);
Serial.println(F(" V"));
}
/* --- Variante B: externe Spannung ueber Teiler messen ---
Zeile ADC_MODE(ADC_VCC) oben entfernen, dann gilt der Pin als Eingang.
Teiler fuer eine 18650-Zelle (max. 4,2 V) auf 1,0 V:
R1 = 470k von Batterie+ zum ADC-Pin
R2 = 150k vom ADC-Pin nach GND
-> Faktor (470+150)/150 = 4,133
*/
#define ADC_PIN A0
const float TEILER = 4.133; // real nachmessen!
const float ADC_VOLL = 1.0; // 1023 entspricht 1,0 V
float batterieVolt() {
uint32_t summe = 0;
for (uint8_t i = 0; i < 16; i++) {
summe += analogRead(ADC_PIN);
delay(2);
}
float roh = summe / 16.0;
return (roh / 1023.0) * ADC_VOLL * TEILER;
}
uint8_t ladezustand(float u) {
if (u >= 4.15) return 100;
if (u <= 3.30) return 0;
if (u > 3.85) return (uint8_t)(70 + (u - 3.85) * (30.0 / 0.30));
if (u > 3.60) return (uint8_t)(20 + (u - 3.60) * (50.0 / 0.25));
return (uint8_t)((u - 3.30) * (20.0 / 0.30));
}
// --- Unterspannungsschutz: lieber schlafen als die Zelle tiefentladen ---
void pruefeBatterie() {
float u = batterieVolt();
Serial.printf("Akku: %.2f V (%u %%)\n", u, ladezustand(u));
if (u < 3.25) {
Serial.println(F("Unterspannung - dauerhafter Tiefschlaf"));
ESP.deepSleep(0); // wacht nur noch per RST-Taster auf
delay(100);
}
}
⚠️ 3,3 V direkt an TOUT zerstören den ADC. Der Eingang ist auf 1,0 V ausgelegt, nicht auf 3,3 V. Wer eine NodeMCU-Anleitung kopiert, in der A0 einfach an den Sensor geht, vergisst den Teiler, der dort auf der Platine sitzt. Beim nackten Modul musst du ihn selbst bauen – Widerstände dafür findest du im 600er Sortiment.
ℹ️ ADC_MODE(ADC_VCC) und externe Messung schließen sich aus. Der Chip kann entweder den Pin auslesen oder die eigene Versorgung – nicht beides. Wenn dein Projekt hinter einem Regler läuft, ist Variante A nutzlos (du misst dann immer 3,3 V). Direkt an der Zelle betrieben, spart Variante A dagegen zwei Widerstände und den Ruhestrom des Teilers.
5Konfigurierbarer Webserver mit gespeicherten Einstellungen
Ein fest verbautes Modul willst du nicht zum Umkonfigurieren ausbauen. Dieser Sketch bringt einen kleinen Webserver mit, der Schwellwerte im EEPROM ablegt:
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <EEPROM.h>
#define RELAIS_PIN 15 // GPIO15 - nach dem Boot frei nutzbar
#define EE_MAGIC 0xA5
struct Konfig {
uint8_t magic;
uint16_t intervallSek;
int16_t schwelleZehntelGrad;
};
Konfig cfg;
ESP8266WebServer server(80);
void konfigLaden() {
EEPROM.begin(sizeof(Konfig));
EEPROM.get(0, cfg);
if (cfg.magic != EE_MAGIC) { // erster Start
cfg.magic = EE_MAGIC;
cfg.intervallSek = 300;
cfg.schwelleZehntelGrad = 220; // 22,0 Grad
EEPROM.put(0, cfg);
EEPROM.commit();
}
}
void konfigSpeichern() {
EEPROM.put(0, cfg);
EEPROM.commit();
}
String seite() {
String s = F("<!DOCTYPE html><html><head><meta charset='utf-8'>"
"<meta name='viewport' content='width=device-width,initial-scale=1'>"
"<title>ESP-12F</title></head><body>"
"<h2>Einstellungen</h2><form action='/set'>");
s += F("Intervall (s): <input name='iv' value='");
s += cfg.intervallSek;
s += F("'><br><br>Schwelle (Grad): <input name='sw' value='");
s += cfg.schwelleZehntelGrad / 10.0;
s += F("'><br><br><button>Speichern</button></form>");
s += F("<p>RSSI: ");
s += WiFi.RSSI();
s += F(" dBm<br>Laufzeit: ");
s += millis() / 1000;
s += F(" s</p></body></html>");
return s;
}
void handleSet() {
if (server.hasArg("iv")) {
long v = server.arg("iv").toInt();
if (v >= 10 && v <= 3600) cfg.intervallSek = (uint16_t) v;
}
if (server.hasArg("sw")) {
float v = server.arg("sw").toFloat();
if (v > -40.0 && v < 85.0) cfg.schwelleZehntelGrad = (int16_t)(v * 10);
}
konfigSpeichern();
server.sendHeader("Location", "/");
server.send(302, "text/plain", "");
}
void setup() {
Serial.begin(115200);
pinMode(RELAIS_PIN, OUTPUT);
digitalWrite(RELAIS_PIN, LOW);
konfigLaden();
WiFi.mode(WIFI_STA);
WiFi.begin("DeinWLAN", "DeinPasswort");
while (WiFi.status() != WL_CONNECTED) { delay(250); Serial.print('.'); }
Serial.println();
Serial.print(F("IP: "));
Serial.println(WiFi.localIP());
server.on("/", []() { server.send(200, "text/html", seite()); });
server.on("/set", handleSet);
server.on("/an", []() { digitalWrite(RELAIS_PIN, HIGH); server.send(200, "text/plain", "an"); });
server.on("/aus", []() { digitalWrite(RELAIS_PIN, LOW); server.send(200, "text/plain", "aus"); });
server.begin();
}
void loop() {
server.handleClient();
}
ℹ️ GPIO15 als Relaisausgang ist ideal. Er hat durch den Boot-Pulldown bereits einen definierten Low-Pegel beim Start – dein KY-019 Relaismodul mit High-Level-Trigger schaltet also beim Einschalten garantiert nicht kurz durch. Bei GPIO0 oder GPIO2 wäre das anders, die sind beim Boot high.
Wie lange hält die Batterie wirklich?
Die Rechnung ist einfacher, als viele denken. Entscheidend ist nicht der Deep-Sleep-Strom allein, sondern wie lange das Modul pro Zyklus wach ist:
| Phase | Strom | Dauer je Zyklus | Ladung |
|---|---|---|---|
| Deep Sleep | 0,02 mA | 900 s | 0,005 mAh |
| Boot + Sensor | 25 mA | 2,2 s | 0,015 mAh |
| WLAN verbinden | 75 mA | 3,5 s | 0,073 mAh |
| Senden | 140 mA | 0,3 s | 0,012 mAh |
| Summe je 15 min | – | – | 0,105 mAh |
Das sind 96 Zyklen pro Tag, also rund 10,1 mAh täglich. Eine 18650-Zelle mit 2600 mAh reicht damit rechnerisch etwa 257 Tage – realistisch mit Reglerverlusten und Selbstentladung gut ein halbes Jahr. Die größte Stellschraube ist die WLAN-Verbindungszeit:
// Statische IP spart 2 bis 3 Sekunden Verbindungszeit -
// das ist der groesste Hebel fuer die Batterielaufzeit ueberhaupt.
IPAddress ip(192, 168, 1, 77);
IPAddress gw(192, 168, 1, 1);
IPAddress sn(255, 255, 255, 0);
IPAddress dns(192, 168, 1, 1);
// Kanal und BSSID merken - spart den kompletten Scan.
// Werte einmal per WiFi.channel() / WiFi.BSSID() auslesen.
uint8_t kanal = 6;
uint8_t bssid[6] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 };
bool schnellVerbinden() {
WiFi.persistent(false);
WiFi.mode(WIFI_STA);
WiFi.config(ip, gw, sn, dns);
WiFi.begin("DeinWLAN", "DeinPasswort", kanal, bssid, true);
uint32_t start = millis();
while (WiFi.status() != WL_CONNECTED) {
if (millis() - start > 8000) return false;
delay(10);
}
Serial.printf("Verbunden nach %lu ms\n", millis() - start);
return true;
}
💡 Mit statischer IP, festem Kanal und bekannter BSSID sinkt die Wachzeit von etwa 6 Sekunden auf unter 1,5 Sekunden. Das vervierfacht die Laufzeit – ohne dass du am Aufbau etwas ändern musst. Mehr zum Sparen im Betrieb steht im Artikel ESP32 Deep Sleep Tutorial, das Prinzip ist identisch.
Troubleshooting
⚠️ espcomm_sync failed beim Upload: Der Chip ist nicht im Flash-Modus. Reihenfolge einhalten – GPIO0 auf GND, dann Reset, dann Upload. Und prüfe, ob TX und RX vertauscht sind; das ist der zweithäufigste Grund.
⚠️ Endlose Neustarts, im Monitor steht wdt reset: Die Versorgung bricht ein. 100 µF Elko plus 100 nF direkt an VCC/GND des Moduls setzen und die Stromquelle prüfen. Ein USB-TTL-Adapter allein reicht nicht.
⚠️ Nur Zeichensalat im seriellen Monitor: Falsche Baudrate. Der Bootloader spricht 74880 Baud, dein Sketch meist 115200. Beides ist normal – stell den Monitor passend um.
⚠️ Der Sketch läuft, aber das Modul wacht aus Deep Sleep nie auf: Die Brücke GPIO16 zu RST fehlt oder hat eine kalte Lötstelle. Nachmessen: Im Schlaf muss GPIO16 kurz vor dem Wecken auf Masse gehen.
⚠️ WLAN bricht sporadisch ab, RSSI ist schlecht: Die Antenne des ESP-12F ist die Mäanderstruktur am Rand des Moduls. Unter ihr darf keine Kupferfläche und kein Metall liegen. Auf Lochraster heißt das: Das Modul so anordnen, dass die Antenne über die Platinenkante hinausragt.
⚠️ Nach dem Löten startet nichts mehr: Das ESP-12F ist temperaturempfindlich. Bei mehr als etwa drei Sekunden pro Pad mit 350 Grad Lötkolben leidet der Chip. Nutze eine Adapterplatine mit 2,54-mm-Raster oder löte zügig mit dünnem Lot.
⚠️ ESP.getFlashChipRealSize() meldet 1 MB statt 4 MB: Du hast ein ESP-12E oder eine ältere Charge erwischt. Stell die Flash-Größe in der IDE passend ein, sonst überschreibt das Dateisystem deinen Programmcode.
Praxistipps
- Erst auf Adapterplatine, dann fest verlöten. Ein ESP-12F auf einer 2,54-mm-Adapterplatine lässt sich auf Lochraster stecken und im Fehlerfall tauschen, ohne die ganze Schaltung neu zu bauen.
- Flash-Header vorsehen. Vier Pins – TX, RX, GND, GPIO0 – als Stiftleiste herausführen. Das kostet nichts und erspart dir später das Aufschrauben des Gehäuses. Für OTA-Updates lohnt sich zusätzlich der Artikel OTA-Updates über WLAN.
- Sensoren über einen GPIO versorgen. Ein DHT22 zieht auch im Ruhezustand Strom. Hängt er an einem Ausgangspin statt fest an 3,3 V, ist er im Schlaf komplett aus.
- Pulldown an GPIO15 nicht durch Sensor ersetzen. Manche Module haben eigene Pullups, die den Boot-Pegel kippen. Miss nach dem Anlöten aller Bauteile nach, ob GPIO15 im Ruhezustand wirklich unter 0,3 V liegt.
- Elko so nah wie möglich. Zehn Zentimeter Draht zwischen Kondensator und Modul machen ihn wirkungslos. Sendespitzen sind schnell – der Puffer muss direkt am Pin sitzen.
- Für Displays das kleine OLED nehmen. Das 0,91 Zoll OLED mit 128x32 braucht nur halb so viel RAM für den Framebuffer wie ein 128x64-Modell – auf dem ESP8266 mit seinen 80 kB spürbar.
- Ein zweites Modul als Reserve. Beim ersten Standalone-Aufbau geht erfahrungsgemäß eins kaputt – meist durch 5 V an einem Pin. Das ist Lehrgeld, kein Grund zur Panik.
🚀 Bauteile für dein Standalone-Projekt
- ESP8266 ESP-12F WiFi-Modul – 4 MB Flash, 24 × 16 mm
- 600er Widerstands-Sortiment – Boot-Beschaltung und Spannungsteiler
- LM2596S Step-Down-Wandler – stabile 3,3 V mit Reserve
- TP4056 Lademodul (3er Set) – Akkubetrieb mit Schutzschaltung
- DHT22 / AM2302 Sensor – Temperatur und Luftfeuchte
- 0,91 Zoll OLED 128x32 – kompakte Statusanzeige
- Lochrasterplatinen FR4 (5er Set) – für den dauerhaften Aufbau
- JST-XH Stecker-Sortiment – steckbare Sensor- und Akkuleitungen
- 22AWG Kabel 2-adrig und Dupont-Jumperkabel
Fazit
Das ESP-12F standalone zu betreiben wirkt beim ersten Mal wie ein Rückschritt – man tauscht eine USB-Buchse gegen fünf Widerstände und eine Prozedur aus Tastendrücken. Der Gewinn zeigt sich erst im fertigen Gerät: ein Zwanzigstel der Grundfläche, 20 µA statt mehreren Milliampere im Schlaf und ein Aufbau, der genau die Bauteile enthält, die dein Projekt wirklich braucht.
Wenn du dir die vier Regeln merkst – EN und RST mit Pullup, GPIO15 mit Pulldown, GPIO0 für den Flash-Modus, GPIO16 an RST für Deep Sleep – ist der Rest normale ESP8266-Programmierung. Und wenn das erste selbstgebaute Modul dann ein halbes Jahr lang stündlich seine Messwerte funkt, ohne dass du es je wieder anfassen musst, war der Umweg über die fünf Widerstände jede Minute wert.