Скетч ночника — мигалка на 500 мс и счётчик включений в EEPROM — я перенёс с Uno на NodeMCU за десять минут и застрял на час. Первая встреча: fatal error: WiFi.h: No such file or directory. Сети в скетче не было вовсе, но строка #include <WiFi.h> переехала из старого шаблона без присмотра: на ESP8266 такого файла нет, заголовок называется ESP8266WiFi.h, а всё остальное API внутри совпадает дословно. Поправил я строку — и упёрся в следующий сюрприз: светодиод мигал наоборот, а счётчик EEPROM после каждого рестарта начинался с единицы.
Этот урок — чек-лист переезда с Uno на 8266 по живым граблям: сетевая шапка, метки D на шелкографии против номеров GPIO, перевёрнутый бортовой светодиод, одинокий аналоговый вход с потолком 1 В и EEPROM, которая без двух новых строк молча ничего не сохраняет. В конце — таблица Uno против 8266 и самопроверка, которую я гоняю на любой новой плате прежде сетевых экспериментов. Выбор между самими платами — отдельный разговор, я собирал его с числами в уроке про ESP32 и ESP8266; здесь считаю, что плата уже на столе.
Шапка: одна строка include и вся сеть
Вся сетевая часть 8266 живёт в ESP8266WiFi.h: класс WiFi с теми же begin, status и localIP, что и на ESP32, поверх — тот же HTTPClient. Первый скетч с подключением к роутеру я разбирал в уроке про первый WiFi-запуск — механика begin/status переезжает на 8266 без правок, меняется только заголовок сверху. Ставятся пакеты обеих семей в одну IDE: если окно с платами ещё пустое, начните с урока про установку пакетов.
Вторая грабля шапки — выбранная в меню плата. Прошивка, собранная для ESP32, на 8266 не зальётся: загрузчики разные, и вместо привычных строк вы увидите мусор в порту. Я держу правило: плата в меню, кабель и скорость сверяются до первой загрузки — три секунды против вечера с непонятной тишиной.
HTTP-клиент переезжает тем же способом: на 8266 он лежит в своём заголовке ESP8266HTTPClient.h, а класс HTTPClient внутри — тот же, с begin, GET и getString. После переноса шапки мой старый скетч погоды скомпилировался со второго раза, и второй раз был нужен только потому, что я забыл запятую в массиве. Мораль простая: сначала все include по списку, потом правки кода — компилятор идёт сверху вниз и ругается первым делом на шапку.
Пины: D-метки и светодиод наоборот
На шелкографии NodeMCU пины подписаны метками D0-D8, а язык скетчей живёт по номерам GPIO: D4 — это GPIO2, D1 — GPIO5, D2 — GPIO4. Константы D0-D8 объявлены в описании платы, поэтому pinMode(D4, OUTPUT) работает честно — но стоит написать digitalWrite(4, HIGH), держа в голове метку D4, как вспыхивает чужой пин: число 4 — это GPIO4, на шелкографии он D2. Моя шпаргалка соответствий: D0 — GPIO16, D1 — 5, D2 — 4, D3 — 0, D4 — 2, D5 — 14, D6 — 12, D7 — 13, D8 — 15. Пины GPIO6-11 не трогаем вовсе — они кормят флеш-чип, и любой digitalWrite туда валит плату в рестарт.
Бортовой светодиод на NodeMCU висит на GPIO2 — на той самой D4 — и зажигается при LOW: digitalWrite(2, LOW) — горит, HIGH — погас. На внешнем светодиоде с резистором инверсии нет, а вот встроенный регулярно служит поводом для паники «пин не работает». С той же инверсией я встречался на Uno, где бортовой LED сидит на пине 13, — механика разобрана в первой мигалке.
| Параметр | Arduino Uno | ESP8266 (NodeMCU) |
|---|---|---|
| Логика на пинах | 5 В | 3.3 В: 5 В на GPIO выводит пин из строя |
| АЦП | шесть входов A0-A5, вход до 5 В | только A0 и только вход: чип ест до 1 В, плата с делителем — до 3.2 В |
| Флеш под скетч | 32 КБ | 1-4 МБ, на NodeMCU обычно 4 МБ |
| Оперативка | 2048 байта | 80 КБ, из них 40-50 КБ свободно рядом с WiFi-стеком |
| Такт и EEPROM | 16 МГц; EEPROM настоящая, 1 КБ | 80 МГц, разгон до 160; EEPROM эмулируется во флеше |
Такт и уровни — то, что меняет поведение схемы ещё до первой строки кода. Восемьдесят мегагерц против шестнадцати на Uno чувствуется во всём: перебор массивов, деления и печать больших логов идут в разы быстрее, а в меню платы есть и разгон до 160 МГц для жадных до тактов скетчей. Зато логика здесь 3.3 В: вход читает 3.3 В как HIGH спокойно, но подавать 5 В сигналом на GPIO, и особенно на RX, нельзя — нужен делитель или согласователь уровней. Модули, питающиеся от 5 В, чаще всего живут с 8266 напрямую: реле-модуль с оптопарой и дисплей с собственным контроллером срабатывают от 3.3 В на входе — но каждый раз проверяю порог по паспорту модуля, а не по совету из комментария на маркете.
Аналоговая часть — самый тихий и самый дорогой тупик переезда. У чипа один аналоговый вход, он же только вход: ни digitalRead по нему как по цифровому, ни analogWrite — A0 в этом смысле куда скромнее шести входов Uno. Диапазон чипа — ровно 1 В: всё, что выше, вход не умеет. На NodeMCU и Wemos D1 mini перед A0 стоит резисторный делитель, расширяющий окно до 3.2-3.3 В, — а вот у голых модулей вроде ESP-01 делителя нет, и там вход держит свои честные 1023 ступени на один вольт. Шкала при этом десятибитная на обеих платах: analogRead вернёт 0-1023 и там и там, поменяется только цена деления. Любой перенос схемы с Uno начинается у меня с мультиметра: померить напряжение на точке, которая уйдёт в A0, до того, как провод воткнут.
Отсюда и порядок переезда аналогового датчика. Первый шаг — источник: датчики с аналоговым выходом на 5 В переделываются делителем или заменяются на вариант с питанием 3.3 В, которых на рынке большинство. Второй — проверка верхней точки мультиметром при живой схеме, но отключённом A0. Третий — калибровка по крайним значениям: запомните пары аналоговых чисел на ярком свету и в темноте, и только потом вписывайте пороги в код. Три шага занимают десять минут, а экономят неделю с сожжённым входом, как у меня было с первым фоторезистором.
// Порт с Uno на NodeMCU: мигалка и счётчик включений.// Сеть тут не нужна, поэтому WiFi-шапки нет; для сетевого// скетча первой строкой ставится #include <ESP8266WiFi.h>.#include <EEPROM.h> const int LED = 2; // метка D4 на шелкографии = GPIO2const int LED_ON = LOW; // бортовой светодиод зажигается при LOW void setup() { Serial.begin(115200); // на Uno я держал 9600 pinMode(LED, OUTPUT); digitalWrite(LED, HIGH); // гасим сразу: после старта горит EEPROM.begin(512); // на Uno не нужно; тут задаём размер int boots = EEPROM.read(0) + 1; EEPROM.write(0, boots); EEPROM.commit(); // без этой строки счётчик не переживёт рестарт Serial.print("boot n="); Serial.println(boots);} void loop() { digitalWrite(LED, LED_ON); delay(500); digitalWrite(LED, !LED_ON); delay(500);}EEPROM.begin(512) и EEPROM.commit() — две строки, без которых счётчик жил ровно до первого рестарта. Ядро 8266 эмулирует EEPROM во флеш-чипе по секторам: begin резервирует буфер в оперативке — 512 байт по умолчанию, максимум 4096, — и все write между begin и commit крутятся в этом буфере; только commit вываливает его во флеш одним куском. Отсюда и чтение: EEPROM.read берёт значение из буфера, который begin наполнил при старте. Механику износа ячейки и счётчик на ней я разбирал в уроке про счётчик включений — там всё про Uno, для 8266 сверху добавляются только эти две строки-скобки.
Размер буфера подбирается под содержимое с запасом: конфиг на сотню байт спокойно живёт в begin(512), а вот структура на 600 байт потребует begin(1024) — число в begin должно покрывать весь ваш адресный диапазон, иначе запись за пределом тихо потеряется. И второе: commit не бесплатен — он пишет целый сектор флеша, поэтому писать его в цикле каждую секунду я бы не стал: износ ячейки и тормоза loop прилагаются. Раз в сутки, по событию, по кнопке — пожалуйста, тот же счётчик включений пишет именно так.
Скорость порта — 115200 без колебаний: 8266 печатает на порядок быстрее, и на 9600 большой лог тормозит loop заметнее, чем кажется. Строка мусора в начале монитора — не поломка: загрузчик кричит на своих 74880 бод, которые скетчевая скорость не разбирает; это две разные скорости на одном проводе. Привычка из урока про Serial-монитор: скорость в углу окна сверяется со скетчем до первого сообщения в никуда.
- Сетевой скетч на 8266 начинается со строки include: ESP8266WiFi.h вместо WiFi.h, остальное API — begin, status, localIP — то же самое
- Метки D на шелкографии — не номера пинов: D4 = GPIO2, D1 = GPIO5, D2 = GPIO4; GPIO6-11 держит флеш, туда не пишем
- Бортовой светодиод на GPIO2 горит при LOW — инверсия, как у LED на пине 13 Uno
- A0 один и только вход: чип ест до 1 В, плата с делителем до 3.2 В; 5 В с Uno-схемы выжигают вход
- EEPROM.begin(512) и EEPROM.commit() — без них write живёт в буфере и умирает вместе с питанием
- 1. Сетевой скетч с Uno не компилируется на ESP8266: файл WiFi.h не найден. Что делать?
- 2. Светодиод на NodeMCU висит на GPIO2 (метка D4). Какая строка его зажжёт?
- 3. Сколько аналоговых входов у голого чипа ESP8266 и какой диапазон?
- 4. Счётчик включений на EEPROM после рестарта всегда показывает 1. Чего не хватает на 8266?
- 5. Почему в мониторе при старте NodeMCU мелькает строка мусора?
Частые вопросы по теме урока
- Сетевой скетч с Uno не компилируется на ESP8266: файл WiFi.h не найден. Что делать?
- На 8266 сетевой заголовок называется ESP8266WiFi.h, а класс WiFi внутри — с теми же begin, status и localIP. Одной правки include хватает. заменить WiFi.h на ESP8266WiFi.h — остальное API то же
- Светодиод на NodeMCU висит на GPIO2 (метка D4). Какая строка его зажжёт?
- Бортовой светодиод зажигается низким уровнем: LOW — горит, HIGH — погас. Число 4 в коде — это GPIO4 (метка D2), совсем другой пин, а A0 цифровым выходом не бывает. analogWrite(A0, 255)
- Сколько аналоговых входов у голого чипа ESP8266 и какой диапазон?
- У чипа один канал A0 с диапазоном 1 В и шкалой 0-1023. До 3.2-3.3 В расширяет окно делитель на платах NodeMCU и D1 mini — у голых модулей его нет. один вход, до 1 В
- Счётчик включений на EEPROM после рестарта всегда показывает 1. Чего не хватает на 8266?
- Ядро держит EEPROM в буфере оперативки: begin резервирует буфер, write пишет в него, и только commit вываливает сектор во флеш. Без commit значение умирает вместе с питанием. вызова EEPROM.begin и EEPROM.commit
- Почему в мониторе при старте NodeMCU мелькает строка мусора?
- Загрузчик здоровается своей скоростью 74880 бод, скетчевая 115200 её не разбирает — отсюда мусор в первых строках. Дальше пойдут уже читаемые строки скетча. загрузчик кричит на 74880 бод, а скетч настроен на 115200