ESP32 для новичков: от логических микросхем до умных устройств

Прокомментировать Просмотры: 0

В предыдущей статье «Первый шаг к микроконтроллерам: введение в цифровые схемы» вы познакомились с логическими микросхемами серии 155 и простыми устройствами на их основе. Однако для реализации более сложной схемы таких микросхем понадобится немало. А чтобы изменить логику её работы, потребуется переработать и перепаять соединения или даже собрать устройство заново.

Сегодня цифровые устройства часто создают на базе микроконтроллеров и микрокомпьютеров. Их поведение определяется программой, которую при необходимости можно быстро изменить.

Множество окружающих нас «умных» устройств содержат микроконтроллеры: электрочайники, стиральные машины, кондиционеры, игрушки и компоненты умного дома.

Для взаимодействия с внешними устройствами микроконтроллеры оснащают линиями ввода-вывода общего назначения — General-Purpose Input/Output (GPIO). Обычно они используются для цифровых сигналов. Некоторые микроконтроллеры также содержат АЦП и ЦАП для работы с аналоговыми сигналами. Если их точности недостаточно, применяют внешние модули.

К GPIO можно подключить как простые компоненты, например кнопки и светодиоды, так и более сложные устройства — дисплеи или радиомодули. Одни соединяются с выводами напрямую, для других необходимы дополнительные модули. Так, реле позволяет управлять мощной нагрузкой, а специальные интерфейсные модули — электродвигателями.

Возможности современных микроконтроллеров выходят за рамки обработки сигналов. Они обмениваются данными по Wi-Fi и Bluetooth, работают как веб-серверы и создают точки доступа, к которым можно подключить телефон. Такая точка доступа позволяет управлять устройством даже без подключения к интернету.

В этой статье я покажу, как подключать кнопки и светодиоды к отладочной плате ESP32-S3-DevKitC-1-N16R8. Вы научитесь создавать программы в Arduino IDE, загружать их в микроконтроллер и проверять работу на макетной плате. Мы также рассмотрим прерывания, ШИМ и распиновку ESP32-S3-DevKitC-1-N16R8.

Каждый пример основан на несложной схеме, которую можно собрать самостоятельно. Повторяя их, вы получите практический опыт работы с ESP32: от включения светодиода до управления им с помощью кнопок.

Какой микроконтроллер выбрать для первых опытов

Среди популярных платформ сегодня можно выделить Arduino, ESP32, nRF52840, Raspberry Pi Pico и STM32. Они различаются числом ядер и частотой процессора, объёмом оперативной памяти, наличием беспроводной связи, количеством GPIO и другими характеристиками.

Начнём со знакомой многим экосистемы Arduino (рис. 1).

Рис. 1. Плата Arduino UNO
Рис. 1. Плата Arduino UNO

Классическая плата UNO R3 построена на 8-битном микроконтроллере ATmega328P с частотой 16 МГц и имеет 2 КБ оперативной памяти.

UNO R4 Minima и компактная Nano R4 используют 32-битный микропроцессор Renesas RA4M1 с частотой 48 МГц и 32 КБ ОЗУ, но встроенной беспроводной связи у них тоже нет. Исключение составляет UNO R4 WiFi: поддержку Wi-Fi и BLE в ней обеспечивает отдельный микроконтроллер ESP32-S3. В целом Arduino хорошо подходит для обучения и несложных задач автоматизации.

Для Arduino выпущено множество плат расширения — шилдов (Shields), которые можно устанавливать друг на друга. На рис. 2 слева показана Arduino с платой для подключения Ethernet и карты памяти SD, справа — модуль Wi-Fi.

Рис. 2. Платы расширения для подключения сети и SD-карты памяти
Рис. 2. Платы расширения для подключения сети и SD-карты памяти

Платформа STM32 широко распространена в профессиональной электронике и включает множество моделей. Для новичка это разнообразие может стать препятствием: экосистема инструментов достаточно сложна, а настройка периферии требует опыта. Кроме того, большинство моделей не имеют встроенной беспроводной связи.

На рис. 3 представлена отладочная плата NUCLEO-F401RE, которую удобно применять для прототипирования.

Рис. 3. Плата NUCLEO-F401RE
Рис. 3. Плата NUCLEO-F401RE

Сильная сторона nRF52840 — низкое энергопотребление. Wi-Fi платформа не поддерживает, зато предлагает более экономичные BLE, Thread и Zigbee. При этом её производительность сравнительно невысока, а освоение может оказаться непростым для начинающих.

Raspberry Pi Pico — недорогая плата от Raspberry Pi на микроконтроллере RP2040: два ядра ARM Cortex-M0+ с частотой до 133 МГц и 264 КБ ОЗУ. Для программирования можно использовать MicroPython, C/C++ или Arduino IDE. В версии Pico W дополнительно доступны Wi-Fi и Bluetooth.

