В этом уроке поговорим о микроконтроллере ESP8266 и платах на его основе. Как с ними работать и чем они отличаются от Arduino на базе МК AVR. ESP8266 – китайский микроконтроллер за 2 доллара с большим объемом памяти и WiFi связью на борту. Официальная документация:
Характеристики:
- Напряжение питания: 3.3V (2.5-3.6V)
- Ток потребления: 300 мА при запуске и передаче данных, 35 мА во время работы, 80 мА в режиме точки доступа
- Максимальный ток пина – 12 мА.
- Flash память (память программы): 1 МБ
- Flash память (файловое хранилище): 1-16 МБ в зависимости от модификации
- EEPROM память: до 4 кБ
- SRAM память: 82 кБ
- Частота ядра: 80/160 МГц
- GPIO: 11 пинов
- ШИМ: 10 пинов
- Прерывания: 10 пинов
- АЦП: 1 пин
- I2C: 1 штука (программный, пины можно назначить любые)
- I2S: 1 штука
- SPI: 1 штука
- UART: 1.5 штуки
- WiFi связь
Начало работы
Для работы с платами на основе esp8266 нужно установить ядро и драйвер.
- Идём в Файл/Настройки/Дополнительные ссылки для менеджера плат. Вставляем ссылку https://arduino.esp8266.com/stable/package_esp8266com_index.json.
- Инструменты/Плата/Менеджер плат…, ищем в поиске esp8266 и устанавливаем. В списке плат появится семейство плат на базе esp8266.
- На большинстве плат стоит USB конвертер CH340, как на всех китайских Ардуинах. Если вы ещё не устанавливали драйвер
Настройки платы
Для работы с любой платой (даже самодельной) можно выбрать пункт Generic esp8266, будет доступен полный набор настроек. Для работы с Wemos Mini выбираем LOLIN Wemos D1 R2 mini. Настроек станет меньше, а к пинам платы можно будет обращаться в программе по их подписям на плате (Dn). Основные настройки:
- 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: полностью очистить память.
- Порт: к какому порту подключена плата.
Нумерация пинов
У самого чипа esp8266 все выводы пронумерованы цифрами. На распиновке они подписаны как GPIOn, где n – номер. На плате (NodeMCU, Wemos Mini) пины подписаны как Dn и эти номера не совпадают с номерами GPIO! При работе например с Wemos можно использовать как нумерацию выводов GPIO (
digitalWrite(5, LOW)
), так и D-нумерацию пинов на плате (
digitalWrite(D1, LOW)
) – если выбрана плата Wemos. Новички очень часто в этом путаются, будьте внимательны. Также GPIO1 и GPIO3 подписаны на плате как TX и RX, по этим названиям к ним тоже можно обращаться (
digitalWrite(TX, LOW)
).
Особенности пинов
У esp8266 много системных пинов, с которыми нужно быть очень внимательным.
- К целому ряду пинов подключена внешняя Flash память, в общем случае их использовать нельзя (если очень нужно – ищите информацию). На плате NodeMCU визуально гораздо больше пинов, чем на Wemos Mini, но по факту “безопасных” для использования пинов там ровно столько же.
- С оставшимися пинами тоже не всё гладко: некоторые из них требуют наличия определенного логического уровня на момент включения микроконтроллера (подача питания, перезагрузка). Если к этим пинам подключить что-то, дающее противоположный сигнал – esp не запустится. Вот распиновка с нужным уровнем сигнала при запуске:
- На плате (NodeMCU, Wemos и других) эти пины уже подтянуты резисторами к нужному напряжению, поэтому нужно несколько раз подумать, что вы к ним подключаете и как оно повлияет на напряжение на пине. Например, можно подключить энкодер, он прижмёт системный пин к GND и esp не запустится.
- На GPIO16/D0 нельзя подключать прерывания (
attachInterrupt()
) и включать ШИМ сигнал (
analogWrite()
).
- Максимальный ток с GPIO – 12 мА.
- Светодиод
LED_BUILTIN
находится на пине GPIO2 и его поведение инвертировано: при подаче
LOW
он включается и наоборот.
- При старте контроллера почти все пины делают скачок до высокого уровня, подробнее – в этой статье. Единственными “спокойными” пинами являются D1 (GPIO5) и D2 (GPIO4). Если контроллер управляет напрямую какими-то железками (реле, транзистор, или является “кнопкой” для другого устройства), то лучше использовать именно эти пины!
- На этих же пинах сидит I2C, но шину можно переназначить на любые другие пины через
Wire.begin(sda, scl)
.
Особенности работы WiFi
WiFi реализован синхронно, его обработчик должен постоянно вызываться во время работы программы не реже, чем каждые 20 мс (если WiFi используется в программе). Обработка WiFi происходит в следующих местах:
- Автоматически в конце каждой итерации
loop()
- Внутри любого
delay()
- Внутри функции
yield()
Если у вас есть участки программы, которые долго выполняются, то нужно разместить вызовы
yield()
до и после тяжёлых блоков кода. Также в чужих скетчах можно встретить
delay(0)
, по сути это и есть
yield()
.
По тем же причинам не рекомендуется использовать задержку
delayMicroseconds()
более чем на 20’000 мкс.
Отличия от AVR Arduino
Деление на 0
В отличие от AVR, деление на 0 приводит к критической ошибке и перезагрузке микроконтроллера. Стараемся этого избегать.
min() и max()
В ядре esp8266 функции
min()
и
max()
реализованы как функции, а не как макросы, поэтому должны использоваться с данными одного типа. Использование переменных разного типа приведёт к ошибке компиляции.
map()
В функции
map(val, min, max, to min, to max)
нет защиты от деления на 0, поэтому если min равен max – микроконтроллер зависнет и перезагрузится. Если min и max задаются какими-то внешними условиями – проверяйте их равенство вручную и исключайте вызов
map()
с такими аргументами.
Типы данных
- Тип
int
является синонимом
long
(
int32_t
) и занимает 4 байта. В AVR
int
это
int16_t
, то есть 2 байта.
- Тип
char
является синонимом
byte
– принимает значения 0.. 255 в отличие от -128.. 127 в AVR.
- Тип
double
имеет полную двойную точность – 8 байт. В AVR это 4 байта.
- Указатель занимает 4 байта, так как область памяти тут 32-битная. В AVR – 2 байта.
Функция 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.
- Разрядность ШИМ по умолчанию 8 бит (0.. 255) на версиях ядра 3.x. На ранних версиях – 10 бит (0.. 1023). Скажем спасибо индусам за совместимость.
- Частота ШИМ по умолчанию 1 кГц.
- ШИМ реализован программно, поэтому на повышенной частоте и разрядности будет тормозить выполнение программы!