Кухонный ночник неделю слушался пульта безупречно — пока однажды не зажёгся сам. Я в соседней комнате крутил громкость музыкального центра, а у ночника в таблице кодов на команде 21 сидело включение света. Команды совпали: и центр, и ночник видели один и тот же байт. Досаднее всего было то, что пульт центра я держал спиной к ночнику — он даже не светил в его сторону, кадр добрался по отражению от белого потолка.
Разбор этого полтергейста и есть тема урока. У NEC внутри каждого кадра лежат не только 8 бит команды, но и 8 бит адреса — паспорт устройства, для которого кадр предназначен. Ночник игнорировал адрес и потому слушался всех подряд.
Разберём кадр NEC до последнего бита: чем отличается бит 0 от бита 1 на линии, зачем в посылке две инверсии, откуда берётся кадр-повтор и как за одну проверку отучить плату реагировать на чужие пульты. Обещание на конец урока: адрес любого пульта в доме вы сможете снять за пять минут и вписать в скетч одной строкой.
Кадр изнутри: лидер 9 мс и биты длиной паузы
Секрет NEC в том, что все вспышки на линии одинаковые: каждая начинается пачкой несущей 38 кГц длительностью 560 мкс, и глазом от бита к биту не отличишь. Пачечная структура — не украшение: солнцу и лампам притвориться прерывистым светом с такой частотой не даётся, и приёмник их отсеивает. Смысл бита зашит в тишину после вспышки: пришло 560 мкс темноты — это ноль, пришло 1690 мкс — единица. Бит 0 живёт 1,12 мс, бит 1 — 2,25 мс, и данные целиком едут в интервалах между вспышками. Приёмник меряет эти паузы и складывает биты в байты — именно поэтому такой метод называют кодированием длиной паузы.
Кадр начинается с шапки: вспышка 9 мс и пауза 4,5 мс. Девять миллисекунд несущей — это будильник для приёмника: за это время автоматическая регулировка усиления TSOP успевает подстроиться под яркость и расстояние, а короткие помехи от ламп шапкой не притворяются. После шапки идут 32 бита данных. Весь кадр занимает от 49 до 85 мс в зависимости от числа единиц — при равной смеси нулей и единиц получается около 68 мс.
Для ощущения масштаба: в ленте WS2812 бит живёт 1,25 мкс, а NEC-бит — в тысячу раз дольше. Пульту спешить некуда: у него нет провода, и весь запас надёжности выбирается длинными, хорошо различимыми интервалами. Если захочется понять, как такие интервалы меряют на микросекундном уровне, загляните в урок про точные замеры micros — библиотека делает ровно то же самое, только аппаратным таймером внутри прерывания.
#include <IRremote.hpp> const int IR_PIN = 2;const byte MY_ADDRESS = 0x00; // возьмите из читалки для своего пульта void setup() { Serial.begin(9600); IrReceiver.begin(IR_PIN, ENABLE_LED_FEEDBACK);} void loop() { if (IrReceiver.decode()) { byte addr = IrReceiver.decodedIRData.address; byte cmd = IrReceiver.decodedIRData.command; if (addr == MY_ADDRESS) { Serial.print("addr=0x"); Serial.print(addr, HEX); Serial.print(" cmd=0x"); Serial.print(cmd, HEX); Serial.print(" dec="); Serial.println(cmd); } // resume обязателен даже для чужих кадров: // иначе застрянете на первой же чужой посылке IrReceiver.resume(); }}За лидером едут четыре байта: адрес, инверсия адреса, команда, инверсия команды. Инверсия — это тот же байт, но с перевёрнутыми битами: у команды 0x43 инверсия 0xBC, и в сумме пара всегда даёт 0xFF. Приёмник проверяет обе пары: если хоть одна не сходится, кадр битый и выбрасывается целиком. Два байта накладных расходов вместо полноценной контрольной суммы — дешёвая и неубиваемая защита, за которую NEC и любят производители дешёвых пультов.
Обратите внимание на комментарий в скетче: resume() стоит за пределами фильтра. Это распространённая редактура ошибок — поставить resume только внутрь if и на чужом кадре намертво застрять: структура занята, decode() молчит, пульт кажется сломанным. Читали или нет — буфер освобождай всегда. Поля кадра, если забыли их назначение, разобраны в уроке про анатомию decodedIRData.
Hex-печать здесь не украшение: сравнивать кадр с даташитом удобнее в шестнадцатеричной системе, а десятичный столбец я печатаю для сверки с собственной таблицей кодов из первого урока раздела. Два представления одного числа в одном логе экономят десяток секунд на каждую кнопку. А инверсию байта можно пощупать руками: ниже — интерактивная песочница, соберите команду из битов и нажмите XOR 0xFF — увидите тот самый перевёрнутый байт, второй в паре NEC.
Биты, байты и переполнение — видно глазами, а не в голове.
Подгружаем интерактив…
Адрес и команда: почему пульты не конфликтуют
Восемь бит адреса — это 256 значений, и производитель зашивает своё так, чтобы пульт от телевизора не переключал каналы ресиверу. Это не секретность и не защита от соседей — это маршрутизация внутри одного комплекта техники. Для нас адрес — готовый фильтр: одна строка сравнения, и ночник больше не реагирует на громкость центра.
Но у фильтра есть граница применимости, проверенная на моих трёх китайских пультах из наборов: у двух из них адрес 0x00. Нулевой адрес — любимый вариант безымянных клонов, поэтому фильтр вида «адрес равен нулю» пропустит всех соседей с такими же пультами. Если в доме два и больше дешёвых пульта, различайте их по комбинации адреса и команды, а ещё лучше — просто спрячьте макетку от прямого луча: отражение от потолка, как в истории из вступления, добирается до приёмника легче, чем кажется.
Моё рабочее правило: фильтр по адресу ставлю в каждом постоянном проекте, но адрес вписываю в константу из результатов собственной читалки, а не из чужой статьи. Код повторяется из урока в урок один в один — меняется только число, и именно оно решает, чьи команды слышит плата. Проверку устраивайте на двух пультах сразу: положите их рядом и жмите одинаковые по смыслу кнопки — один и тот же код с разными адресами собирается в пару быстрее, чем кажется.
| Часть кадра NEC | Длительность или состав | Зачем она нужна |
|---|---|---|
| Лидер | вспышка 9 мс | будит приёмник, усиление подстраивается под расстояние |
| Пауза лидера | 4,5 мс тишины | отделяет шапку от данных, помеха такой длины редка |
| Бит 0 | 560 мкс вспышка + 560 мкс пауза | итого 1,12 мс |
| Бит 1 | 560 мкс вспышка + 1690 мкс пауза | итого 2,25 мс — ровно вдвое дольше нуля |
| Байты 1–2 | адрес и его инверсия | паспорт устройства плюс проверка целостности |
| Байты 3–4 | команда и её инверсия | номер кнопки плюс проверка целостности |
| Кадр-повтор | 9 мс + 2,25 мс, каждые 108 мс | сообщение «кнопку всё ещё держат» без пересылки бит |
Симулятор: switch с фильтром адреса
- Кадр NEC: лидер 9 мс плюс пауза 4,5 мс, затем 32 бита; бит 0 — 1,12 мс, бит 1 — 2,25 мс
- Все вспышки одинаковые по 560 мкс — значение бита несёт длина тишины после вспышки
- Четыре байта: адрес, инверсия адреса, команда, инверсия команды; не сходится с 0xFF — кадр битый
- При удержании пульт шлёт кадр-повтор 9 + 2,25 мс каждые 108 мс вместо полного кадра
- Фильтр по decodedIRData.address отучает плату от чужих пультов; у части китайских клонов адрес 0x00
- resume() обязателен для любого кадра, включая отфильтрованный — иначе decode() застрянет
- 1. Сколько байтов полезных данных в кадре NEC и что это за байты?
- 2. Чем бит 1 отличается от бита 0 на линии NEC?
- 3. В кадре пришли команда 0x43 и байт 0xBC. Что это значит?
- 4. Зачем пульт при удержании шлёт кадр-повтор вместо полного кадра?
- 5. Два пульта дают команду 21 на разных кнопках. Что различит их?
Кадр NEC разобран до микросекунд, фильтр по адресу стоит, и полтергейст с громкостью центра больше не потревожит. Дальше по разделу — пульты, которые живут вне NEC: Sony SIRC, RC5 и RAW-дампы продолжат историю с той же читалкой и новым словарём. А практику закрепите на своей технике: снимите адрес каждого пульта в доме читалкой, впишите их в константы и попробуйте команду, которую шлют два пульта сразу — разницу увидите на первый же кадре.
Частые вопросы по теме урока
- Сколько байтов полезных данных в кадре NEC и что это за байты?
- 32 бита — это четыре байта, причём половина из них — инверсии: та самая бесплатная проверка целостности пары с суммой 0xFF. Четыре: адрес, инверсия адреса, команда, инверсия команды
- Чем бит 1 отличается от бита 0 на линии NEC?
- Вспышки всегда по 560 мкс. Данные едут в тишине: 560 мкс паузы — ноль, 1690 мкс — единица. Пауза после вспышки — 1690 мкс против 560 мкс
- В кадре пришли команда 0x43 и байт 0xBC. Что это значит?
- 0x43 + 0xBC = 0xFF — пара сходится, инверсия подтверждает команду. Разошлось бы — библиотека выбросила кадр ещё до decode(). 0xBC — инверсия 0x43, кадр целый
- Зачем пульт при удержании шлёт кадр-повтор вместо полного кадра?
- Кадр-повтор — только шапка 9 мс плюс 2,25 мс паузы. Его смысл: «ту же кнопку всё ещё держат», без пересылки 32 бит. Короткий кадр 11 мс вместо 50–85 мс экономит батарейку и время эфира
- Два пульта дают команду 21 на разных кнопках. Что различит их?
- Команда — номер кнопки внутри своего пульта. Границы между устройствами рисует адрес: 256 значений на семейство техники. Адрес из первого байта кадра