Для примеров в этой статье я выбрал ESP32 китайской компании Espressif Systems. Платформа сочетает встроенные Wi-Fi и Bluetooth LE, достаточную вычислительную мощность и богатый набор периферии. Программы для неё можно писать как в простой Arduino IDE, так и с помощью профессиональных инструментов.

На базе ESP32 выпускают недорогие компактные модули, а также более оснащённые платы с экранами и средствами дальней радиосвязи LoRa. При этом их стоимость остаётся относительно невысокой.

На рис. 4 слева изображена отладочная плата ESP32-S3-DevKitC-1-N16R8, справа — компактная ESP32-S3 Super Mini.

Рис. 4. Две платы микроконтроллеров на базе ESP32
Рис. 4. Две платы микроконтроллеров на базе ESP32

ESP32-S3-DevKitC-1-N16R8 оснащена 512 КБ встроенной SRAM, 16 МБ флеш-памяти и 8 МБ PSRAM.

Флеш-память сохраняет данные после отключения питания; в неё записывается прошивка устройства. Содержимое псевдостатической памяти Pseudo-Static RAM (PSRAM), напротив, при выключении питания теряется. Она также работает медленнее встроенной SRAM. Кроме того, предусмотрена небольшая RTC-память, сохраняющая данные в режиме глубокого сна, когда энергопотребление платы значительно снижается. Подробнее типы памяти описаны в разделе «Memory Types» документации.

Микроконтроллер имеет два процессорных ядра с частотой до 240 МГц, поддерживает Wi-Fi 4 и Bluetooth 5 LE. На плате также размещена антенна Wi-Fi.

Для первых опытов пригодятся встроенный RGB-светодиод, два разъёма USB и кнопки сброса RST и загрузки BOOT.

Производительности этого микроконтроллера достаточно для множества задач: обработки видео с камеры и звука, вывода изображений на дисплей и запуска специально подготовленных нейросетевых моделей.

ESP32-S3 Super Mini, несмотря на небольшие размеры, тоже обладает широкими возможностями. Она оснащена двумя ядрами Xtensa LX7 с частотой до 240 МГц, модулями Wi-Fi 4 и Bluetooth 5 LE, 512 КБ SRAM, разъёмом USB и выводами GPIO. Такую плату можно использовать в системах умного дома, устройствах с дисплеем и проектах по обработке звука и изображений.

На рис. 5 представлены платы Waveshare ESP32-S3-LCD-1.47 и Heltec HTIT-WB32LAF.

Рис. 5. Платформы ESP32 с экраном и модулем LoRa
Рис. 5. Платформы ESP32 с экраном и модулем LoRa

Компактная ESP32-S3-LCD-1.47 оснащена цветным экраном и двухъядерным процессором Xtensa LX7 с частотой до 240 МГц. Она поддерживает Wi-Fi 4 и Bluetooth 5 LE, имеет встроенную антенну, 16 МБ флеш-памяти и 8 МБ PSRAM.

Дисплей диагональю 1,47 дюйма с разрешением 172×320 и поддержкой 262 тыс. цветов годится как для экспериментов, так и для разработки графических интерфейсов.

На плате предусмотрены слот для карт TF (Micro-SD), разъём USB и кнопки RST и BOOT.

Справа на рис. 5 находится Heltec HTIT-WB32LAF. Её особенность — LoRa-трансивер SX1262, который позволяет передавать данные на расстояние в несколько километров, пусть и с небольшой скоростью. Также плата оснащена OLED-дисплеем диагональю 0,96 дюйма и разрешением 128×64, разъёмами для солнечной панели и Li-Po-аккумулятора и схемой зарядки.

Сравнение характеристик популярных современных микроконтроллеров можно найти в статье «Top 10 Microcontrollers in 2026: A Comprehensive Comparison Guide».

Чем микроконтроллер отличается от микрокомпьютера

Для взаимодействия с оборудованием применяют не только микроконтроллеры, но и микрокомпьютеры. На рис. 6 в качестве примера показаны Raspberry Pi 3 Model B+ и Orange Pi 3B.

Рис. 6. Микрокомпьютеры Raspberry Pi 3 Model B+ и Orange Pi 3B
Рис. 6. Микрокомпьютеры Raspberry Pi 3 Model B+ и Orange Pi 3B

Микрокомпьютеры тоже имеют GPIO для подключения внешних устройств, но отличаются от микроконтроллеров назначением, стоимостью и энергопотреблением.

Микроконтроллеры

