ESP8266 - китайский микроконтроллер с большим объемом памяти и WiFi связью на борту (SoM на картинке справа). Популярные платы на его основе: Wemos D1 mini (слева), NodeMCU (по центру).
Wemos mini #
Плата Wemos D1 mini является лучшим вариантом для знакомства с МК ESP8266 - недорогая, компактная и удобная в работе на макетке. Существует несколько вариантов исполнения и их версий, в принципе они все хорошие и рекомендуются к покупке:
Информация #
Документация:
- Arduino core (github)
- Arduino core (readthedocs)
Купить Wemos mini:
Wemos mini идёт в нашем наборе GyverKIT в версиях GyverKIT PRO и GyverKIT IOT
Характеристики #
Характеристика | Значение |
---|---|
Микроконтроллер | Espressif ESP8266 |
Логический уровень | 3.3V |
Напряжение питания | 2.2.. 3.6V |
Через стабилизатор (Wemos) | 4.5.. 5.5V |
Через стабилизатор (NodeMCU) | 5.. 15V |
Макс. ток с пина | 12 mA |
Ток потребления | 300 mA при запуске и передаче данных, 35 mA во время работы, 80 mA в режиме точки доступа |
Режимы энергосбережения | Modem sleep (15 mA), Light sleep (0.4 mA), Deep sleep (15 uA) |
Частота тактирования | 80/160 MHz |
Flash | 1.. 16 MB внешняя |
RAM | 82 kB (доступно около 52 kB) |
EEPROM | Эмуляция из Flash |
GPIO | 14 (доступно 11) |
ADC | 10 bit 1 канал |
ШИМ пины | 10 |
Аппаратные интерфейсы | 1x SPI, 1x I2S, 1.5x UART, WiFi |
Аппаратного I2C нет, есть встроенный программный
Распиновка #
Особенности пинов #
У esp8266 много системных пинов, с которыми нужно быть очень внимательным:
- К нескольким пинам подключена внешняя Flash память, в общем случае их использовать нельзя (если очень нужно - ищите информацию). На плате NodeMCU визуально гораздо больше пинов, чем на Wemos Mini, но по факту "безопасных" для использования пинов там ровно столько же. У Wemos эти пины не выведены на плату
- Светодиод
LED_BUILTIN
находится на пинеGPIO2
и его поведение инвертировано: при подачеLOW
он включается и наоборот - На
GPIO16
нельзя подключать прерыванияattachInterrupt()
и включать ШИМ сигналanalogWrite()
GPIO0
управляет режимом запуска МК (старт или режим прошивки)- При старте контроллера почти все пины делают скачок до высокого уровня, подробнее - в этой статье. Единственными "спокойными" пинами являются
D1
(GPIO5) иD2
(GPIO4). Если контроллер управляет напрямую какими-то железками (реле, транзистор, или является "кнопкой" для другого устройства), то лучше использовать именно эти пины! На этих же пинах сидит I2C, но шину можно переназначить на любые другие пины - С оставшимися пинами тоже не всё гладко: некоторые из них требуют наличия определенного логического уровня на момент включения МК (подача питания, перезагрузка). Если к этим пинам подключить что-то, дающее противоположный сигнал - esp не запустится. На распиновке у таких пинов указан и зачёркнут сигнал, который нельзя подавать при запуске
Пин | Нельзя |
---|---|
D8 (GPIO15) | HIGH |
D4 (GPIO2) | LOW |
TX (GPIO1) | LOW |
К этим пинам можно подключать внешние железки, но с пониманием того, какой сигнал они дадут на пин. Например, можно подключить энкодер, он прижмёт системный пин к GND и esp не запустится
Нумерация пинов #
У самого чипа esp8266 все выводы пронумерованы цифрами. На распиновке они подписаны как GPIOn, где n - номер GPIO. На плате (NodeMCU, Wemos Mini) пины подписаны как Dn и эти номера не совпадают с номерами GPIO! При работе например с Wemos можно использовать как нумерацию выводов GPIO - digitalWrite(5, LOW)
, так и D-нумерацию пинов на плате - digitalWrite(D1, LOW)
, если выбрана плата Wemos. Новички очень часто в этом путаются, будьте внимательны. Также GPIO1
и GPIO3
подписаны на плате как TX
и RX
, по этим названиям к ним тоже можно обращаться - digitalWrite(TX, LOW)
.
Аналоговый пин один, к нему можно обращаться как analogRead(0)
.
Особенности #
WiFi #
WiFi реализован синхронно, его обработчик должен постоянно вызываться во время работы программы не реже, чем каждые 20 мс (если WiFi используется в программе). Обработка WiFi происходит в следующих местах:
- После выхода из
loop()
- Внутри
delay()
- Внутри
yield()
Поэтому:
- Нужно вызывать
delay(0)
/yield()
до и после тяжёлых блоков кода и/или внутри них - Нужно обязательно вызывать
delay(0)
/yield()
в глухих циклах ожидания - Не рекомендуется использовать задержку
delayMicroseconds()
более чем на20 000
мкс
while (some_condition) {
// ...
delay(0);
}
yield();
тяжёлая_функция();
yield();
Если этого не делать - МК перезагрузится с ошибкой WDT reset
Деление на 0 #
В отличие от AVR, деление на 0
приводит к критической ошибке и перезагрузке микроконтроллера. Стараемся этого избегать.
min() и max() #
В ядре esp8266 функции min()
и max()
реализованы как функции, а не как макросы, поэтому должны использоваться с данными одного типа. Использование переменных разного типа приведёт к ошибке компиляции:
unsigned long v;
v = max(v, 123); // ошибка
v = max(v, 123ul); // ОК
map() #
В функции map(val, min, max, to_min, to_max)
нет защиты от деления на 0
, поэтому если min равен max - микроконтроллер зависнет и перезагрузится. Если min
и max
задаются какими-то внешними условиями - проверяйте их равенство вручную и исключайте вызов map()
с такими аргументами.
Типы данных #
int
- 32 битныйdouble
- 64 битный- Указатель - 32 битный
analogRead() #
ESP8266 имеет крайне убогий одноканальный АЦП:
- Сам АЦП в esp8266 может измерять напряжение в диапазоне 0.. 1.0V. На платах (NodeMCU, Wemos Mini) стоит делитель напряжения, который расширяет диапазон до более удобных 3.3V
- Разрешение - 10 бит, т. е. значения
0.. 1023
как на Arduino - Частый вызов
analogRead()
замедляет работу WiFi. При вызовах чаще нескольких миллисекунд WiFi полностью перестаёт работать - Результат
analogRead()
имеет кеширование до 5 мс, то есть полученные данные могут запаздывать на это время - АЦП может использоваться для измерения напряжения питания МК: для этого нужно вызвать
ADC_MODE(ADC_VCC);
доvoid setup()
(просто в коде программы, вне функций), а само напряжение питания можно получить изESP.getVcc()
analogWrite() #
- Работает на всех пинах, кроме
GPIO16
- ШИМ реализован программно, поэтому на повышенной частоте и разрядности будет тормозить выполнение программы
- Частота по умолчанию 1 кГц
- Частоту можно настроить в
analogWriteFreq(100.. 40000 Гц)
- Частоту можно настроить в
- Разрядность по умолчанию 8 бит (0.. 255) на версиях ядра 3.x. На ранних версиях - 10 бит (0.. 1023)
- Разрядность можно настроить в
analogWriteResolution(4...16 бит)
- Разрядность можно настроить в
Аппаратные прерывания #
- Работают на всех пинах, кроме
GPIO16
- В обработчике нельзя использовать динамическое выделение и перераспределение памяти (
new
,malloc
,realloc
), соответственно менятьString
-строки тоже нельзя - В прерывании нельзя использовать задержки
- Функция-обработчик должна быть объявлена с атрибутом
IRAM_ATTR
:
IRAM_ATTR void myIsr() {}
void setup() {
attachInterrupt(1, myIsr, RISING);
}
Либо с ICACHE_RAM_ATTR
(на старых версиях ядра):
void ICACHE_RAM_ATTR myIsr() {}
void setup() {
attachInterrupt(1, myIsr, RISING);
}
EEPROM #
EEPROM в esp8266 является эмуляцией из Flash памяти, поэтому мы можем выбрать нужный размер:
- Перед началом работы нужно вызвать
EEPROM.begin(4.. 4096)
с указанием размера области памяти в байтах - Для применения изменений в памяти нужно вызвать
EEPROM.commit()
- В некоторых версиях SDK отсутствует
EEPROM.update()
иEEPROM.length()
- У Flash памяти небольшой ресурс - всего около 10'000 перезаписей. У фирменной памяти Winbond (можно найти на некоторых моделях ESP-12 и прочих) - около 50'000 перезаписей
Важно: EEPROM реализован следующим образом: после запуска EEPROM.begin(4.. 4096)
содержимое EEPROM указанного размера дублируется в оперативной памяти. После любого изменения и вызова EEPROM.commit()
стирается весь блок Flash памяти (4 кБ) и записывается заново. Таким образом ресурс "EEPROM" памяти у ESP вырабатывается довольно быстро и весь сразу, а не по ячейкам.
Вместо EEPROM используйте библиотеку FileData для удобного хранения любых данных в файловой системе
Serial (UART) #
- В отличие от реализации для AVR, можно изменить размер буфера на приём:
Serial.setRxBufferSize(размер)
в байтах. Вызывать передSerial.begin()
, по умолчанию 256 байт - Можно настроить работу только на приём или только на отправку для освобождения пина:
Serial.begin(скорость, SERIAL_8N1, mode)
, гдеmode
:SERIAL_TX_ONLY
- только отправкаSERIAL_RX_ONLY
- только приёмSERIAL_FULL
- приём и отправка (по умолчанию)
- Можно перенести
Serial
на другие пины при помощиSerial.swap()
, вызывать послеSerial.begin()
. Пины переместятся на GPIO15/D8 (TX) и GPIO13/D7 (RX). Если вызвать ещё раз - переместятся обратно на GPIO1 (TX) и GPIO3 (RX) и так по кругу - У esp8266 есть второй аппаратный UART, но его приёмная нога (RX) занята одним из пинов для работы с памятью и не выведена на плате Wemos Mini. Нога TX находится на GPIO2/D4, то есть можно работать только на отправку, но на практике и это может пригодиться. В программе просто работаем с объектом
Serial1
, настроив его только на отправку
При перезагрузке ESP8266 отправляет в UART информацию о перезапуске на скорости 74880, что при другой скорости монитора выглядит как набор битых символов
Начало работы #
- Ссылка для менеджера плат:
https://arduino.esp8266.com/stable/package_esp8266com_index.json
- Для платы Wemos mini выбираем
LOLIN(WEMOS) D1 R2 & mini
- Для работы с любой платой (даже самодельной) можно выбрать
Generic esp8266
, будет доступен полный набор настроек
Параметры #
- Upload speed: скорость загрузки прошивки. Можно смело поднимать до 921600
- CPU Frequency: частота тактирования процессора. Для большинства задач хватит стандартных 80 МГц. На 160 МГц будет работать шустрее, но могут быть сбои
- Flash Size: распределение памяти, настройка имеет вид xMB (FS:xMB OTA:~xKB). Размер памяти под программу не меняется - это всегда 1 МБ
- Первое число: полный объём микросхемы памяти (в основном 4MB, на Wemos и NodeMCU стоят такие)
- Второе число: объём под файловое хранилище
- Третье число: объём под OTA (обновление по воздуху) - всегда меньше 1 МБ
- Что выбрать? У Wemos самый ходовой - первый вариант: 4MB (FS:2MB OTA:~1019KB)
- Flash mode: режим загрузки во Flash память
- DOUT: медленный, но совместим со всеми модификациями esp8266
- QIO: более быстрый, но будет работать не на всех чипах
- Erase Flash: режим очистки памяти
- Only Sketch: стереть только программу
- Sketch + WiFi Settings: стереть программу и настройки WiFi (логин-пароль последнего подключения и т.д.)
- All Flash Contents: полностью очистить память
platformio.ini #
[env:d1_mini]
platform = espressif8266
board = d1_mini
framework = arduino
monitor_speed = 115200
upload_speed = 921600
monitor_filters = esp8266_exception_decoder, default
build_type = debug
board_build.filesystem = littlefs
lib_deps =