На журнальном столике у меня жили три пульта: телевизор, колонка и люстра. Каждый вечер начинался с археологии в подушках дивана. Коды всей техники я снял читалкой за один вечер и понял: Arduino уже знает всё, что нужно, — осталось назначить кнопки на самой плате и научить её шлать команды сама. Первая версия заработала с сюрпризом: сценарий кино включал колонку и крутил громкость, но люстра мигала светом от каждой третьей команды громкости, будто её дёргали за провод.
Мигание стало лучшим уроком недели: люстра была собрана на пульте-клоне с адресом 0x00, и диод, светящий в её сторону, будил светильник от кадров, предназначенных колонке. Здесь разберём, как сложить коды своей техники в таблицу, как собрать из них сценарии и куда направить диод, чтобы управлять нужным устройством, а не всей комнатой сразу.
Идея пришла, когда я в третий раз за месяц чистил батарейный отсек люстрового пульта от следов батарейки, которая умерла полгода назад и честно протекла. Колонка и телевизор жили нормально, но три коробочки с крошечными кнопками на одном столике — уже не удобство, а склад. Плата с парой кнопок занимает вдвое меньше места, а батарейки ей заменяет зарядка из ящика — от старого телефона.
Таблица кодов: вечер с читалкой
Фундамент пульта — таблица, и собирается она элементарно. Направляете каждый родной пульт на читалку из урока про приём кодов, жмёте кнопки по очереди, записываете пары адрес-команда. У моей колонки вышло четыре записи: power 67, VOL+ 21, VOL− 7, EQ 9, адрес 0x00 — EQ переключает саунд-режимы, пригодился позже для ночного прослушивания. У телевизора — своя тройка: power 67, каналы 69 и 70. Восемнадцать кнопок трёх пультов ужались в короткий комментарий над скетчем — и это вся база данных моего домашнего ИК-моста.
Храню таблицу в константах над скетчем: имя, адрес, команда — по строке на кнопку. Отладка несложная: шлёте команду из таблицы, смотрите на технику, сверяете с читалкой. Кнопка не сработала — первым делом перепечатайте её код заново, а не перепрошивайте вслепую: севшая батарейка в родном пульте плывёт по интервалам, и вы получаете те же симптомы, что при UNKNOWN-кадрах.
Таблица — это ещё и контракт между приёмом и передачей. Если завтра в доме появится новая колонка с фирменным пультом, я дописываю строки, не трогая сценарии: функция otpravit() одна на все команды, и сценарии ссылаются на неё, а не на разрозненные вызовы. Мой формат записи: имя для лога, адрес, команда и число повторов по умолчанию — четыре поля полностью описывают кнопку. Держите имена в одном стиле, иначе через месяц в комментариях начнётся анархия: у меня когда-то рядом жили VOL-, громкость и ГромкостьМинус — три имени одной кнопки.
Само снятие таблицы за вечер проходит легче по сценарию. Свежие батарейки во все пульты, прямая видимость с читалкой, каждую кнопку жмёте дважды и сверяете два напечатанных кадра: совпали — запись надёжная, разошлись — третий прогон и батарейка под подозрением. У меня спорными традиционно выходят кнопки верхнего ряда: палец давит сбоку, кадр уходит с половины комнаты в стену, и читалка ловит ослабленный сигнал. На снятие восемнадцати кнопок уходит полчаса, из которых двадцать минут — это перепечатывать цифры в заметки телефона, не вылезая из дивана.
#include <IRremote.hpp> const uint8_t IR_SEND_PIN = 3; // на Uno отдан Timer2 — не занимайте его кнопкамиconst uint8_t BTN_CINEMA = 2;const uint8_t BTN_EVENING = 4;const uint8_t LIGHT_PIN = 7; // модуль реле света // Таблица кодов, снятая читалкой за вечер (адрес 0x00 у обеих):// колонка: power 67, VOL+ 21, VOL- 7// телевизор: power 67, CH+ 69, CH- 70bool lastCinema = HIGH;bool lastEvening = HIGH; void otpravit(uint16_t addr, uint16_t cmd, int repeats) { IrSender.sendNEC(addr, cmd, repeats); Serial.print("Tx: addr=0x"); Serial.print(addr, HEX); Serial.print(" cmd=0x"); Serial.print(cmd, HEX); Serial.print(" povtory="); Serial.println(repeats);} void setup() { Serial.begin(9600); pinMode(BTN_CINEMA, INPUT_PULLUP); pinMode(BTN_EVENING, INPUT_PULLUP); pinMode(LIGHT_PIN, OUTPUT); IrSender.begin(IR_SEND_PIN, ENABLE_LED_FEEDBACK);} void loop() { bool nowCinema = digitalRead(BTN_CINEMA); bool nowEvening = digitalRead(BTN_EVENING); if (lastCinema == HIGH && nowCinema == LOW) { digitalWrite(LIGHT_PIN, LOW); // свет гаснет первым otpravit(0x00, 67, 2); // колонка: power delay(300); // техника просыпается otpravit(0x00, 7, 10); // VOL- десятью повторами Serial.println("Scenarij: kino"); } if (lastEvening == HIGH && nowEvening == LOW) { digitalWrite(LIGHT_PIN, HIGH); otpravit(0x00, 21, 6); // VOL+ шестью повторами Serial.println("Scenarij: vecher"); } lastCinema = nowCinema; lastEvening = nowEvening; delay(20);}Одна кнопка — один сценарий
Сценарий — это последовательность вызовов sendNEC с паузами, и порядок здесь важнее кодов. Сначала питание, потом всё остальное: моя колонка в режиме сна глотала громкость, пока я не вставил паузу 300 мс после power — технике нужно время проснуться, и треть секунды ожидания решают больше, чем любые повторы. Громкость шагом в одну цепочку повторов из прошлого урока выглядит для колонки как зажатая кнопка родного пульта: sendNEC(0x00, 7, 10) длится около 1,2 с и опускает звук заметно, без десяти отдельных нажатий. И не забывайте обратную связь: пачка из трёх команд тянется полторы секунды, за которые человек успевает усомниться, что кнопка работает, — финальный пик зуммером или вспышка диода снимает это сомнение без слов.
Кнопки на плате веду фронтами, как в уроке про антидребезг: HIGH до нажатия, LOW в момент нажатия, одно нажатие — один сценарий. Свет в сценарии вожу реле-модулем из урока про 220 вольт: щелчок реле идёт до всех ИК-команд — свет гаснет мгновенно, техника дожимается за пару секунд.
Отдельная история — пин 3. Первую кнопку я повесил именно на него, потому что она была ближе: макетка работала, кнопка нажималась, а диод молчал, и я минут пятнадцать проверял резисторы. Оказалось, скетч стартует с IrSender.begin(3), передатчик забирает пин себе, и кнопка, подключённая туда же, живёт своей жизнью — INPUT_PULLUP на пине с занятым таймером ничего не читает. Теперь кнопки у меня на 2 и 4, а пин 3 объявлен резервом передатчика в комментарии над скетчем. Та же ловушка ждёт зуммер: tone() тоже сидит на Timer2 и без передатчика не уживается.
Геометрия решает больше, чем код. Диод с конусом 20–30 градусов из первого урока тройки светит узким лучом — направьте его туда, где сидит адресат, и чужая техника перестанет видеть ваши команды. Мой стенд стоит на полке за колонкой и светит в стену напротив: отражение добивает до приёмника колонки, а конус уже не достаёт до люстры. Техника с фирменными пультами имеет ненулевые адреса и молчит на чужие кадры сама — проблемы создают только клоны на нулевом адресе. И помните про средний ток: паузы в 300 мс между командами — это ещё и отдых кристалла, тот самый импульсный режим из первого урока.
| Шаг сценария кино | Команда | Пауза после шага |
|---|---|---|
| Свет гаснет | digitalWrite реле на пине 7 | мгновенно, до всех ИК-команд |
| Колонка включается | sendNEC(0x00, 67, 2) | 300 мс — техника просыпается |
| Громкость вниз | sendNEC(0x00, 7, 10) | цепочка повторов, около 1,2 с |
| Подтверждение | пик зуммером или вспышка светодиода | сразу, сценарий завершён |
Симулятор: сценарии кнопками платы
- 1. С чего разумнее всего начать сборку своего пульта?
- 2. Колонка глотает громкость сразу после команды power. Какое исправление сработает?
- 3. Люстра с пультом-клоном на адресе 0x00 реагирует на команды громкости, предназначенные колонке. Почему?
- 4. Что означает печать Tx: addr=0 cmd=7 в скетче-сценарии на живой плате?
- 5. Сколько разных адресов различает 8-битное адресное поле NEC?
- Таблица кодов — пары адрес-команда из читалки: три пульта моей техники ужались в восемь строк комментария
- Сценарий — последовательность sendNEC с паузами: питание первым, 300 мс на пробуждение, громкость повторами
- На Uno пин 3 отдан несущей Timer2: кнопки и реле вешайте на другие пины
- Узкий диод и направление луча — фильтр против клонов на адресе 0x00: люстра перестала мигать от громкости
- Одна кнопка — один сценарий: свет, колонка и ТВ подчиняются плате вместо трёх пультов на столике
Три пульта ушли в ящик, а на столе осталась плата с двумя кнопками — по-моему, честная плата за вечер с читалкой и диодом за десять рублей. Самое ценное в конструкции — масштабирование: третий сценарий — это ещё одна ветка if и две-три строки вызовов, четвёртый — ещё одна кнопка на свободном пине. Дальше раздел можно развивать двумя путями: копировать пульты, которых библиотека не знает, через RAW-дампы в уроке про RC5, Sony и RAW, или навести порядок в самих сценариях — конечные автоматы из базового раздела отлично ведут многошаговые последовательности, и теперь им есть что слать в эфир. А когда захочется привязать сценарии не к кнопкам, а ко времени суток — пригодятся часы реального времени из урока про DS3231 и шину I2C: сценарий вечер будет запускаться сам в девять вечера, без единого нажатия.
Частые вопросы по теме урока
- С чего разумнее всего начать сборку своего пульта?
- Таблица кодов — фундамент всего пульта. Читалка печатает пары адрес-команда за вечер; вслепую перебирать команды долго, а разборка пульта нужна только в самых экзотических случаях. Снять адрес и команду каждой кнопки читалкой, как в уроке про приём кодов
- Колонка глотает громкость сразу после команды power. Какое исправление сработает?
- Техника в режиме сна не готова принимать команды — это проблема тайминга, а не силы сигнала. Пауза после питания решает то, что не решают ни повторы, ни ток. Вставить паузу около 300 мс после power: технике нужно время проснуться
- Люстра с пультом-клоном на адресе 0x00 реагирует на команды громкости, предназначенные колонке. Почему?
- Клоны из наборов почти все живут на нулевом адресе, и техника-адресат не проверяет адрес всерьёз. Лечится геометрией: узкий конус диода и правильное направление луча. У дешёвых клонов одинаковый адрес 0x00, и фильтра по адресу у люстры нет
- Что означает печать Tx: addr=0 cmd=7 в скетче-сценарии на живой плате?
- Печать Tx — это момент отправки, а не подтверждение приёма: ИК-канал слепой в обратную сторону. Убедиться, что команда дошла, может только сама техника — глазами и ушами. Что скетч отправил команду 7 на адрес 0 через ИК-диод
- Сколько разных адресов различает 8-битное адресное поле NEC?
- Восемь бит дают 256 значений. У большинства пультов из наборов адрес один — ноль, поэтому вся маршрутизация внутри семейства техники держится на фирменных ненулевых адресах. 256