Микроконтроллер объединяет в одной микросхеме процессор, память и периферию — фактически целую вычислительную систему. Он выполняет прошивку без операционной системы или под управлением операционной системы реального времени RTOS. ESP32 потребляет относительно небольшой ток — около 100–300 мА, а в режиме сна расходует значительно меньше энергии. Программа на микроконтроллере запускается за доли секунды.

Микроконтроллеры используют в датчиках и IoT-устройствах, для управления двигателями, реле и бытовой техникой. Они востребованы в автомобильной и промышленной электронике — везде, где важны точное соблюдение временных интервалов, экономичность и надёжность.

Микрокомпьютеры

Микрокомпьютеры, например Raspberry Pi и Orange Pi, представляют собой полноценные компьютеры на одной плате. Их также называют одноплатными компьютерами — Single-Board Computer (SBC).

Обычно такие устройства оснащают многоядерными ARM-процессорами с частотой порядка 1–2,5 ГГц и оперативной памятью объёмом от 512 МБ до 16 ГБ. Они работают под управлением операционной системы, например Linux или Android. На плате могут быть разъёмы USB, Ethernet и HDMI, а также интерфейсы для камер.

Микрокомпьютеры применяют в качестве домашних серверов и шлюзов, медиацентров и информационных киосков, в системах компьютерного зрения и искусственного интеллекта. Они подходят для прототипирования сложных проектов и координации нескольких микроконтроллеров.

На микрокомпьютере можно запускать самые разные программы: веб-серверы, базы данных, Docker и другие приложения. Однако гарантировать время реакции такой системы нельзя. Её энергопотребление составляет примерно 2–15 Вт. Перед отключением питания операционную систему нужно корректно завершить, иначе файловая система на SD-карте может быть повреждена.

Микроконтроллер обычно значительно дешевле микрокомпьютера: первый можно купить за несколько сотен рублей, второй — за несколько тысяч или даже десятков тысяч. На цену микрокомпьютера заметно влияет объём оперативной памяти. Кроме того, для него могут понадобиться корпус, SD-карта, блок питания и вентилятор.

В сложных проектах оба типа устройств нередко работают вместе: микроконтроллер взаимодействует с оборудованием в реальном времени, а микрокомпьютер отвечает за сложную логику, сеть и нейросети.

Плата ESP32-S3-N16R8

Для примеров в этой статье используется ESP32-S3-DevKitC-1-N16R8 (рис. 7).

Рис. 7. Платформа ESP32-S3-DevKitC-1-N16R8
Рис. 7. Платформа ESP32-S3-DevKitC-1-N16R8

На плате расположены два USB-разъёма. С нижней стороны один обозначен как COM, другой — как USB. Первый подключён через мост USB-UART CH343P и используется для загрузки прошивки и отладки кода. В зависимости от производителя платы вместо него может применяться CP2102N.

Разъём USB напрямую соединён с выводами GPIO19 и GPIO20. Его можно использовать как виртуальный COM-порт, интерфейс отладки USB-JTAG или для эмуляции USB-устройств — клавиатуры, мыши и геймпада.

Подключите плату к USB-порту компьютера через разъём COM. Запустится установленная на ней прошивка, которая периодически меняет цвет RGB-светодиода (рис. 8).

Рис. 8. Первое включение ESP32-S3-DevKitC-1-N16R8
Рис. 8. Первое включение ESP32-S3-DevKitC-1-N16R8

На рис. 8 видны ещё три светодиода. Нижний красный индикатор показывает наличие питания. Один из двух остальных мигает при передаче данных с компьютера на ESP32 через COM, например во время загрузки прошивки, а второй — при отправке данных с ESP32 на компьютер, в том числе отладочных сообщений.

Кнопка RST перезапускает микроконтроллер и программу. Кнопка BOOT соединена с выводом GPIO0. Если удерживать её при сбросе или включении питания, ESP32-S3 перейдёт в режим загрузчика для прошивки. Во время обычной работы её можно использовать как пользовательскую кнопку.

Обозначение «N16R8» указывает на объём памяти: 16 МБ флеш-памяти (N16) и 8 МБ PSRAM (R8).

Пока подключать дополнительные компоненты не будем. Сначала установим Arduino IDE, а к работе с оборудованием вернёмся позже.

Установка Arduino IDE в Windows 11

Перейдите на сайт arduino.cc, нажмите Download и скачайте установщик Arduino IDE для Windows. Для версии 2.3.10 файл называется arduino-ide_2.3.10_Windows_64bit.exe. Его также можно найти на сайте одного из магазинов микроконтроллеров.

Запустите скачанный файл и пройдите этапы установки. При появлении запросов разрешите установку драйверов. Подробное описание процедуры приведено в статье «Как установить arduino ide на windows».

