Кровать у стены, телевизор посередине, диван напротив — и пульт, который с кровати работает через раз. Я неделю двигал приёмник по полке сантиметр за сантиметром: поставишь к окну — не ловит с дивана, вернёшь к двери — мёртвая зона за спинкой кресла. Спинка съедает прямой луч, отражение от потолка слабое, и комната в пять метров оказывается длиннее паспортных восьми метров дальности. Про то, как геометрия и отражения режут сигнал, я уже писал в уроке про дальность и геометрию приёма — полкой это не лечится: каждый сантиметр в пользу одной половины комнаты отбирается у другой.
Лечится вторым глазом. Приёмник TSOP стоит копейки, лежит в каждом наборе, и второй экземпляр в дальнем конце комнаты закрывает мёртвую зону физически, а не молитвой. Вопрос только в разводке: пин у платы не резиновый, а коду ещё полезно знать, с какой стороны пришла команда — хотя бы чтобы понимать, кто в доме нажал пульт. Я перепробовал все три пути — спаянные выходы, два пина, вторую плату — и у каждого своя цена, о которой в туториалах обычно молчат.
Дальше по плану: почему два выхода приёмника можно соединить прямо накоротко, чего библиотека IRremote 4.x не умеет с двумя пинами (и что она честно умеет), а в конце — мой скетч опроса двух зон с приоритетом, фильтром брака и журналом в мониторе порта.
Один пин или два: что умеет библиотека на самом деле
Начну с приятного: выход TSOP — транзистор с открытым коллектором, деталь умеет только прижимать линию к нулю, высокий уровень держит подтяжка. Об этом я подробно писал в уроке про подключение VS1838B. Из этого свойства следует неожиданный бонус: два выхода можно соединить накоротко на один пин, и ничего не сгорит — конфликтовать тут нечему, кто услышал пульт, тот и прижал линию. Авторы IRremote так и пишут в README: соедините выходы нескольких приёмников с одним входом, это классическая схема открытого коллектора.
Плата за простоту двойная. Первая: на одном пине зоны неразличимы — код видит один и тот же кадр, и выяснить, какой «глаз» его поймал, невозможно в принципе. Вторая: если оба приёмника слышат один пульт, кадры приходят с разными задержками и накладываются друг на друга — на форумах это описано ровно как «принимает то правильно, то нет». Лечится не кодом, а геометрией: разворачиваю приёмники линзами в разные концы комнаты с разносом в три-четыре метра, и каждый слушает только свою половину.
Если же зона нужна по задаче — трекер присутствия, две комнаты, лог «откуда нажали» — одним пином не обойтись. Тут надо знать границы библиотеки: в IRremote 4.x приёмник один, IrReceiver — синглтон, приём сидит на прерывании смены пина, и второй экземпляр библиотека в штатном режиме не поднимает. Честный двухзонный приём на одной плате — свой опрос двух пинов без библиотеки: длительности кадра NEC я раскладывал в уроке про 32 бита, здесь их меряет pulseIn. Своего декодера не бойся: он на сорок строк и разбирает только то, что реально шлёт твой пульт.
// TSOP на пинах 2 (окно) и 3 (диван). IRremote не участвует: IrReceiver// в 4.x один, а зоны нужны поимённо. Выход приёмника инвертирован —// пачка несущей прижимает линию к нулю, между кадрами подтяжка держит HIGH.const int PIN_Z1 = 2;const int PIN_Z2 = 3; unsigned long tLastCmd = 0; // true — с пина собран валидный кадр NEC, команда лежит в cmdbool readCommand(int pin, byte &cmd) { unsigned long pulse = pulseIn(pin, LOW, 15000); // пачка преамбулы if (pulse < 8000 || pulse > 10500) return false; // 9 мс у NEC, прочее — брак pulse = pulseIn(pin, HIGH, 10000); // пауза после преамбулы if (pulse < 3500 || pulse > 5500) return false; // 4.5 мс у полного кадра byte addr = 0, inv = 0, cmd8 = 0, cmdInv = 0; for (int i = 0; i < 32; i++) { if (pulseIn(pin, LOW, 3000) == 0) return false; // пачка бита — 0.56 мс unsigned long space = pulseIn(pin, HIGH, 3000); // пауза: 0.56 — ноль, 1.68 — единица if (space == 0) return false; byte bit = (space > 1100) ? 1 : 0; if (i < 8) addr = (addr << 1) | bit; else if (i < 16) inv = (inv << 1) | bit; else if (i < 24) cmd8 = (cmd8 << 1) | bit; else cmdInv = (cmdInv << 1) | bit; } cmd = cmd8; return true;} void setup() { Serial.begin(9600); pinMode(PIN_Z1, INPUT); pinMode(PIN_Z2, INPUT); Serial.println("Dve zony: okno i divan");} void loop() { byte cmd = 0; if (readCommand(PIN_Z1, cmd) && millis() - tLastCmd > 200) { Serial.print("[zona 1 okno] cmd="); Serial.println(cmd, HEX); tLastCmd = millis(); return; // кадр первой зоны победил — второй ждём заново } if (readCommand(PIN_Z2, cmd) && millis() - tLastCmd > 200) { Serial.print("[zona 2 divan] cmd="); Serial.println(cmd, HEX); tLastCmd = millis(); }}Как это работает: pulseIn ждёт падения линии до нуля, фильтр 8000–10500 микросекунд отбирает девятимиллисекундную преамбулу NEC, дальше пауза 4.5 мс и тридцать два бита по длительностям пауз — 0.56 мс ноль, 1.68 мс единица. Меня интересует третий байт, команда; проверку инверсии я для журнала опускаю — брак отсеивается уже на преамбуле, развалившийся кадр просто не проходит фильтры. Полную расшифровку с инверсией делала библиотека, а как устроены байты кадра — в уроке по ссылке выше. В журнале команда печатается в hex, и читать 0x21 и 33 как одно число помогает урок про bin, hex и dec — привычка нужная, когда сравниваешь журналы двух зон между собой. Сами пины для приёмника держи INPUT: подтяжка уже стоит внутри модуля, лишняя только срежет размах.
Приоритет здесь фиксированный: зона 1 опрашивается первой и при одновременном приходе забирает кадр себе. Качество приёма в логе видно другим способом — битый кадр не проходит фильтр длительностей, зона молчит, и в мониторе остаются только честные срабатывания. Дебаунс на двести миллисекунд гасит дубли на случай, когда кадр успели услышать обе зоны подряд. Приоритет можно сделать и плавающим: считаешь брак по каждой зоне за минуту и первым опрашиваешь глаз с меньшим. Честно скажу, в квартире с двумя приёмниками одной партии порядок опроса ни разу не стал узким местом — проще подобрать пару и не плодить состояния.
Оговорка, которую я обязан сделать: опрос блокирующий. Пока pulseIn слушает зону 1 до пятнадцати миллисекунд, кадр зоны 2 может пройти незамеченным. Для пульта это не смерть — при удержании повтор приходит каждые 108–110 мс — но в боевой проект такой цикл берут с фильтром мусорных кодов из урока про помехи, а если две зоны на одной плате не складываются, есть план Б — плата-ретранслятор в дальнем конце комнаты.
Арифметика на пределе, и её стоит держать в голове: полный кадр NEC тянется 68 миллисекунд, а два прохода pulseIn с таймаутами съедают до тридцати. Пока слушаю зону 1, кадр зоны 2 проходит мимо — не баг, а расплата за опрос двух пинов одной платой. Спасает то, что пульт шлёт повтор через 108–110 мс: потерянное нажатие дублируется само, и журнал зон за вечер не теряет ни одного реального нажатия — теряет разве что часть дублей, которые и не нужны.
Зоны в деле: засветка, клоны и проверка перед пайкой
Засветка ломает приоритет молча. Приёмник у окна ловит солнце и лампы, автоматика усиления задирает порог — дальняя зона слышит лучше ближней, и лог показывает обратную картину. Я влезал в эту историю на кухне с окном на юг: днём работала только дальняя зона, вечером обе, и первый час я грешил на код, хотя виноват был свет. Помогло то же, что и в уроке про помехи от света: разворот линз от окна и конденсатор в питании каждого приёмника.
Мой второй тупик — пара приёмников с разных партий: безымянный клон с дивана оказывался чувствительнее «фирменного» у окна, и зона 1 стабильно проигрывала. Вывод простой, теперь он у меня в правиле: два глаза для одной комнаты беру одной марки и одной партии — разброс чувствительности у клонов достигает двукратного, и приоритет в коде не спасает от железа, которое слышит неровно.
Перед пайкой зоны проверяют на макетке за десять минут: скетч-тестер из урока про подключение на каждый пин по очереди, пульт в руке, ходишь по комнате и смотришь, в какой точке кадр собирается, а где разваливается. Отмечаешь мёртвые зоны прямо на плане квартиры — приёмники встают по ним, а не наугад.
Отдельное слово про провод: сигнальная линия на длинной дистанции живёт с подтяжкой, а не на честном слове. У меня две зоны соединялись четырьмя метрами витой пары — сигнал на конце проседал, кадры разваливались на битах, и журнал показывал только дальнюю зону. Перенёс резистор подтяжки на дальний конец линии, к самому приёмнику, и картина выровнялась: правило то же, что для любой длинной цифровой линии — держи подтяжку у источника, а не у входа платы.
Питание держи раздельным, с развязкой каждому глазу: резистор 100 Ом и электролит 4.7 мкФ, как просит даташит. Две линзы на одной рейке с ШИМ-нагрузкой ловят фантомов в две руки — журнал зон заполнится призраками быстрее, чем ты успеешь нажать пульт, и отличать их от честных кадров придётся уже фильтром кодов. Дешевле сразу развязать: конденсатор стоит копейки, а вечер с журналом призраков — дороже.
| Схема | Код | Зоны | Где ломается |
|---|---|---|---|
| Выходы вместе на один пин | скетч прежний, IRremote 4.x | не различить | наложение кадров, если оба приёмника видят один пульт |
| Два пина, свой опрос | свой декодер на pulseIn, около 40 строк | честный лог зоны | блокирующий опрос: кадр второй зоны можно пропустить |
| Две платы-ретранслятора | у каждой свой скетч | по номеру платы | связь между платами и два блока питания |
Кнопка → 32-битный кадр: AGC, инверсии и repeat видны глазом; включите помехи и поймайте бит, который не прошёл проверку.
Подгружаем интерактив…
- Выход TSOP с открытым коллектором только прижимает линию к нулю — поэтому два выхода можно соединить на один пин, официальный путь из README IRremote
- На одном пине зоны неразличимы: код видит кадр, но не знает, какой приёмник его поймал
- IRremote 4.x держит один IrReceiver-синглтон; приём сидит на прерывании смены пина, второй канал штатно не поднимается
- Двухзонный опрос на pulseIn: преамбула 9 мс, пауза 4.5 мс, биты по паузам 0.56/1.68 мс; брак отсеивается фильтрами длительностей
- Приоритет фиксирован порядком опроса, дебаунс 200 мс гасит дубли; наложение кадров лечится разворотом линз, а не кодом
- Приёмники одной партии и развязка в питании каждому: разброс чувствительности клонов до двух раз
- 1. Почему два выхода TSOP можно спаять прямо вместе на один пин?
- 2. Оба приёмника слышат один пульт, и коды принимаются «то верно, то нет». В чём причина?
- 3. Что в скетче урока показывает качество приёма зоны?
- 4. Сколько приёмников поднимает IRremote 4.x в штатном режиме на одной плате?
- 5. Приёмники спаяны на один пин, кадры разваливаются. Первое действие?
Зоны настроены, журнал честно показывает, какая половина комнаты услышала кнопку, а мёртвых точек на плане квартиры больше нет. Следующий шаг логичен: пульт — это же готовый пультовый интерфейс не только для комнаты, но и для умного дома. Дальше подключаю мост: код кнопки уходит из IRremote в топик MQTT, а Home Assistant делает с ним всё, что захочется — от света до штор, о которых пойдёт речь в конце пакета.
Частые вопросы по теме урока
- Почему два выхода TSOP можно спаять прямо вместе на один пин?
- Открытый коллектор только тянет линию вниз; высокий уровень даёт подтяжка. Поэтому параллельное соединение выходов — штатная схема, которую советует сам README IRremote. Выход с открытым коллектором умеет только прижимать линию к нулю — конфликтовать нечему
- Оба приёмника слышат один пульт, и коды принимаются «то верно, то нет». В чём причина?
- Один и тот же кадр доходит до приёмников в разные моменты, фронты складываются и разваливают тайминги. Лечение геометрическое: разворот линз в разные концы комнаты. Кадры от двух приёмников приходят с разной задержкой и накладываются друг на друга
- Что в скетче урока показывает качество приёма зоны?
- Развалившийся кадр не проходит фильтр преамбулы 8000–10500 мкс и отбрасывается. Приоритет при этом фиксированный — первой опрашивается зона 1. Битый кадр не проходит фильтр длительностей — зона молчит, в логе только честные срабатывания
- Сколько приёмников поднимает IRremote 4.x в штатном режиме на одной плате?
- В 4.x приёмник один, приём сидит на прерывании смены пина. Второй канал — только своим опросом без библиотеки или параллельными выходами без зон. Один: IrReceiver — синглтон
- Приёмники спаяны на один пин, кадры разваливаются. Первое действие?
- Наложение кадров — геометрическая проблема: линии затыкают разворотом приёмников с разносом в три-четыре метра, чтобы каждый слышал свою половину комнаты. Развернуть приёмники линзами в разные концы комнаты