База знаний · Датчики и модули

ИК-пульт и приёмник: управление Arduino с дивана

Любой пульт от телевизора плюс приёмник за 200 рублей: как узнать коды кнопок, включить что-нибудь с пульта и почему tone() глушит приём.

Любой пульт от телевизора, кондиционера или приставки — готовое беспроводное управление для Arduino. Нужен только приёмник за двести рублей и одна библиотека. Пульт шлёт вспышки невидимого инфракрасного света, приёмник превращает их в цифры, а скетч решает, что делать: включить свет, повернуть робота, переключить трек.

Приёмник: три ножки и 38 кГц

Пульт мигает светодиодом не просто так, а с несущей частотой — чаще всего 38 кГц. Приёмник вроде VS1838B или TSOP4838 настроен на неё: он отсекает солнце и лампы, а на вспышки пульта отвечает нулями и единицами на выводе OUT. Отдельный «голый» приёмник стоит несколько десятков рублей, в Trema-модуле тот же VS1838B уже распаян с конденсатором и шлейфом — 194 ₽. Пульт в комплект не входит: подойдёт любой домашний или 21-кнопочный из наборов.

UNO / NANOлюбая классика 5 ВVS1838B / TSOP4838линзой к вамOUT · GND · VCC2OUTсигнал: любой цифровой выводGNDGNDобщий провод5VVCCпитание 2,7–5,5 В
Три ножки, линзой к себе, слева направо: OUT, GND, VCC. Перепутать питание с землёй — самая частая ошибка: приёмник греется и молчит. У Trema-модуля с готовым шлейфом путать нечего; сигнальный провод подключайте к выводу 2, как в скетчах ниже.

Библиотека IRremote и её новый вид

Стандарт — библиотека IRremote, в каталоге сейчас версия 4.7.1. В 2021 году она сменила кожу: вместо IRrecv irrecv(2) и decode_results из старых уроков теперь один готовый объект IrReceiver, подключается она строкой #include <IRremote.hpp>, а результат лежит в IrReceiver.decodedIRData уже разобранным на протокол, адрес и команду. Старые скетчи библиотека 4.x ещё собирает, но коды в них выглядят иначе: одно 32-битное число вместо адреса и команды, а удержание кнопки даёт FFFFFFFF. Если переписываете урок десятилетней давности, проще перейти на новый вид — он короче.

Шаг 1. Узнать коды своих кнопок

Первый скетч ничего не делает, только печатает, что пришло. На Uno он занимает 8 970 байт.

#include <IRremote.hpp>  // IRremote 4.x подключается именно так, с .hpp

const byte IR_PIN = 2;   // выход приёмника OUT

void setup() {
  Serial.begin(9600);
  IrReceiver.begin(IR_PIN, ENABLE_LED_FEEDBACK);  // светодиод платы мигнёт на каждый сигнал
  Serial.println("Нажимайте кнопки пульта");
}

void loop() {
  if (IrReceiver.decode()) {
    if (IrReceiver.decodedIRData.flags & IRDATA_FLAGS_IS_REPEAT) {
      Serial.println("(кнопка удерживается)");
    } else {
      Serial.print("Протокол: ");
      Serial.print(getProtocolString(IrReceiver.decodedIRData.protocol));
      Serial.print("  адрес: 0x");
      Serial.print(IrReceiver.decodedIRData.address, HEX);
      Serial.print("  команда: 0x");
      Serial.println(IrReceiver.decodedIRData.command, HEX);
    }
    IrReceiver.resume();  // готовы принимать следующую посылку
  }
}

Откройте монитор порта на 9600 и понажимайте кнопки. Для пульта из набора вы увидите что-то вроде Протокол: NEC адрес: 0x0 команда: 0xC — это кнопка «1». Команда и есть номер кнопки, её и запоминаем. Адрес — номер «устройства», у всех кнопок одного пульта он одинаковый; он пригодится, если в комнате два пульта с одинаковыми командами.

Пока держите кнопку, пульт NEC не повторяет код, а шлёт короткий сигнал «всё ещё нажато» — библиотека отмечает его флагом IRDATA_FLAGS_IS_REPEAT, и скетч пишет «кнопка удерживается». Это важно для шага 2: если не отсеивать повторы, одно долгое нажатие переключит свет десять раз.

Шаг 2. Включить что-нибудь с пульта

Впишите коды двух кнопок и получите выключатель. Коды в скетче — от чёрного 21-кнопочного пульта «Car MP3», который кладут в большинство наборов: кнопка «1» — 0x0C, «2» — 0x18. Скетч занимает 7 262 байта.

#include <IRremote.hpp>

const byte IR_PIN = 2;
const byte LED = LED_BUILTIN;

// Коды кнопок узнайте первым скетчем и впишите свои.
const uint16_t CMD_ON = 0x0C;   // у 21-кнопочного пульта из наборов это кнопка «1»
const uint16_t CMD_OFF = 0x18;  // кнопка «2»

void setup() {
  pinMode(LED, OUTPUT);
  IrReceiver.begin(IR_PIN);  // без подмигивания: светодиод платы занят нами
}

void loop() {
  if (IrReceiver.decode()) {
    // Удержание кнопки шлёт повторы — на них не реагируем.
    if (!(IrReceiver.decodedIRData.flags & IRDATA_FLAGS_IS_REPEAT)) {
      uint16_t cmd = IrReceiver.decodedIRData.command;
      if (cmd == CMD_ON) {
        digitalWrite(LED, HIGH);
      } else if (cmd == CMD_OFF) {
        digitalWrite(LED, LOW);
      }
    }
    IrReceiver.resume();
  }
}