Программы для Arduino IDE пишут на C++, поэтому знание языка будет полезным. Начать можно с основ и готовых примеров, изучая остальное по мере работы. Для обучения подойдут англоязычный сайт LearnCpp.com и русскоязычный учебник «Уроки С++».

О C++ написано немало книг, в том числе «Язык программирования C++. Лекции и упражнения» Стивена Прата. Также рекомендую англоязычную документацию «Welcome to ESP32 Arduino Core’s documentation».

Запускаем первую программу

Подключив плату к компьютеру с Microsoft Windows 11, выясните, какой COM-порт ей назначен. Для этого откройте Диспетчер устройств (рис. 9) и разверните раздел Порты (COM и LPT).

Рис. 9. Диспетчер устройств
Рис. 9. Диспетчер устройств

В названии устройства должен упоминаться мост USB-UART, например CH343 или CP2102. В моём случае контроллеру назначен COM4. Это название понадобится при работе с ESP32 в Arduino IDE.

Если порт определился, откройте Arduino IDE. В меню Tools выберите Port, а затем в разделе Serial Port укажите порт, к которому подключена плата (рис. 10).

Рис. 10. Выбор порта, к которому подключена плата микроконтроллера
Рис. 10. Выбор порта, к которому подключена плата микроконтроллера

У меня выбран COM4, но на вашем компьютере номер может отличаться.

Затем откройте File → Preferences и введите в поле Additional boards manager URLs следующий адрес:

https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json

Нажмите OK, чтобы сохранить настройки.

Теперь установим поддержку нужной платформы. В меню Tools выберите Board, затем Boards manager. Введите в поиске «esp Espressif» и найдите пакет esp32 от Espressif Systems (рис. 11).

Рис. 11. Найден пакет esp32 by Espressif Systems
Рис. 11. Найден пакет esp32 by Espressif Systems

Нажмите INSTALL и дождитесь окончания установки.

После этого откройте Tools → Board и в разделе esp32 выберите ESP32S3 Dev Module (рис. 12).

Рис. 12. Выбор платы
Рис. 12. Выбор платы

Если настройки выполнены верно, название платы появится на панели инструментов, а выбранный COM-порт — в строке состояния (рис. 13).

Рис. 13. Выбрана плата ESP32S3 Dev Module и порт COM4
Рис. 13. Выбрана плата ESP32S3 Dev Module и порт COM4

Для N16R8 в меню Tools установите Flash Size: 16MB и PSRAM: OPI PSRAM. Иначе PSRAM не будет работать. Для примера с мигающим светодиодом это, впрочем, не критично.

Если плата подключена к компьютеру через разъём с обозначением USB, для отладки через Serial установите USB CDC On Boot: Enabled. При подключении через COM эту опцию следует оставить выключенной.

Об отладке я расскажу в одной из следующих статей цикла.

Создание скетча

Создайте на компьютере папку RGB-Blink и сохраните в ней файл RGB-Blink.ino со следующим содержимым:

#define RGB_PIN 48

void setup() {
  randomSeed(esp_random()); // аппаратный генератор случайных чисел
}

void loop() {
  uint8_t r, g, b;
  do {
    r = random(0, 256);
    g = random(0, 256);
    b = random(0, 256);
  } while (r + g + b < 100); // отсекаем слишком тёмные цвета

  // Яркость уменьшена в 4 раза, светодиод очень яркий
  neopixelWrite(RGB_PIN, r / 4, g / 4, b / 4);

  delay(1000);
}

Готовый файл также доступен в моём репозитории на GitHub.

Откройте его в Arduino IDE (рис. 14).

Рис. 14. Запуск программы RGB-Blink.ino
Рис. 14. Запуск программы RGB-Blink.ino

Чтобы скомпилировать программу, загрузить её на плату и запустить, нажмите кнопку Upload со стрелкой, выделенную на рис. 14.

В нижней части окна, на панели Output, появятся сообщения о компиляции и загрузке (рис. 15).

Рис. 15. Сообщения в процессе компиляции и загрузки
Рис. 15. Сообщения в процессе компиляции и загрузки

Если на одном из этих этапов возникнут ошибки, сведения о них появятся здесь же.

По окончании загрузки вы увидите сообщение о сбросе микроконтроллера (рис. 16).

Рис. 16. Выполнен сброс микроконтроллера и запуск программы
Рис. 16. Выполнен сброс микроконтроллера и запуск программы

Плата перезапустится, как после нажатия RST, и начнёт выполнять загруженную программу.

Принцип работы RGB-Blink.ino

Скетч RGB-Blink.ino каждую секунду меняет цвет встроенного RGB-светодиода, выбирая новый случайным образом.

В начале кода указан номер вывода, к которому подключён светодиод:

#define RGB_PIN 48

