Ночник стоит на макетке у кровати и включается кнопкой, до которой лень тянуться, — а значит, пора собрать пульт из того, что под рукой: вторая Uno, три тактовые кнопки, ИК-светодиод. Это самый дешёвый проект раздела: детали копеечные, а механика целиком уже разобрана — формирование кадра и вызов sendNEC показаны в уроке про IrSender.sendNEC. Здесь я собираю из них цельный прибор и разбираю решения, которых в том уроке не было: какой адрес выбрать, сколько слать повторов и как не дёргать чужой телевизор.
Внутри NEC-кадра всего два числа: адрес устройства и код команды — разбор по битам сделан в разделе про NEC, а инверсии в 32-битном слове расписаны отдельно. Пульт шлёт оба числа вслепую, всякому, кто слушает: ИК не знает про пары и не спрашивает согласия. Отсюда растут оба правила урока: свой адрес берите непохожим на соседей, а команду — коротким байтом, который вторая плата трактует однозначно. Масштабы не путать: у NEC адрес — шестнадцать бит, команда — восемь, и перепутанные местами константы в отладке выглядят как порча эфира.
Адрес: почему не 0xFF00 и не адрес вашего телевизора
Адрес — единственная перегородка между вашим пультом и остальными приборами в комнате. Возьмёте 0xFF00 — адрес пультов из дешёвых наборов, и любой такой приёмник начнёт выполнять ваши команды: известная история, когда самодельный пульт переключал разом ночник и соседнюю макетку, потому что у обеих стоял один и тот же адрес из туториала. Возьмёте адрес от пульта LG — половина истории ещё хуже: приёмник телевизора честно решит, что его окликнули, и канал переключится. У разных производителей наборов встречаются и 0xBF00, и 0x00FF — подбором адресов из коробок вы коллекционируете конфликты.
Решение стоит ноль: возьмите 16 бит от фонаря и запишите константой в шапке — у меня в проектах живут 0x0102 и 0x1A2B, с комментарием, какому прибору адрес принадлежит. Через полгода у вас будет три самодельных пульта, и книга адресов в шапке скетча спасёт вечер. Правило обратного теста: перед отправкой своей команды чужому прибору проверьте кадр сниффером — приёмник-читалка из урока про сниффер чужого пульта печатает адрес и команду каждого кадра, и вы увидите эфир ещё до сборки второй платы.
И оговорка про понты: пульт имеет смысл собирать там, где кнопок мало и линия видимости в порядке. Три-четыре слепых команды вслепую — его ниша, и в ней он бьёт и радио, и Wi-Fi ценой и простотой: ноль настройки, ноль сети, от двух батареек живёт годами. Меню, экраны обратной связи и обратный канал — про другое устройство.
Повторы: интерфейс кнопки, а не украшение
Третий аргумент sendNEC — число повторных кадров — решает, как кнопка ведёт себя при удержании. Переключатели света и режимов живут с нулём: одна команда — одно действие, и дубликат лишь мигал бы зря. Непрерывные величины — яркость, громкость, положение шторы — требуют повторов: держите кнопку, передатчик докладывает кадры, приёмник насчитывает шаги. У NEC кадр повтора устроен хитро — только заголовок без чисел, поэтому и повтор, и удержание считаются у приёмника отдельно; механика и фильтрация разобрана в уроке про NEC-повторы. В скетче ниже на каждое нажатие яркости уходят три повтора: даже если один кадр глотнёт лампа или стена, шаг дойдёт.
Дрожание контактов убираю millis-подходом без delay(): блокирующая пауза в loop вешает и опрос соседних кнопок, и весь будущий приём, а планировщик из урока про millis вместо delay стоит три строки. Фильтр по времени — не раньше 400 миллисекунд от прошлого кадра — давит не столько дребезг, сколько сдерживает палку: без него удержание задаёт темп повторов, и яркость пролетает весь диапазон за секунду. Держите фильтр честным: таймер отсчитывается от кадра любой кнопки, иначе две кнопки, нажатые почти одновременно, удвоят темп.
// Свой пульт: передатчик на Uno/Nano — только пин 3 (выход Timer2)#include <IRremote.hpp> const int BTN_LIGHT = 2; // свет: вкл/выклconst int BTN_UP = 4; // ярчеconst int BTN_DOWN = 5; // темнее const uint16_t MY_ADDRESS = 0x0102; // свой адрес, не как у наборовconst uint8_t CMD_LIGHT = 0x12;const uint8_t CMD_UP = 0x13;const uint8_t CMD_DOWN = 0x14; unsigned long lastSent = 0;bool prevLight = HIGH; void setup() { Serial.begin(9600); IrSender.begin(); // библиотека сама встанет на ногу 3 pinMode(BTN_LIGHT, INPUT_PULLUP); pinMode(BTN_UP, INPUT_PULLUP); pinMode(BTN_DOWN, INPUT_PULLUP); Serial.println("pult gotov, peredatchik na pine 3");} void loop() { unsigned long ms = millis(); if (digitalRead(BTN_LIGHT) == LOW && prevLight == HIGH) { IrSender.sendNEC(MY_ADDRESS, CMD_LIGHT, 0); // переключатель: без повторов lastSent = ms; Serial.println("otpravlen: svet"); } prevLight = digitalRead(BTN_LIGHT); // удержание: пачка повторов не чаще, чем раз в 400 мс if (digitalRead(BTN_UP) == LOW && ms - lastSent >= 400) { IrSender.sendNEC(MY_ADDRESS, CMD_UP, 3); // 3 повторных кадра lastSent = ms; Serial.println("otpravlen: yarkost+"); } if (digitalRead(BTN_DOWN) == LOW && ms - lastSent >= 400) { IrSender.sendNEC(MY_ADDRESS, CMD_DOWN, 3); lastSent = ms; Serial.println("otpravlen: yarkost-"); }}Две детали схемы, которых не видно в коде. Светодиод ставится не на удобную ногу, а строго на пин 3: генератор 38 килогерц завязан на второй таймер Uno и Nano, и его выход — именно эта нога; библиотека настроит таймер сама, но пересадить диод на соседний пин без правки библиотеки не получится. Вторая деталь — ток: прямые 30–50 миллиампер для ноги многовато, ставьте резистор 100–150 Ом, а про оптику и дальность разговор идёт в уроке про ИК-светодиод 940 нм. И помните про камеру: не всякая ловит 940 нанометров одинаково, у части моделей пятно бледное — проверьте свой заранее на живом пульте от телевизора.
Проверяйте пульт до появления второй платы. Камера телефона видит ближний инфракрасный слабым фиолетовым пятном на чёрном фоне — уходят кадры или нет, видно без всякого приёмника. Дальше стенд из одной платы: сниффер печатает адрес и команду каждого кадра, вы сверяете их со своей книгой. И только потом берите вторую Uno с приёмником на пине 11 и словарём команд: урок про две платы и свой протокол показывал и собственный формат кадров, но вам он не нужен — NEC готовый, вторая плата просто слушает IrReceiver-ом. Словарь на приёмной стороне берите из уроков раздела: там он уже в PROGMEM.
| Решение | Значение по умолчанию | Почему |
|---|---|---|
| адрес пульта | свой 16-битный, например 0x0102 | не совпадёт ни с наборами 0xFF00, ни с бытовой техникой |
| повторы для переключателей | 0 | дубликат переключателя мигает впустую |
| повторы для непрерывных величин | 3 и больше при удержании | шаг дойдёт, даже если кадр глотнёт стена |
| пауза между отправками | 400 мс и больше | сдерживает темп и глушит дребезг без delay |
Книга команд и отладка пары плат
Книгу команд стройте по прибору, а не по кнопкам: свет — 0x12, ярче — 0x13, темнее — 0x14, ночная сцена — 0x15. Байты идут подряд, и в отладке пропущенный шаг виден сразу; скачущие числа вроде 0x12, 0x67, 0x03 превращают каждое совещание с пультом в головоломку. Дыры в нумерации держите как запас: добавите четвёртую кнопку — впишете 0x16, не перекраивая ни таблицу приёмника, ни привычки пальцев.
Пара плат отлаживается по двум мониторам: передатчик печатает то, что шлёт, приёмник — то, что поймал. Числа совпали, а действие не стронулось — ищите фильтр адреса на приёмнике или константу с чужим регистром. Расхождение в числах почти всегда про физику: диод светит мимо, угол завален, батарейка села, — код тут ни при чём, и это радует, потому что код вы уже проверили.
И не пренебрегайте сниффером после сборки: он независим от ваших скетчей и видит эфир честно. Из моей практики: передатчик светил с макетки под углом в сорок градусов к приёмнику, кадры доходили через отражение от потолка, и дальность плавала вместе с погодой за окном. Подвинул диод на два сантиметра — исчезла целая категория необъяснимых жалоб.
- 1. Какую ногу на Uno/Nano отдают под ИК-светодиод передатчика в IRremote 4.x?
- 2. Управляете яркостью по удержанию кнопки. Сколько повторов просить у sendNEC?
- 3. Какой адрес выбрать для своего пульта?
- 4. Почему приёмник и передатчик IRremote не ставят на одной Uno?
- 5. Кнопку держат нажатой, пульт шлёт NEC-повторы. Что делает приёмник второй платы?
- Пульт из Arduino — светодиод 940 нм на пине 3 и sendNEC(адрес, команда, повторы); остальное — кнопки и millis
- Адрес берите свой и запишите в книгу в шапке: 0xFF00 и адреса бытовой техники — гарантированный конфликт
- Ноль повторов — переключателям, три и больше — яркости и громкости при удержании
- Одна плата — одна роль: приём и передача делят Timer2, вместе на Uno не живут
- Проверка без приёмника: камера телефона видит ИК-вспышки фиолетовым пятном; сниффер печатает адрес и команду каждого кадра
Частые вопросы по теме урока
- Какую ногу на Uno/Nano отдают под ИК-светодиод передатчика в IRremote 4.x?
- Генератор несущей 38 кГц завязан на второй таймер, его выход — нога 3. Библиотека настроит таймер сама; переставить светодиод на другую ногу без правки библиотеки не получится. Пин 11 — история приёмника, пин 13 — индикация. пин 3 — выход второго таймера
- Управляете яркостью по удержанию кнопки. Сколько повторов просить у sendNEC?
- Непрерывные величины живут на повторах: приёмник считает кадры и шагает. Ноль годится для переключателей, где дубликат безвреден, а непрерывному шагу нужны запасные кадры. три и больше, по числу повторных кадров во время удержания
- Какой адрес выбрать для своего пульта?
- Свой адрес не пересекается ни с наборами, ни с бытовой техникой: чужой приёмник не примет ваш кадр за свой. 0xFF00 и адреса реальных пультов — гарантированные конфликты. Книга адресов в шапке — страховка на случай второго пульта. свой случайный 16-битный, записанный константой в шапке
- Почему приёмник и передатчик IRremote не ставят на одной Uno?
- Приём и генерация несущей живут на Timer2 ATmega328. Совместное использование даёт плавающие отказы, поэтому пару собирают из двух плат. оба требуют второй таймер: один из соседей оглохнет
- Кнопку держат нажатой, пульт шлёт NEC-повторы. Что делает приёмник второй платы?
- Повторные кадры — топливо непрерывных величин: счётчик шагов растёт, пока держат кнопку. Первый кадр несёт адрес и команду, повторы — только заголовок. Фильтр повторов и счётчик шагов — тема урока про NEC-повторы. считает кадры и шагает величину