Остальные кнопки этого пульта, чтобы не снимать каждый раз (протокол NEC, адрес 0x0):

КнопкаКомандаКнопкаКомандаКнопкаКоманда
CH−0x45CH0x46CH+0x47
|◀◀0x44▶▶|0x40▶||0x43
−0x07+0x15EQ0x09
00x16100+0x19200+0x0D
10x0C20x1830x5E
40x0850x1C60x5A
70x4280x5290x4A

Осторожно: у второго ходового пульта — белого, с кнопками POWER, VOL+ и FUNC/STOP — те же числа сидят на других кнопках: 0x40 там «воспроизведение», 0x43 — «вперёд», 0x15 — «тише». Поэтому первый скетч всё равно нужен: пять минут с монитором порта избавят от загадок.

Вместо светодиода на этом же месте может стоять реле, сервопривод или мотор — меняется только то, что делается в ветках if. Дальше по той же схеме собирается MP3-плеер с пультом — он разобран в статье про DFPlayer Mini.

NEC, Sony, RC5: какой пульт у вас

Разных способов кодировать кнопки десятки, IRremote знает основные: NEC (почти все китайские пульты и большинство телевизоров), Sony, Samsung, LG, Panasonic, JVC, RC5 и RC6 (Philips). Вам это знать не обязательно: первый скетч печатает протокол сам, а сравнивать вы всё равно будете команду. Если протокол показан как UNKNOWN — библиотека такого не знает: так бывает с кондиционерами, у которых посылки длинные и не помещаются в буфер, и с рваным сигналом издалека. Управлять всё равно можно: вместо команды сравнивайте decodedIRData.decodedRawData — для неизвестного протокола там лежит хэш посылки, у каждой кнопки свой.

Что ломается

  • tone() глушит приёмник. На Uno и Nano IRremote живёт на том же таймере 2, что и tone(): после первого же писка приём останавливается. Делайте, как в примере библиотеки: IrReceiver.stopTimer(), затем tone(), подождите, пока звук отзвучит, и только потом IrReceiver.restartTimer(). По той же причине не пользуйтесь analogWrite() на выводах 3 и 11, пока принимаете сигнал.
  • Одно нажатие — десять срабатываний. Кнопку подержали чуть дольше, и пришла серия повторов с тем же кодом. Проверяйте флаг повтора, как во втором скетче.
  • Солнце и лампы. Приёмник у окна или под лампой дневного света ловит помехи и выдаёт случайные протоколы. Уберите его в тень или прикройте трубочкой из чёрной изоленты.
  • Ножки наоборот. VCC и GND перепутаны — приёмник греется и молчит. Линзой к себе: OUT, GND, VCC.
  • Два пульта — одна команда. Кнопка «1» на пульте телевизора и на пульте из набора может давать одинаковую команду. Сравнивайте ещё и адрес: decodedIRData.address.

А отправить сигнал?

IRremote умеет и передавать: ИК-светодиод через резистор 100–220 Ом на любой вывод, и IrSender.sendNEC(адрес, команда, повторы) заменит кнопку на телевизоре. Так делают «умные пульты» для кондиционера. Коды для них берут тем же первым скетчем с родного пульта. Отдельно для этого есть и модуль приёмник-передатчик по I²C, который разгружает плату от таймеров.

Частые вопросы

Как узнать коды кнопок своего пульта?

Загрузите скетч из статьи с IrReceiver.printIRResultShort или с выводом адреса и команды, откройте монитор порта на 9600 и нажимайте кнопки: для каждой напечатаются протокол, адрес и команда. Команда — это и есть код кнопки, его вписывают в скетч.

Почему IRremote не собирается: decode_results не объявлен?

Вы взяли скетч под старую IRremote 2.x, а в каталоге стоит 4.x. Подключайте библиотеку строкой #include <IRremote.hpp>, вместо IRrecv и decode_results используйте готовый объект IrReceiver, а результат берите из IrReceiver.decodedIRData.command. Старые примеры библиотека 4.x ещё собирает с заголовком IRremote.h, но коды в них выглядят иначе.

Почему приёмник выдаёт FFFFFFFF или ноль при удержании кнопки?

Пульты NEC при удержании не повторяют код, а шлют короткий сигнал «всё ещё нажато». В IRremote 4.x он помечается флагом IRDATA_FLAGS_IS_REPEAT, в старой 2.x показывался как 0xFFFFFFFF. В скетче такие посылки просто пропускают, иначе одно долгое нажатие сработает много раз.

Как подключить ИК-приёмник VS1838B?

Три ножки, линзой к себе, слева направо: OUT, GND, VCC. OUT — на любой цифровой вывод (в статье — 2), GND — на землю, VCC — на 5V или 3.3V: приёмник работает от 2,7 до 5,5 В. Перепутанные VCC и GND — самая частая причина, почему приёмник греется и молчит.

Почему после tone() пульт перестаёт работать?

На Uno и Nano IRremote и tone() делят один аппаратный таймер — второй. После звука приём останавливается. Вызовите IrReceiver.restartTimer() после tone() или переложите звук на другую библиотеку. По той же причине не используйте analogWrite() на выводах 3 и 11, пока принимаете сигнал.

Можно ли с Arduino управлять телевизором или кондиционером?

Да: ИК-светодиод через резистор 100–220 Ом на любой вывод и IrSender.sendNEC(адрес, команда, повторы) из той же IRremote. Коды снимают с родного пульта первым скетчем статьи. Дальность у одного светодиода небольшая, два-три метра.

Обновлено: 22 октября 2026