На официальной ESP32-S3-DevKitC-1 светодиод соединён с GPIO48 в ревизии 1.0 или с GPIO38 в ревизии 1.1. У клонов и других плат на ESP32-S3 подключение может быть иным, поэтому проверьте документацию производителя.

Макрос RGB_BUILTIN позволяет не привязывать программу к конкретному номеру вывода.

На плате установлен не обычный трёхцветный светодиод, а адресуемый светодиод со встроенным контроллером — WS2812 или совместимый с ним, также известный как NeoPixel. Для управления им достаточно одной линии GPIO.

Программы для ESP32 обычно содержат две функции — setup и loop. Первая выполняется при запуске и проводит необходимую инициализацию. Затем многократно вызывается loop, которая служит основным циклом программы.

При запуске функция randomSeed инициализирует генератор случайных чисел:

void setup() {
  randomSeed(esp_random());
}

Затем loop вызывает random, чтобы получить значения компонентов цвета от 0 до 255:

uint8_t r, g, b;
do {
  r = random(0, 256);
  g = random(0, 256);
  b = random(0, 256);
} while (r + g + b < 100);

Верхняя граница, переданная вторым аргументом random, не включается в диапазон. Поэтому указано 256, а не 255.

Условие while отбрасывает слишком тёмные цвета.

Цвет светодиоду задаёт функция neopixelWrite:

neopixelWrite(RGB_PIN, r / 4, g / 4, b / 4);

Она передаёт значения яркости красного, зелёного и синего компонентов. Поскольку встроенный светодиод светит очень ярко, каждое значение делится на четыре: остаётся примерно 25% максимальной яркости.

Перед следующим проходом loop делает паузу на одну секунду:

delay(1000);

Функция esp_random возвращает 32-битное значение аппаратного генератора ESP32. В этом скетче randomSeed использует его для инициализации генератора псевдослучайных чисел Arduino, а random затем формирует последовательность для выбора цветов.

Поэтому после перезапуска порядок цветов меняется. Аппаратный генератор выдаёт полноценно случайные числа только при работающем радиоблоке, но для выбора цвета светодиода в этом примере ограничение несущественно.

Подключение кнопок

В статье «Первый шаг к микроконтроллерам: введение в цифровые схемы» я показывал схемы на цифровых логических микросхемах с двумя кнопками, реализующие операции 2И-НЕ, 2И и исключающее ИЛИ. Их входы подтягивались к питанию резисторами. В схемах со счётчиками и сдвиговым регистром для подавления дребезга контактов применялся конденсатор.

С помощью микроконтроллера эти схемы можно упростить. ESP32-S3-DevKitC-1-N16R8 позволяет подтягивать большинство входов GPIO к питанию без внешних резисторов, а дребезг кнопок устранять программно.

Соберите на макетной плате схему с микроконтроллером и двумя кнопками, как показано на рис. 17.

Рис. 17. Управление RGB-светодиодом с помощью кнопок
Рис. 17. Управление RGB-светодиодом с помощью кнопок

ESP32-S3-DevKitC-1-N16R8 довольно широкая, поэтому для доступа ко всем выводам я соединил две макетные платы. Если соединить их не получается, проверьте, что платы одного типа и из одной поставки.

Кнопки подключены к GPIO4 и GPIO5, а также к земле — контакту GND платы. Внешние подтягивающие резисторы не нужны.

Программа esp32s3_onboard_rgb_polling

Скетч esp32s3_onboard_rgb_polling.ino управляет цветом встроенного RGB-светодиода ESP32-S3-DevKitC-1-N16R8.

К GPIO4 и GPIO5 подключены две кнопки. При нажатии первой GPIO4 соединяется с землёй и светодиод становится синим. Вторая кнопка, подключённая к GPIO5, включает зелёный цвет. Одновременное нажатие обеих кнопок даёт голубой цвет.

Номера выводов кнопок задаются так:

const int BTN_BLUE  = 4;
const int BTN_GREEN = 5;

При инициализации setup включает подтяжку GPIO4 и GPIO5 к питанию и с помощью setLed выключает RGB-светодиод:

void setup() {
  pinMode(BTN_BLUE,  INPUT_PULLUP);
  pinMode(BTN_GREEN, INPUT_PULLUP);
  setLed(false, false);
}

Функция setLed устанавливает яркость отдельных цветовых компонентов:

void setLed(bool green, bool blue) {
  neopixelWrite(LED_PIN, 0, green ? BRIGHT : 0, blue ? BRIGHT : 0);
}

Управление цветом происходит в цикле loop:

