Первый вечер на ESP32 я потратил на склейку двух библиотек. Приёмник переписал из наших уроков — IrReceiver.begin() и decodedIRData, передатчик взял из статьи про ESP8266 — IRrecv irrecv и results.value. Итог закономерен: два диалекта в одном скетче, компилятор ругался на каждое второе имя, а я подозревал плату. Оказалось, в мире ESP8266 и ESP32 живёт собственная библиотека — IRremoteESP8266, и её API приёма — старая вторая версия IRremote, те самые IRrecv и decode_results, которые мы выносили за скобки при миграции.
Это не дубль, а отдельная экосистема. Список поддержанных протоколов шире — счёт идёт на сотню, и главное, в ней есть целый этаж классов климатической техники, которым посвящён третий урок тройки. Под капотом на ESP32 работает аппаратный блок RMT, и это меняет характер передачи сильнее, чем кажется: кадр перестаёт зависеть от того, чем занят скетч. Типичный проект на этой связке — шлюз: плата слушает пульт и пересылает команды в сеть, куда обычный Uno без щита расширений не добирается.
Здесь разберём оба диалекта построчно, посчитаем, что даёт RMT на практике, и соберём макетку: приёмник на 3.3-вольтовой логике, передатчик с транзистором, плюс грабли пинов, на которых я просидел два вечера. И всё это без щитов-переходников: две ноги GPIO и два провода питания.
Другое API: IRrecv, kIrLed и decode_results
Автор библиотеки сознательно держит старый API: скетчей на IRrecv под ESP8266 написаны тонны, ломать их не стали. Приёмник выглядит так: IRrecv irrecv(kIrPin); decode_results results; irrecv.enableIRIn(); и в loop — if (irrecv.decode(&results)). Результат лежит в results.value одним словом: у NEC туда складываются адрес и команда, у всех протоколов есть results.decode_type и results.bits. Отдельно есть флаг results.repeat: у NEC он поднимается на кадре-повторе, аналог флага IS_REPEAT из нового API — различение нажатия и удержания работает так же. Видели это зеркально: урок про миграцию на версию 4 переводил скетчи со старого API на новое — здесь перевод не нужен, старое и есть родное.
Передатчик — IRsend irsend(kIrLed): константа kIrLed задаёт пин ИК-светодиода, на большинстве плат по умолчанию это GPIO 4. После irsend.begin() доступны sendNEC(данные, биты), sendSony, sendRC5 и знакомый по RAW-уроку sendRaw(массив, длина, несущая). Пины задаются в конструкторах, а не в begin, и это моя любимая грабля: я однажды искал причину молчания передатчика в схеме, а диод просто висел на пятом пине при отправке с четвёртого.
Теперь RMT — блок Remote на кристалле. На классическом ESP32 восемь каналов (на S3 и C3 раскладка другая), каждый генерирует и мерит последовательности импульсов с шагом в доли микросекунды. IRremoteESP8266 отдаёт кадр такому каналу: процессор один раз заполняет таблицу интервалов, дальше железо мигает диодом само. На Uno sendRaw дёргает таймер и блокирует loop — наши 100 мс из RAW-урока; на ESP32 loop продолжает крутиться, даже когда WiFi в тот же момент таскает пакеты по сети. Форма импульсов перестаёт зависеть от скетча — для ИК это гарантия целого кадра.
#include <IRremoteESP8266.h>#include <IRrecv.h>#include <IRsend.h>#include <IRutils.h> const uint16_t kIrLed = 4; // пин ИК-светодиодаconst uint16_t kIrPin = 15; // пин приёмника TSOP IRsend irsend(kIrLed);IRrecv irrecv(kIrPin);decode_results results; void setup() { Serial.begin(115200); irsend.begin(); irrecv.enableIRIn(); // приёмник слушает} void loop() { if (irrecv.decode(&results)) { Serial.print("protokol="); Serial.println(typeToString(results.decode_type)); Serial.print("value=0x"); serialPrintUint64(results.value, HEX); Serial.println(); if (results.decode_type == NEC) { // эхо: повторяем принятый кадр со светодиода irsend.sendNEC(results.value, results.bits); } irrecv.resume(); // буфер свободен, слушаем дальше }}Приёмник ставится как на Uno, с одной поправкой питания. TSOP4838 живёт от 2.5 до 5.5 вольт, но GPIO ESP32 не толерантны к пяти вольтам: выход приёмника при питании от 5 В тянет ногу выше допустимых 3.3, и это верный способ похоронить порт. Питаем TSOP от пина 3V3 — и выход становится родным для GPIO. Карта ног и их капризов уже разобрана в уроке про распиновку DevKit.
Передатчик — наоборот, слабое место. Нога ESP32 отдаёт порядка 20-40 мА в пике, и ИК-диод напрямую через резистор 150 Ом светит уверенно на полметра-метр — для экспериментов на столе хватает. Управлять техникой через комнату — ставьте транзистор: 2N2222, база через резистор, ток диода 50-100 мА, дальность три-пять метров при прямой видимости. Пара чисел для базы: при hFE около сотни диоду на 60 мА хватит базы в полмиллиампера, то есть резистор 2.2-4.7 кОм; я ставлю 1 кОм без разбора — транзистор глубоко в насыщении, а пара лишних миллиампер базы никому не мешает. Мнение с границей: на макетке я ленюсь и кормлю диод напрямую, но постоянный пульт-шлюз собирал только с транзистором — неуспехи с дальностью дорого стоят по времени.
Про младшего брата — пару слов: на ESP8266 всё то же самое, включая kIrLed на GPIO 4 (на Wemos это подпись D2), приёмник чаще вешают на GPIO 14, подпись D5. Скетч с ESP32 переносится один в один: тот же IRrecv, те же decode_results, те же sendNEC и sendRaw. Разница в железе под капотом: RMT есть только у ESP32, ESP8266 генерирует импульсы таймером, поэтому длинный кадр там чувствительнее к тому, чем занят скетч.
Макетка: приёмник, передатчик и грабли пинов
Схема целиком: TSOP4838 — OUT на GPIO 15, VCC на 3V3, GND на GND; диод анодом через резистор 100-150 Ом на GPIO 4, катодом на GND, для дальности — через транзистор. Номера в скетче и в жизни должны совпасть: пины живут в конструкторах irsend(kIrLed) и irrecv(kIrPin). Грабля, на которой я просидел вечер, — приёмник на GPIO 12: это strapping-нога, чьё состояние при подаче питания выбирает напряжение флеша, и подтяжка от модуля TSOP мешала плате стартовать. Перенёс на 15 — ожило.
Тест стола перед интеграцией занимает две минуты. Шаг первый: наведите бытовой пульт на приёмник и нажмите любую кнопку — в мониторе должны появиться протокол и слово кадра. Шаг второй: направьте диод платы на собственный приёмник и дайте скетчу отправить кадр — увидите вторую строку с тем же value: приёмник и передатчик живы, можно учить технику. Я гоняю этот тест до того, как лезть с платой к телевизору: половина мнимых поломок убирается на столе.
Вторая грабля из мира библиотек: в один скетч не должны попадать оба заголовка, IRremote.hpp и IRremoteESP8266.h. Четвёртый IRremote ради совместимости держит свои IRrecv и decode_results, имена сталкиваются, и компилятор сыплет повторами определений. Один скетч — одна библиотека: Uno и Nano собирают на IRremote, ESP8266 и ESP32 — на IRremoteESP8266, выбор по плате, а не по статье, которая попалась первой.
| Вопрос | IRremote 4 (Uno) | IRremoteESP8266 (ESP32/ESP8266) |
|---|---|---|
| Приём | IrReceiver.decode() — decodedIRData.command | irrecv.decode(&results) — results.value |
| Старт приёмника | IrReceiver.begin(пин, ENABLE_LED_FEEDBACK) | irrecv.enableIRIn() |
| Передача | IrSender.sendNEC / sendRaw | irsend.sendNEC / sendRaw, пин в конструкторе |
| Генерация импульсов | таймер AVR, sendRaw блокирует loop | блок RMT, кадр уходит железу |
| Климатическая техника | нет готовых классов | IRac и классы по маркам: ir_Midea, ir_Gree и другие |
| Список протоколов | десятки | счёт на сотню |
- IRremoteESP8266 — родная библиотека ESP8266/ESP32: API второй версии, IRrecv, decode_results, results.value
- Передатчик: IRsend irsend(kIrLed), по умолчанию GPIO 4; пины задаются в конструкторах
- RMT — аппаратные каналы импульсов: кадр уходит железу, loop не блокируется даже при активном WiFi
- TSOP питаем от 3V3: GPIO ESP32 не переносят 5 вольт на выходе приёмника
- Диод напрямую — метр дальности; транзистор 2N2222 с током диода 50-100 мА — три-пять метров
- GPIO 12 — strapping-нога: периферия с подтяжкой на ней мешает загрузке
- 1. Какое API приёма использует IRremoteESP8266?
- 2. Что даёт блок RMT при отправке sendRaw на ESP32?
- 3. От чего питаем TSOP4838 на ESP32?
- 4. Диод напрямую от ноги ESP32 — какая дальность?
- 5. Почему приёмник не ставят на GPIO 12?
Теперь два диалекта не путаются: Uno и Nano — IRremote четвёртой версии, ESP8266 и ESP32 — IRremoteESP8266 со своим словарём. Какую плату брать под проект целиком, разобрано в уроке про выбор между ESP32 и ESP8266, а приёмный конвейер из анатомии decodedIRData переносится на новую библиотеку за вечер: смысл полей тот же.
Таблица кодов при этом переезжает без сюрпризов: пульт из набора декодируется в один и тот же NEC и там, и там — команда 67 остаётся командой 67. Меняются только имена полей и способ включения приёмника. Так что проекты из первых уроков раздела — свет с пульта, фильтры по адресу — переезжают на ESP32 переписыванием пары строк, а взамен получают WiFi и простор RAM для RAW-кадров. Дальше — самая необычная техника в разделе: кондиционеры, у которых кадр длиннее и хитрее всего, что мы до этого видели.
Частые вопросы по теме урока
- Какое API приёма использует IRremoteESP8266?
- Библиотека сознательно держит старый API: тонны скетчей под ESP8266 написаны на IRrecv и decode_results, и ломать их не стали. Старое второй версии: IRrecv, decode_results, results.value
- Что даёт блок RMT при отправке sendRaw на ESP32?
- RMT — аппаратные каналы импульсов: процессор один раз заполняет таблицу интервалов, железо мигает диодом само, скетч продолжает жить. На Uno те же 100 мс из RAW-урока — скетч просто глух. Дальность растёт вдвое
- От чего питаем TSOP4838 на ESP32?
- Выход TSOP при 5-вольтовом питании тянет ногу выше допустимых 3.3 В. Пин 3V3 на плате рядом — питаем от него, и выход становится родным. От батареи 9 В
- Диод напрямую от ноги ESP32 — какая дальность?
- Нога отдаёт 20-40 мА в пике — этого хватает на метр. Через 2N2222 с током диода 50-100 мА дальность вырастает до трёх-пяти метров. Дальность от способа подключения не зависит
- Почему приёмник не ставят на GPIO 12?
- GPIO 12 при подаче питания выбирает напряжение флеша по своему состоянию. TSOP с подтяжкой на этой ноге помешал загрузке — перенос на GPIO 15 решил всё. Только для аналоговых датчиков