void loop() {
  uint8_t raw = 0;
  if (digitalRead(BTN_BLUE)  == LOW) raw |= 0b01;
  if (digitalRead(BTN_GREEN) == LOW) raw |= 0b10;

  if (raw != lastRaw) {
    lastRaw = raw;
    lastChange = millis();
  }

  if (raw != stable && (millis() - lastChange) > DEBOUNCE_MS) {
    stable = raw;
    setLed(stable & 0b10, stable & 0b01);
  }

  delay(1);
}

Функция считывает кнопки, ждёт завершения дребезга и обновляет состояние светодиода. Она повторяется непрерывно, примерно раз в миллисекунду.

В начале каждого прохода состояния кнопок записываются в два бита переменной raw: бит 0 соответствует синей кнопке, бит 1 — зелёной.

Поскольку в setup включена подтяжка к питанию, нажатой считается кнопка, на входе которой присутствует логический ноль LOW. Возможны четыре двоичных значения:

  • 0b00 — ни одна кнопка не нажата;

  • 0b01 — нажата синяя кнопка;

  • 0b10 — нажата зелёная кнопка;

  • 0b11 — нажаты обе кнопки.

Если текущее «сырое» состояние отличается от предыдущего, произошло изменение: кнопку нажали или отпустили либо её контакт дребезжит.

Новое состояние сохраняется в lastRaw, а текущее время в миллисекундах — в lastChange. Пока контакт дребезжит и показания меняются, время последнего изменения постоянно обновляется:

if (raw != lastRaw) {
  lastRaw = raw;
  lastChange = millis();
}

Затем проверяются два условия: текущее состояние отличается от последнего подтверждённого и с момента изменения прошло более 30 мс. Если оба выполнены, дребезг считается завершённым и светодиоду задаётся нужный цвет.

Выражение stable & 0b10 выделяет бит зелёной кнопки, а stable & 0b01 — синей:

if (raw != stable && (millis() - lastChange) > DEBOUNCE_MS) {
  stable = raw;
  setLed(stable & 0b10, stable & 0b01);
}

Работа с прерываниями

Для обработки сигналов оборудования часто используют прерывания. Получив сигнал, например от кнопки, процессор приостанавливает основную программу и передаёт управление специальной функции — обработчику прерывания Interrupt Service Routine (ISR).

Обработчик должен выполнять работу быстро, чтобы процессор как можно скорее вернулся к основной программе.

В скетче esp32s3_onboard_rgb_interrupt.ino нажатия обрабатываются с помощью прерываний, поэтому постоянно опрашивать состояние кнопок в цикле не требуется.

При инициализации setup назначает обеим кнопкам обработчик onButtonChange:

void setup() {
  pinMode(BTN_BLUE,  INPUT_PULLUP);
  pinMode(BTN_GREEN, INPUT_PULLUP);
  setLed(false, false);

  attachInterrupt(digitalPinToInterrupt(BTN_BLUE),  onButtonChange, CHANGE);
  attachInterrupt(digitalPinToInterrupt(BTN_GREEN), onButtonChange, CHANGE);
}

Когда уровень на выводе кнопки меняется, выполнение основного цикла loop прерывается и вызывается onButtonChange:

void IRAM_ATTR onButtonChange() {
  lastEdge = millis();
  changed = true;
}

Режим CHANGE в attachInterrupt обеспечивает срабатывание как при нажатии, так и при отпускании кнопки.

Обработчик onButtonChange делает минимум необходимого: сохраняет время события в lastEdge и устанавливает флаг changed.

Атрибут IRAM_ATTR размещает обработчик во внутренней оперативной памяти IRAM, а не во флеш-памяти. Это важно, поскольку при записи во флеш-память ESP32 кэш может отключаться и код из неё в этот момент недоступен для выполнения.

Обе кнопки используют один обработчик. Их состояние определяется позднее, в loop:

void loop() {
  if (changed && (millis() - lastEdge) > DEBOUNCE_MS) {
    changed = false;
    bool blue  = (digitalRead(BTN_BLUE)  == LOW);
    bool green = (digitalRead(BTN_GREEN) == LOW);
    setLed(green, blue);
  }
}

Программа проверяет, произошло ли изменение и прошло ли более 30 мс с последнего изменения уровня:

const uint32_t DEBOUNCE_MS = 30;
…
changed && (millis() - lastEdge) > DEBOUNCE_MS

Когда условие выполняется, флаг changed сбрасывается и считывается текущее состояние обеих кнопок. Затем результат передаётся setLed, которая устанавливает цвет светодиода.

Поскольку программа считывает обе кнопки, неважно, какая из них была нажата первой и вызвала прерывание.

Переменные lastEdge и changed записываются обработчиком прерывания, а читаются в основном цикле loop. Поэтому они объявлены с модификатором volatile:

volatile uint32_t lastEdge = 0;
volatile bool changed = false;

Этот модификатор сообщает компилятору, что значение может измениться вне основного потока выполнения, например в обработчике прерывания, и его нужно читать из памяти при каждом обращении.

Без volatile компилятор может сохранить значение в регистре. В результате, например, цикл while, ожидающий изменения флага, может его так и не заметить.

При этом volatile обеспечивает чтение значения из памяти, но не делает составные операции атомарными.

Между проверкой и сбросом changed может возникнуть прерывание. Если это произойдёт, флаг будет потерян, но состояние кнопок считывается после сброса и изменение уровня будет учтено. Если же прерывание произойдёт после сброса, флаг установится снова и событие будет обработано на следующем проходе loop.

Подключение светодиодов к GPIO

Мы разобрались, как подключать кнопки к ESP32 и обрабатывать их сигналы. Теперь подключим к GPIO внешние светодиоды.

Соедините светодиоды с выводами GPIO6 и GPIO7 через резисторы номиналом 300 Ом (рис. 18).

Рис. 18. Добавляем светодиоды
Рис. 18. Добавляем светодиоды

Длинные выводы светодиодов — аноды — подключите к резисторам, а короткие соедините с землёй, контактом GND платы.

Программа button2led.ino

Простой скетч button2led.ino позволяет управлять светодиодами с помощью кнопок.

При инициализации для выводов кнопок включается подтяжка к питанию, а выводы светодиодов переводятся в режим выхода:

const int BTN1_PIN = 4;
const int BTN2_PIN = 5;
const int LED1_PIN = 6;
const int LED2_PIN = 7;
void setup() {
  pinMode(BTN1_PIN, INPUT_PULLUP);
  pinMode(BTN2_PIN, INPUT_PULLUP);
  pinMode(LED1_PIN, OUTPUT);
  pinMode(LED2_PIN, OUTPUT);
}

В цикле loop функция digitalRead считывает кнопки, а digitalWrite включает соответствующий светодиод при нажатии:

void loop() {
  digitalWrite(LED1_PIN, digitalRead(BTN1_PIN) == LOW);
  digitalWrite(LED2_PIN, digitalRead(BTN2_PIN) == LOW);
}

Подавление дребезга здесь не реализовано: его влияние не будет заметно глазу.

Программа esp32s3_2leds.ino

Скетч esp32s3_2leds.ino плавно меняет яркость двух светодиодов в противофазе: когда один становится ярче, второй гаснет, и наоборот (рис. 19).

Рис. 19. Качели светодиодов
Рис. 19. Качели светодиодов

Яркость регулируется с помощью широтно-импульсной модуляции (ШИМ).

При инициализации вызовы ledcAttach привязывают выводы к ШИМ-каналам с заданными частотой и разрядностью:

const int LED1_PIN = 6;
const int LED2_PIN = 7;
const uint32_t PWM_FREQ = 5000;   // 5 кГц, мерцания не видно
const uint8_t  PWM_BITS = 8;      // 0..255
…
void setup() {
  ledcAttach(LED1_PIN, PWM_FREQ, PWM_BITS);
  ledcAttach(LED2_PIN, PWM_FREQ, PWM_BITS);
}

Яркость изменяется в loop. В начале прохода вычисляется остаток от деления millis на 3000 мс — положение внутри трёхсекундного периода. Оно переводится в фазу от 0 до 2π, после чего вычисляется синус.

Синус принимает значения от −1 до 1. Следующее выражение преобразует этот диапазон в значения от 0 до 1:

float b1 = (sinf(phase) + 1.0f) / 2.0f;

Так определяется яркость первого светодиода. Для второго она вычисляется следующим образом:

float b2 = 1.0f - b1;

Благодаря этому светодиоды работают в противофазе.

Затем оба значения обрабатывает gamma8, учитывающая нелинейное восприятие яркости человеческим глазом. Она возвращает число от 0 до 255, которое передаётся в ledcWrite для обновления параметров ШИМ на каждом выводе.

В конце прохода выполняется задержка на пять миллисекунд:

const uint32_t PERIOD_MS = 3000;  // полный цикл «вдох-выдох»
uint8_t gamma8(float x) {         // x: 0.0..1.0
  return (uint8_t)(powf(x, 2.2f) * 255.0f + 0.5f);
}
void loop() {
  uint32_t t = millis() % PERIOD_MS;
  float phase = (float)t / PERIOD_MS * 2.0f * PI;

  // Синус превращаем из диапазона -1..1 в 0..1
  float b1 = (sinf(phase) + 1.0f) / 2.0f;
  float b2 = 1.0f - b1;           // противофаза

  ledcWrite(LED1_PIN, gamma8(b1));
  ledcWrite(LED2_PIN, gamma8(b2));
  delay(5);
}

Выводы GPIO платы ESP32-S3-DevKitC-1-N16R8

При автоматизации с помощью микроконтроллера важно понимать ограничения выводов GPIO. Их распиновка для ESP32-S3-DevKitC-1-N16R8 приведена на рис. 20.

Рис. 20. Распиновка GPIO для ESP32-S3-DevKitC-1-N16R8
Рис. 20. Распиновка GPIO для ESP32-S3-DevKitC-1-N16R8

Распиновка семейства также доступна на этой странице в разделе ESP32-S3-DevKitC-1 Pin Layout.

Хотя программа теоретически может обращаться к разным GPIO, выбирать выводы для внешних устройств нужно внимательно, чтобы избежать конфликтов.

Для обычных задач подходят GPIO1, 2, 4–18, 21, 38–42 и 47. На рис. 20 они отмечены зелёным. Номера соответствуют обозначениям на плате.

Следующие выводы использовать нельзя; на рисунке они отмечены красным или отсутствуют:

  • GPIO33–37 — заняты PSRAM модуля R8 и недоступны.

  • GPIO26–32 — подключены к SPI FLASH и PSRAM и не выведены наружу.

  • GPIO22–25 — физически отсутствуют у ESP32-S3.

С осторожностью также следует относиться к GPIO0, GPIO3, GPIO45, GPIO46, GPIO43, GPIO44, GPIO19 и GPIO20:

  • GPIO0 — соединён с кнопкой BOOT и используется для конфигурации при запуске.

  • GPIO3 — участвует в выборе источника JTAG и конфигурации при старте.

  • GPIO45 — используется для выбора напряжения SPI Flash.

  • GPIO46 — связан с выводом журнала ROM-загрузчика.

  • GPIO43, GPIO44 — используются консолью через USB-UART.

  • GPIO19, GPIO20 — соединены с разъёмом USB на плате.

Вывод GPIO48, а в версии платы 1.1 — GPIO38, управляет встроенным RGB-светодиодом.

Дополнительные сведения об аппаратной части и выводах приведены в документации «ESP32-S3-DevKitC-1 v1.0 User Guide».

Напряжение на выводах не должно превышать 3,3 В. Сигналы с уровнем 5 В необходимо подавать через делитель или преобразователь уровней.

Ток через вывод не должен превышать 20 мА. Абсолютный максимум составляет около 40 мА, но это предельное, а не рабочее значение. Поэтому светодиоды подключают через резисторы 220–330 Ом.

Периферийные функции ESP32-S3 распределяются через GPIO-матрицу. Благодаря этому I2C, SPI, UART, I2S и ШИМ (LEDC) можно назначить практически на любой подходящий GPIO. Стандартные назначения следующие:

  • I2C: SDA — GPIO8, SCL — GPIO9

  • SPI: CS — GPIO10, MOSI — GPIO11, SCK — GPIO12, MISO — GPIO13

На ESP32-S3-DevKitC-1-N16R8 доступны следующие возможности:

  • Два АЦП: ADC1 на GPIO1–10 и ADC2 на GPIO11–20. Wi-Fi-драйвер может периодически занимать ADC2, из-за чего чтение иногда завершается неудачно. Поэтому датчики предпочтительнее подключать к ADC1.

  • Сенсорные входы (Touch) доступны на GPIO1–14.

  • GPIO15 и GPIO16 предназначены для часового кварца 32 кГц (XTAL_32K_P/N). На официальной ESP32-S3-DevKitC-1 кварц не установлен — это видно на принципиальной схеме Espressif, — поэтому выводы можно использовать как обычные GPIO.

  • GPIO39–42 — выводы JTAG: MTCK, MTDO, MTDI и MTMS. Если внешний JTAG-отладчик не подключён, они могут работать как обычные GPIO.

Что изучить дальше

За пределами вводной статьи осталось немало важных тем. В следующих материалах об ESP32 мы рассмотрим подключение различной периферии, работу с Wi-Fi, отладку программ и другие вопросы.

В следующей статье перейдём от светодиодов к более серьёзной нагрузке и разберём управление лампами, электродвигателями и реле через GPIO. Выход микроконтроллера рассчитан на небольшой ток, поэтому подобные устройства подключают с помощью транзисторных ключей и драйверов. Я покажу, как их выбирать и подключать, а также приведу примеры программ.

Продолжайте изучать встраиваемые устройства на практике, собирая собственные схемы и экспериментируя с ними.

Автор @AlexandreFrolov


НЛО прилетело и оставило читателям нашего блога промокод:
скидка 15% на заказ нового VDS — HABRFIRSTVDS.

Положение об акции

 

Источник

Похожие статьи

Поиск по играм, новостям и статьям…

Введите не менее двух символов

Введите не менее двух символов