Интернет. Безопасность. Программы. Полезные советы

Ардуино инфракрасный пульт и приемник. Чтение данных с любого пульта, реагируем на удержание кнопок

  • Tutorial

Устройства с управлением от инфракрасного пульта тесно вошли в нашу жизнь. Иногда пульт от телевизора или древней аудиосистемы теряется, а купить новый за давностью лет уже невозможно. Заказать новый пульт не всегда возможно, изготовить клон тоже, но обладая донором или информацией о нём можно изготовить конвертер. Такой транскодер будет принимать команды одного пульта и транслировать их в формат другого.

Для Arduino существует прекрасная библиотека IRemote которая делает построение разнообразных ИК систем управления очень простым. Но при решении даже такой простой задачи как транскодер обязательно находятся проблемы которые интересно решать.
Итак для начала нам необходим интегральный ИК приёмник типа TSOP312 или соответствующий шилд для Arduino. Не стоит забывать что ИК приёмников существует очень много и цоколёвка у них меняется случайным образом. Например я использовал некий безымянный элемент по цоколёвке совпадающий с TSOP382 но в уменьшенном корпусе и без разделительного ключа.

Собранная схема нужна нам для получения кодов команд от обеих пультов, к несчастью снять команды с устройства для которого пульт утерян несколько сложнее. Вы можете всё-таки найти пульт донор, воспользоваться универсальным пультом подобрав код (а зачем тогда вам тогда транскодер, раз уж пульт подошёл?) или попытавшись воспользоваться данными из интернет баз по IR кодам. Самым простым для меня оказалось воспользоваться приложением под андроид, эмулирующий нужный мне пульт.
Для чтения данных используем пример IRrecvDumpV2 из поставки IRremote, если ваш пульт относится к распознаваемым библиотекой то сырой результат сканирования вам не понадобится, хотя например пульт от LG у меня ложно распознавался как Samsung и не заработал при попытке отправлять команды через sendLG.

Пример полученных данных под спойлером:

Encoding: SAMSUNG
Code: 34346897 (32 bits)
Timing:
+4450, -4350 + 600, - 500 + 600, - 500 + 600, -1600

+ 600, - 500 + 600, - 500 + 600, - 500 + 600, -1600
+ 600, -1600 + 600, - 500 + 600, -1600 + 600, - 500
+ 600, - 500 + 600, - 500 + 600, -1600 + 600, -1600
+ 600, - 500 + 600, -1600 + 600, - 500 + 600, - 500
+ 600, - 500 + 550, -1650 + 550, - 550 + 550, - 550
+ 550, -1650 + 550, - 550 + 550, -1650 + 550, -1600
+ 600, -1600 + 600
unsigned int rawData = {4450,4350, 600,500, 600,500, 600,1600, 600,1600, 600,500, 600,1600, 600,500, 600,500, 600,500, 600,500, 600,1600, 600,1600, 600,500, 600,1600, 600,500, 600,500, 600,500, 600,1600, 600,1600, 600,500, 600,1600, 600,500, 600,500, 600,500, 550,1650, 550,550, 550,550, 550,1650, 550,550, 550,1650, 550,1600, 600,1600, 600}; // SAMSUNG 34346897
unsigned int data = 0x34346897;


В случае если захват выдаёт сообщение “IR code too long. Edit IRremoteInt.h and increase RAWLEN” библиотеку придётся немного исправить - увеличив размер буфера для команд. Для пульта которым планируется управлять достаточно знать 32 битный код команды, стоит обратить внимание что на некоторых пультах код зажатой клавиши отличается от той же кнопки в режиме нажал и отпустил. Такие кнопки потребуют двух значений. Сводим полученные коды в удобную для вас таблицу. В ту же таблицу сохраняем коды для пульта донора в сыром виде.
Подключаем к Arduino инфракрасный светодиод и пишем простейшую программу которая получает инфракрасный сигнал с заданным кодом и отправляет другой код через светодиод. Резистор на 82 выбран из соображений того что валялось под рукой. Для встраиваемого устройства его можно смело увеличивать до 200 Ом а если передатчик должен быть дальнобойным то придётся дополнить его нехитрым транзисторным каскадом, иначе тока от Arduino обязательно не хватит.


При наличии кодов команд от обеих пультов код транскодера приобретает следующий вид

Void loop() { if (irrecv.decode(&results)) { switch(results.value){ case(0x845E5420):{ irsend.sendRaw(irSignal, sizeof(irSignal) / sizeof(irSignal), khz); }break; } } irrecv.resume(); irrecv.enableIRIn(); }
Запускаем скетч, заливаем в Arduino. Как ни странно после запуска одна команда проходит, после чего все последующие устройством игнорируются. Чтобы не связываться с отладкой добавляем в цикл мигалку на 13 пине и видим что после первой попытки отправить команду плата зависает. Что же, значит не всё так гладко в одновременном использовании передачи и приёма ИК сигнала в одном проекте. Немного покопавшись в используемых таймерах выясняется что так как и отправка и приём использует общий таймер то после начала отправки код должен подождать пока отправка не закончится. Можно эмпирически добавить задержку в пол секунды (delay(500))и всё будет работать, но зная что сырые данные у нас представляют собой отсчёты времени в миллисекундах то можно просто добавить функцию отправки с задержкой. В модуле Irsend есть даже подходящая функция custom_delay_usec, которой я изначально воспользовался неправильно, забыв домножить величину задержки на множитель USECPERTICK из библиотеки (50 мс).

Void sendDelayed(unsigned int array){ irsend.sendRaw(array, sizeof(array) / sizeof(array), khz); int array_size = sizeof(array) / sizeof(array); for(int i=0;i Такой код отлично работает, в switch теперь достаточно вписать нужное число case для кнопок и всё будет работать. Но не тут то было. Коды rawData записываются в виде массива int а у нас платформа на микроконтроллере. Память для переменных будет съедена уже пятью командами длиной по 100 элементов. А ведь на пультах бывает и по 25 кнопок.
Проблемы нет если не пользоваться сырым представлением данных, для этого в библиотеке есть возможность слать команды известными протоколами, например для пультов совместимых с Sony это sendSony. В библиотеке уже реализованы пульты известных производителей, но с ходу разобраться с моим пультом у меня не получилось. Поэтому переходим к более примитивным способам экономии памяти которые помогут тем у кого пульты совсем уж нестандартные.
Первое что приходит в голову это задавать rawData не в виде int, а перейти на байт. Все значения в этом массиве это результат чтения ИК сигнала таймером с периодом 50 миллисекунд, а так как эти данные кратны 50, то разделив их на 50 мы ничего не потеряем. Верхний предел будет ограничен значением 50*255=12750, а это 12 секунд, чего будет достаточно даже для декодирования неспешной азбуки Морзе - если такая необходимость возникнет.
В библиотеку был добавлен метод принимающий на вход байты, что сократило потребления памяти вдвое

IRsend::sendRaw (byte buf, unsigned int len, unsigned int hz)
Только вот памяти под переменные у Arduino всего два килобайта а это максимом 40 команд по 50 байтов. Нам необходимо больше памяти. И эту память мы извлечём из сегмента команд. Достаточно зарезервировать один массив достаточного размера и набивать его перед отправкой чередой присваиваний. Итого из кодового сегмента на одну команду будет тратиться около 100 байт, но ведь и места для кода у нас не меньше десяти килобайт. Так что на средний пульт со ста кнопками нам уже хватит.
Дабы не набивать руками присваивания в библиотеку был добавлен пример IRrecvDumpRawByte который выводит сырые данные не только в форме байтов но и в виде блока присваиваний

Пример под спойлером

rawData=87;rawData=87;rawData=10;rawData=9;rawData=10;rawData=9;rawData=10;rawData=10;rawData=10;rawData=9;rawData=10;rawData=9;rawData=10;rawData=29;rawData=10;rawData=9;rawData=10;rawData=9;rawData=10;rawData=10;rawData=10;rawData=9;rawData=10;rawData=9;rawData=10;rawData=10;rawData=10;rawData=9;rawData=10;rawData=9;rawData=10;rawData=10;rawData=10;rawData=9;rawData=10;rawData=86;rawData=10;rawData=9;rawData=11;rawData=9;rawData=10;rawData=9;rawData=10;rawData=9;rawData=10;rawData=28;rawData=10;rawData=29;rawData=10;rawData=28;rawData=10;rawData=9;rawData=10;rawData=28;rawData=10;rawData=10;rawData=10;rawData=9;rawData=10;rawData=28;rawData=10;rawData=10;rawData=10;rawData=9;rawData=10;rawData=9;rawData=10;rawData=28;rawData=10;rawData=9;rawData=11;rawData=27;rawData=10;rawData=29;rawData=10;rawData=9;rawData=10;


Пример уже написанного скетча который позволяет управлять Samsung DVD HR-755 при помощи пульта Daewoo R40A01 находится в примерах под именем DaewooR40A01toDVDHR755Transcoder. Pull request на добавление примеров в общую ветку пока никто не принял поэтому скачать модифицированную библиотеку можно с форка .

Много фото с переделанным рекордером





















Под катом находятся фотографии интеграции Arduino Nano внутрь этого DVD рекордера, Arduino Mini конечно занимает ощутимо меньше места, но под рукой была только Nano. Питание я взял с панели управления. Сигнал со встроенного приёмника был подключен к Arduino а параллельно ему был напаян ещё один ИК приёмник, расположенный с противоположной стороны от первого. Тем же навесным монтажом на него был напаян ИК светодиод. В принципе этого повторения можно было бы избежать - но сигнал с ИК приёмника инвертирован - поэтому напрямую завести ТТЛ сигнал на устройство не получится - а городить инвертор на логике или транзисторе я уже не стал.

Несмотря на то, что в моём случае сырые данные отлично работали, эксперименты с остальным домашним оборудованием показали что далеко не все захваченные сигналы корректно работали при попытке управления конкретным устройством. Команда включения кондиционера так и не заработала, хотя если он был уже включён смена режимов работала корректно. Колонка от LG тоже отказалась воспринимать сырые команды, но отлично реагировала на отправку кодов через sendSamsung. При этом пять собранных по знакомых телевизора отлично реагировали на сырые данные. Вариант с разной частотой сигнала я опробовал - это никак не помогло. Возможно проблема лежит в частоте дискретизации сигнала в 50 мс. Судя по работоспособности команд формата Samsung на технике LG, протокол стоит формализовать в виде отдельного модуль по аналогии с ir_LG.cpp ir_JVC.cpp ir_Dish.cpp, подобрав для конкретного устройства заголовок и параметры кодирования нулей и единиц. Наверное разбор написания такого протокола послужит неплохой темой для статьи.

Ну и в дополнение, вторая большая ИК библиотека для Arduino это

У каждого дома есть пульт от телевизора, или другой пульт дистанционного управления(ДУ). Данное устройство позволяет на расстоянии управлять каким-либо устройством, что является очень удобным. Не надо тратить драгоценные калории и делать лишние движения. Если у вас есть какое-то устройство и вы хотели бы управлять им на расстоянии, тогда можно сделать дистанционное управление данным устройством. При желании можно сделать и пульт ДУ своими руками, но для этого нет необходимости и это другая история. Зачем может понадобиться дистанционное управление?! - все просто:

Лень - это качество, заставляющее прилагать огромные усилия к тому, чтобы снизить общие затраты энергии.

Впервые дистанционное управление в действии миру показал изобретатель Никола Тесла, в 1898 году на выставке в Медисон-сквер-гарден он представил лодку с радиоуправлением под названием «телеавтомат». На сегодняшний день эта технология получила широчайшее распространение, только добавилось разные способы передачи команд(канал связи).

Из основных каналов связи можно выделить:

  • Радиоканал
  • Ультразвуковой
  • Инфракрасный

В данной статье мы будем говорить об управлении устройством инфракрасным пультом ДУ. Инфракрасное излучение - электромагнитное излучение, занимающее спектральную область между красным концом видимого света и микроволновым излучением. Инфракрасное излучение не видно человеческому глазу, но его можно увидеть с помощи фотокамеры или видеокамеры. Зачастую именно так проверяют работоспособность пульта от телевизора в домашних условиях.

Как то давно на старой работе взял пульт и "глазок"(ИК приемник) от списываемой охранной системы, он долго валялся без дела и наконец я добрался его проверить в работе.

Разобрав данный приемник Я увидел кое-какую хитрость, в данном "глазке" было спаяно вместе 4 ик приемника. Сделано это для того чтобы принимать ик волны с четырех сторон. И это удобно, не нужно ограничивать себя определенным углом приема.

Я так же набросал похожую схему с четырьмя приемниками, вдруг понадобиться. Ик приемники я использовал TSOP1836, но можно брать другие. Что бы обеспечить прием 360 градусов нужно выбрать соответственные ик приемники(с широким углом приема) и расположить максимально близко их между собой. С моим приемников проблем с приемом я не заметил. Так же забросил во вложение печатную плату и расположение элементов.

Для обработки команд я естественно буду использовать arduino uno, в качестве приемника ИК можно использовать
TSOP34836 (обладает высокой дальностью приема, но дороже) или TL1838 . Пульт можно взять любой ИК даже от телевизора. Ну если надо свой пульт то можно купить комплект для arduino .

Принцип работы:
При нажатии на кнопку пульта ду он посылает код кнопки в инфракрасном свете, после чего приемник принимает данный код кнопки и отправляет на исполнительное устройство, которое в зависимости от кнопки выполнит определенное действие.

Так же можно при помощи ИК волн можно передавать информацию на небольшое расстояние. Для передачи своих команд или информации можно использовать вторую arduino с ИК передатчиком. Но скорость такой передачи весьма небыстрая. К плюсам инфракрасного канала относится нечувствительность к электромагнитным помехам.

Для приема arduino ИК сигналов мы подключим ИК приемник следующим образом:

Обратите внимание что расположение ножек у приемника может отличаться.


Приемник имеет 3 ноги, «+» и «-» питания(в основном напряжение 3,3-5В) и нога данных именно она передает информацию на устройство(в нашем случае arduino). Напряжение питания для TSOP34836 является 2.7-5.5 вольт. Я буду использовать 5 вольт от стандартного выхода arduino.

Ну и естественно нужна прошивка для arduino. Алгоритм работы будет следующим: при нажатии на верхнюю кнопку пульта arduino включает реле, а при повторном нажатии выключает. С помощью этого реле можно запитать например подсветку, но не обязательно программировать нажатие кнопки на реле, можно выводить в компьютер команду или выполнить определенную операцию в arduino и т.д.
Для упрощения работы будем использовать готовую библиотеку . Код прошивки:

#include int RECEIVE_PIN = 11;//контакт приемника int RELAY_PIN = 3;//контакт реле IRrecv irrecv(RECEIVE_PIN);//присваиваем пин приемника decode_results results;//полученные данные

void setup() {
Serial.begin(9600);
irrecv.enableIRIn(); // включаем приемник
pinMode(RELAY_PIN, OUTPUT); // настраиваем реле на выход
digitalWrite(RELAY_PIN,HIGH); //устанавливаем высокое значение
}

void loop() {
if (irrecv.decode(&results)) {//если получены данные
Serial.print("0x");
Serial.println(results.value, HEX);//вывод полученного в терминал
if ((results.value == 0x8FF40BF) ||(results.value == 0xD72040BF)) digitalWrite(RELAY_PIN, !digitalRead(RELAY_PIN));//если код кнопки 0x8FF40BF или 0xD72040BF меняем состояние реле на противоположное
delay(200);// задержка от двойного срабатывания
irrecv.resume();// Получаем следующее значение
}
}

Немного поясню по скетчу:



if ((results.value == 0x8FF40BF) ||(results.value == 0xD72040BF))

Полученное значение сравнивается с "0x8FF40BF" и "0xD72040BF" - это коды кнопок в шестнадцатеричной системе исчисления. Два значения лишь потому что я использую два пульта с уникальными кодами.



digitalWrite(RELAY_PIN, !digitalRead(RELAY_PIN));

Стандартная процедура цифровой записи пина за исключением "!digitalRead(RELAY_PIN)". Знак "!" обозначает инверсию, в нашем случае инверсия состояния цифрового выхода "RELAY_PIN".



Serial.print("0x");
Serial.println(results.value, HEX);//вывод полученного в терминал

Данные строки выводят все полученные коды в терминал. В рабочей программе это без надобности, но это нужно что бы узнать нужный код той или иной кнопки. То есть сначала загружаем скетч в ардуино, заходим в терминал и нажав на кнопку получим нужный код.


Так же в библиотеке IRremote есть несколько разных примеров, что может оказаться полезным.


Во вложении к статье:


  • скетч для arduino

  • печатная плата для 4 датчиков

  • Входное напряжение: 4,0 ... 5,5 В (номинально 5 В)
  • Потребляемый ток: до 100 мА в импульсном режиме (при Vсс = 5 В)
  • Длинна световой волны: 940 нм (пиковое значение)
  • Максимальная частота сигнала: до 10 МГц
  • Расстояние передачи: до 10 м (при Vcc = 5 В)
  • Рабочая температура: -25 … 85 °C
  • Угол направленности: 120° (с потерей мощности < 50%)

Все модули линейки "Trema" выполнены в одном формате

Подключение:

Модуль удобно подключать 3 способами, в зависимости от ситуации:

Способ - 1: Используя проводной шлейф и Piranha UNO

Библиотека использует второй аппаратный таймер,

НЕ ВЫВОДИТЕ СИГНАЛЫ ШИМ НА 3 ИЛИ 11 ВЫВОД!

Подробнее про установку библиотеки читайте в нашей ..

Дополнительная информация по работе с модулем:

Пакеты: Практически все пульты отправляют не только информационный пакет (указывающий тип устройства и код нажатой кнопки), но и пакеты повтора, сообщающие устройству об удержании нажатой кнопки. Таким образом принимающее устройство может реагировать на нажатие кнопки однократно или в течении всего времени её удержания.
Например: нажимая и удерживая кнопку с номером телевизионного канала, телевизор переключится на данный канал только один раз. В то время, как нажимая и удерживая кнопку увеличения громкости, телевизор будет её увеличивать в течении всего времени удержания кнопки.

Количество информационных пакетов у большинства пультов равно одному, но некоторые устройства, например кондиционеры, используют 2, 3 и более информационных пакетов.

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

Длительность пауз между пакетами: обычно не превышает 200мс.

Протоколы передачи данных: определяют следующие, основные, параметры:

Несущая частота: у большинства пультов равна 38 кГц, именно на эту частоту настроен Trema ИК-приёмник .

Кодирование информации: это принцип передачи битов данных. Выделим три основных вида кодирования, при которых каждый бит передаётся последовательностью из одного импульса и одной паузы:

Сигналы Start, Stop и Toggle: по своему названию располагаются в начале, конце или середине пакета.

Stop: При кодировании длинной паузы, нельзя определить значение последнего бита в пакете, так как после пакета следует большая пауза, и последний бит будет всегда определяться как «1», поэтому в пакет добавляется сигнал Stop представляющий из себя импульс не несущий никакой информации.

Start: При бифазном кодировании требуется подать сигнал Start, так как невозможно начать передачу пакета с паузы.

Toggle: Это бит, который меняет своё значение при каждом новом нажатии на кнопку, используется в протоколах RS5, RS5X, RS6 (Philips), где пакеты повторов полностью повторяют данные информационного пакета. Таким образом принимающее устройство может отличить удержание кнопки от её повторного нажатия.

кодирование длиной импульсов - сначала передаётся импульс, длина которого зависит от значения передаваемого бита, затем следует пауза, длина которой не зависит от значения бита. Например: в протоколе SIRC (Sony), длина импульса для бита «1» = 1200мкс, а для бита «0» = 600мкс, длина пауз всегда равна 600мкс. Таким образом можно отличить «1» от «0» по длине импульса.

кодирование длиной пауз - сначала передаётся импульс, длина которого не зависит от значения передаваемого бита, затем следует пауза, длина которой зависит от значения бита. Например: в протоколе NEC, длина паузы для бита «1» = 1687,5мкс, а для бита «0» = 562,5мкс, длина импульсов всегда равна 562,5мкс. Таким образом можно отличить «1» от «0» по длине паузы.

бифазное кодирование - длина импульса равна длине паузы, а их последовательность определяет тип передаваемого бита. Например: в протоколе RS5 (Philips), для бита «1» импульс следует за паузой, а для бита «0» пауза следует за импульсом. Для протокола NRC (Nokia), наоборот, для бита «1» пауза следует за импульсом, а для бита «0» импульс следует за паузой.

Примеры:

Однократная передача данных:

#include // Подключаем библиотеку для работы с ИК-передатчиком iarduino_IR_TX VD(10); // Объявляем объект VD, с указанием вывода к которому подключён ИК-передатчик void setup(){ VD.begin(); // Инициируем работу с ИК-передатчиком VD.send(0x00FFA25D); // Однократно отправляем код 0x00FFA25D, без пакетов повторов } void loop(){} // Arduino отправит код 0x00FFA25D, сигнализируя о своём включении

Передача данных с пакетами повторов:

#include // Подключаем библиотеку для работы с ИК-передатчиком iarduino_IR_TX VD(2); // Объявляем объект VD, с указанием вывода к которому подключён ИК-передатчик void setup(){ pinMode(3,INPUT); // Конфигурируем 3 вывод, к которому подключена кнопка, как вход pinMode(4,INPUT); // Конфигурируем 4 вывод, к которому подключена кнопка, как вход pinMode(5,INPUT); // Конфигурируем 5 вывод, к которому подключена кнопка, как вход VD.begin(); // Инициируем работу с ИК-передатчиком } void loop(){ if(digitalRead(3)){VD.send(0x00FFA25D, true);} // Если нажата кнопка, подключённая к 3 выводу, то отправляем код 0x00FFA25D, а при её удержании, отправляем пакеты повторов, так как функция вызвана с параметром true if(digitalRead(4)){VD.send(0x00FF629D, true);} // Если нажата кнопка, подключённая к 4 выводу, то отправляем код 0x00FF629D, а при её удержании, отправляем пакеты повторов, так как функция вызвана с параметром true if(digitalRead(5)){VD.send(0x00FFE21D, true);} // Если нажата кнопка, подключённая к 5 выводу, то отправляем код 0x00FFE21D, а при её удержании, отправляем пакеты повторов, так как функция вызвана с параметром true }

Передача данных с указанием протокола:

#include // Подключаем библиотеку для работы с ИК-передатчиком iarduino_IR_TX VD(5); // Объявляем объект VD, с указанием вывода к которому подключён ИК-передатчик void setup() { VD.begin(); // Инициируем работу с ИК-передатчиком pinMode(6,INPUT); // Конфигурируем 6 вывод, к которому подключена кнопка, как вход pinMode(7,INPUT); // Конфигурируем 7 вывод, к которому подключена кнопка, как вход pinMode(8,INPUT); // Конфигурируем 8 вывод, к которому подключена кнопка, как вход VD.protocol("AeQQV~zK]Kp^KJp[@@@@@@@Bp"); // Указываем протокол передачи данных от пульта ELENBERG } // Получить строку протокола, можно нажав любую кнопку пульта телевизора // и вызвав одноименную функцию приёмника, без параметров void loop(){ if(digitalRead(4)){VD.send(0x417, true);} // отправляем сигнал ON/OFF (с пакетами повторов, пакеты повторяются через заданный в протоколе интервал времени) if(digitalRead(5)){VD.send(0x425, true);} // отправляем сигнал VOL- (с пакетами повторов, пакеты повторяются через заданный в протоколе интервал времени) if(digitalRead(6)){VD.send(0x427);} // отправляем сигнал VOL+ (без пакетов повторов, громкость будет увеличиваться быстрее, так как функция вызывается в цикле без интервалов) }

Данный пример показывает, как передатчик может полностью имитировать сигналы других ИК-пультов дистанционного управления.

Полученную строку протокола, нужно передать в качестве параметра функции protocol(), после чего можно отправлять коды кнопок функцией send(). В результате, устройства будут реагировать на ИК-передатчик , как на собственный ИК-пульт .

Описание основных функций библиотеки:

Подключение библиотеки:

#include // Подключаем библиотеку, для работы с ИК-передатчиком. iarduino_IR_TX VD(№_ВЫВОДА[,ИНВЕРСИЯ]); // Объявляем объект VD, с указанием номера вывода, к которому подключён ИК-передатчик. // Вторым параметром, типа bool, можно указать, что данные на передатчик требуется инвертировать.

Функция begin();

  • Назначение: инициализация работы с ИК-передатчиком
  • Синтаксис: begin();
  • Параметры: Нет.
  • Возвращаемые значения: Нет.
  • Примечание: Вызывается 1 раз в коде setup.
  • Пример:
VD.begin(); // Инициируем работу с ИК-передатчиком

Функция send();

  • Назначение: Передача данных.
  • Синтаксис: send(ДАННЫЕ [, УДЕРЖАНИЕ ]);
  • Параметры:
    • ДАННЫЕ - код, типа uint32_t, который требуется передать;
    • УДЕРЖАНИЕ - необязательный параметр, типа bool - указывающий что необходимо передавать не только код, но и пакеты повторов. Параметр имеет смысл, если функция вызывается пока удерживается кнопка.
  • Возвращаемые значения: Нет.
  • Примечание: Если функция вызвана без параметра УДЕРЖАНИЕ, или он равен false, то функция, при каждом её вызове, однократно передаст указанный код. Если функция вызвана с параметром УДЕРЖАНИЕ равным true, то функция подавляет дребезг кнопки и отправляет пакеты повторов (с указанным в протоколе интервалом) при её удержании.
  • Пример:
VD.send(0xCCDDEEFF); // Отправляем код 0xCCDDEEFF. Если функцию вызывать постоянно, в цикле, то она каждый раз будет отправлять этот код. VD.send(0xCCDDEEFF, true); // Отправляем код 0xCCDDEEFF. Если функцию вызывать постоянно, в цикле, то она отправит код только в первый раз, а далее будет отправлять пакеты повторов, в соответствии с указанным протоколом передачи данных.

Функция protocol();

  • Назначение: Установка протокола передачи данных.
  • Синтаксис: protocol(СТРОКА);
  • Параметры:
    • СТРОКА - состоящая из 25 символов протокола + символ конца строки. Данную строку можно получить вызвав одноимённую функцию, без параметров, для приёмника.
  • Возвращаемые значения: bool - строка содержит корректные данные о протоколе или нет.
  • Примечание: Функция устанавливает протокол передачи данных, таким образом ИК-передатчик может имитировать сигналы обычных пультов. После вызова данной функции, передачи данных функцией send() будут осуществляться по новому протоколу. Протокол передачи данных по умолчанию, соответствует пульту «Car mp3».
  • Пример:
VD.protocol("AeQQV~zK]Kp^KJp[@@@@@@@Bp"); // Указываем протокол передачи данных от пульта ELENBERG. // Теперь передатчик будет отправлять данные, кодируя их, в соответствии с указанным протоколом. // Получить строку протокола, можно нажав любую кнопку пульта телевизора и вызвав одноименную функцию для ИК-приёмника, без параметров.

Переменная frequency:

  • Значение: Устанавливает несущую частоту передачи данных в кГц;
  • Тип данных: uint8_t;
  • Примечание: Если переменной не присваивать значение, то передача ведётся на частоте указанной в протоколе. Если указать значение 0, то данные будут передаваться без модуляции.
VD.frequency=36; // Устанавливаем несущую частоту передачи данных в 36 кГц. VD.send(0xCCDDEEFF); // Отправляем данные с несущей частотой 36 кГц. VD.send(0xABCDEF); // Отправляем данные с несущей частотой 36 кГц. // Несущая частота будет изменена, если задать новое значение переменной frequency, или задать новый протокол передачи данных, через вызов функции protocol().

Применение:

  • управление роботами, движущимися, летающими и плавающими моделями, бытовой и специализированной техникой.
  • включение/выключение освещения, обогрева, вентиляции, полива и т.д.
  • открывание/закрывание дверей, жалюзи, мансардных окон, форточек и т.д.
  • Входное напряжение: 2,7 ... 5,5 В
  • Потребляемый ток: 0,65 … 1,05 мА (при Vсс = 5В) номинально 0,9 мА
  • Несущая частота: 38 кГц
  • Длинна световой волны: 850 … 1050 нм (пропускаемая фильтром более 80%)
  • Чувствительность: 0,17… 30000 мW/м2 (к мощности светового потока)
  • Расстояние приёма: до 45 м
  • Рабочая температура: -25 … 85 °C
  • Угол направленности: ±45°

Все модули линейки "Trema" выполнены в одном формате

Подключение:

Модуль подключается к любому цифровому выводу arduino. В комплекте имеется кабель для быстрого и удобного подключения к Trema Shield .

Модуль удобно подключать 3 способами, в зависимости от ситуации:

Способ - 1: Используя проводной шлейф и Piranha UNO


Библиотека использует второй аппаратный таймер,

НЕ ВЫВОДИТЕ СИГНАЛЫ ШИМ НА 3 ИЛИ 11 ВЫВОД!

Подробнее про установку библиотеки читайте в нашей ..

Дополнительная информация по работе с модулем:

Пакеты: Практически все пульты отправляют не только информационный пакет (указывающий тип устройства и код нажатой кнопки), но и пакеты повтора, сообщающие устройству об удержании нажатой кнопки. Таким образом принимающее устройство может реагировать на нажатие кнопки однократно или в течении всего времени её удержания.

Например: нажимая и удерживая кнопку с номером телевизионного канала, телевизор переключится на данный канал только один раз. В то время, как нажимая и удерживая кнопку увеличения громкости, телевизор будет её увеличивать в течении всего времени удержания кнопки.

Количество информационных пакетов у большинства пультов равно одному, но некоторые устройства, например кондиционеры, используют 2, 3 и более информационных пакетов.

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

Длительность пауз между пакетами: обычно не превышает 200мс.

Протоколы передачи данных: определяют следующие, основные, параметры:

  • несущую частоту;
  • способ кодирования информации, длительность импульсов и пауз передаваемых битов;
  • количество информационных пакетов:
  • состав информационного пакета и пакетов повторов;
  • длительность пауз между пакетами;
  • наличие и форму сигналов Start, Stop и Toggle;

Несущая частота: у большинства пультов равна 38 кГц, именно на эту частоту настроен Trema ИК-приёмник .

Кодирование информации: это принцип передачи битов данных. Выделим три основных вида кодирования, при которых каждый бит передаётся последовательностью из одного импульса и одной паузы:

  • кодирование длиной импульсов - сначала передаётся импульс, длина которого зависит от значения передаваемого бита, затем следует пауза, длина которой не зависит от значения бита. Например: в протоколе SIRC (Sony), длина импульса для бита «1» = 1200мкс, а для бита «0» = 600мкс, длина пауз всегда равна 600мкс. Таким образом можно отличить «1» от «0» по длине импульса.
  • кодирование длинной пауз - сначала передаётся импульс, длина которого не зависит от значения передаваемого бита, затем следует пауза, длина которой зависит от значения бита. Например: в протоколе NEC, длина паузы для бита «1» = 1687,5мкс, а для бита «0» = 562,5мкс, длина импульсов всегда равна 562,5мкс. Таким образом можно отличить «1» от «0» по длине паузы.
  • бифазное кодирование - длина импульса равна длине паузы, а их последовательность определяет тип передаваемого бита. Например: в протоколе RS5 (Philips), для бита «1» импульс следует за паузой, а для бита «0» пауза следует за импульсом. Для протокола NRC (Nokia), наоборот, для бита «1» пауза следует за импульсом, а для бита «0» импульс следует за паузой.

Сигналы Start, Stop и Toggle: по своему названию располагаются в начале, конце или середине пакета.

Stop: При кодировании длинной паузы, нельзя определить значение последнего бита в пакете, так как после пакета следует большая пауза, и последний бит будет всегда определяться как «1», поэтому в пакет добавляется сигнал Stop представляющий из себя импульс не несущий никакой информации.

Start: При бифазном кодировании требуется подать сигнал Start, так как невозможно начать передачу пакета с паузы.

Toggle: Это бит, который меняет своё значение при каждом новом нажатии на кнопку, используется в протоколах RS5, RS5X, RS6 (Philips), где пакеты повторов полностью повторяют данные информационного пакета. Таким образом принимающее устройство может отличить удержание кнопки от её повторного нажатия.

Примеры:

Проверка наличия данных поступивших с ИК-пульта , осуществляется функцией check(). Эта функция реагирует на нажатие кнопок ИК-пульта , но если её вызывать с параметром true , то она будет реагировать и на удержание кнопок.

Чтение данных с любого пульта, реагируем только на нажатие кнопок:

#include // Подключаем библиотеку для работы с ИК-приёмником iarduino_IR_RX IR(7); // Объявляем объект IR, с указанием вывода к которому подключён ИК-приёмник void setup(){ Serial.begin(9600); // Инициируем передачу данных в монитор последовательного порта, на скорости 9600 бит/сек IR.begin(); // Инициируем работу с ИК-приёмником } void loop(){ if(IR.check()){ // Если в буфере имеются данные, принятые с пульта (была нажата кнопка) Serial.println(IR.data, HEX); // Выводим код нажатой кнопки Serial.println(IR.length); // Выводим количество бит в коде } }

В данном скетче функция check() вызывается без аргументов, значит и реагирует она только на нажатия кнопок ИК-пульта .

Чтение данных с любого пульта, реагируем на удержание кнопок:

#include // Подключаем библиотеку для работы с ИК-приёмником iarduino_IR_RX IR(6); // Объявляем объект IR, с указанием вывода к которому подключён ИК-приёмник void setup(){ Serial.begin(9600); // Инициируем передачу данных в монитор последовательного порта, на скорости 9600 бит/сек IR.begin(); // Инициируем работу с ИК-приёмником } void loop(){ if(IR.check(true)){ // Если в буфере имеются данные, принятые с пульта (удерживается кнопка) Serial.println(IR.data, HEX); // Выводим код нажатой кнопки Serial.println(IR.length); // Выводим количество бит в коде } }

В данном скетче функция check() вызывается с параметром true , значит и реагирует она как на нажатия, так и на удержания кнопок ИК-пульта .

Чтение данных с любого пульта, с указанием как реагировать на какие кнопки.

#include // Подключаем библиотеку для работы с ИК-приёмником iarduino_IR_RX IR(6); // Объявляем объект IR, с указанием вывода к которому подключён ИК-приёмник // bool flgKey1 = false; uint32_t codKey1 = 0xFF30CF; // Определяем флаг нажатия и код кнопки 1 bool flgKey2 = false; uint32_t codKey2 = 0xFF18E7; // Определяем флаг нажатия и код кнопки 2 bool flgKey3 = false; uint32_t codKey3 = 0xFF7A85; // Определяем флаг нажатия и код кнопки 3 bool flgKey = false; uint32_t tmrKey = 0; // Определяем флаг разрещающий вывод данных в монитор и время последнего нажатия кнопки. // void setup(){ // Serial.begin(9600); // Инициируем передачу данных в монитор последовательного порта, на скорости 9600 бит/сек IR.begin(); // Инициируем работу с ИК-приёмником } // // void loop(){ // if(IR.check(true)){ // Если в буфере имеются данные, принятые с пульта (удерживается кнопка), то... if(millis()-200 > tmrKey){ // Если с последней поступившей команды прошло более 200 мс, то flgKey1=false; // Считаем что кнопка 1 не удерживается flgKey2=false; // Считаем что кнопка 2 не удерживается flgKey3=false; // Считаем что кнопка 3 не удерживается } tmrKey = millis(); flgKey=true; // Сохраняем время последней реакции на пульт и азрешаем вывод данных if(IR.data==codKey1){ if(flgKey1){flgKey=false;} flgKey1=true; }else{flgKey1=false;} // Запрещаем вывод данных кнопки 1 при её удержании if(IR.data==codKey2){ if(flgKey2){flgKey=false;} flgKey2=true; }else{flgKey2=false;} // Запрещаем вывод данных кнопки 2 при её удержании if(IR.data==codKey3){ if(flgKey3){flgKey=false;} flgKey3=true; }else{flgKey3=false;} // Запрещаем вывод данных кнопки 3 при её удержании if(flgKey){ // Если вывод данных разрешен, то... Serial.println(IR.data, HEX); // Выводим код нажатой кнопки Serial.println(IR.length); // Выводим количество бит в коде } // } // } //

В данном скетче функция check() вызывается с параметром true , значит она реагирует как на нажатия, так и на удержания кнопок ИК-пульта . Но вывод данных в монитор последовательного порта осуществляется только при установленном флаге flgKey , который сбрасывается при удержании кнопок с кодами 0xFF30CF , 0xFF18E7 и 0xFF7A85 . Получается что на 3 кнопки скетч реагирует только при нажатии, а на остальные кнопки, как на нажатие, так и на удержание.

Чтение данных только с тех пультов, которые работают по указанному протоколу:

#include // Подключаем библиотеку для работы с ИК-приёмником iarduino_IR_RX IR(5); // Объявляем объект IR, с указанием вывода к которому подключён ИК-приёмник void setup(){ Serial.begin(9600); // Инициируем передачу данных в монитор последовательного порта, на скорости 9600 бит/сек IR.begin(); // Инициируем работу с ИК-приёмником IR.protocol("Ae`` `|LJ` @@@@BPBp"); // Указываем протокол передачи данных, на который следует реагировать } void loop(){ if(IR.check(true)){ // Если в буфере имеются данные, принятые с пульта (удерживается кнопка) Serial.println(IR.data, HEX); // Выводим код нажатой кнопки Serial.println(IR.length); // Выводим количество бит в коде } }

В данном скетче, в коде setup(), указан протокол передачи данных, который редко совпадает у разных производителей ИК-пультов . Значит функция check() в коде loop() будет реагировать только на те ИК-пульты , которые поддерживают указанный протокол.

Получение протокола передачи данных и типа кодировки:

#include // Подключаем библиотеку для работы с ИК-приёмником iarduino_IR_RX IR(4); // Объявляем объект IR, с указанием вывода к которому подключён ИК-приёмник void setup(){ Serial.begin(9600); // Инициируем передачу данных в монитор последовательного порта, на скорости 9600 бит/сек IR.begin(); // Инициируем работу с ИК-приёмником } void loop(){ if(IR.check()){ // Если в буфере имеются данные, принятые с пульта (была нажата кнопка) Serial.println(IR.protocol()); // Выводим строку протокола передачи данных } }

В данном примере описано как получить протокол передачи данных ИК-пультов . В статье , описано, как передавать коды кнопок по указанному протоколу.

Таким образом, можно создать скетч ИК-передатчика для имитации сигналов различных ИК-пультов . В результате, устройства будут реагировать на ИК-передатчик , как на собственный ИК-пульт .

Описание основных функций библиотеки:

Подключение библиотеки:

#include // Подключаем библиотеку, для работы с ИК-приёмником. iarduino_IR_RX IR(№_ВЫВОДА [, ИНВЕРСИЯ]); // Объявляем объект IR, с указанием номера вывода, к которому подключён ИК-приёмник. // Вторым параметром, типа bool, можно указать, что данные с приёмника являются инверсными.

Функция begin();

  • Назначение: инициализация работы с ИК-приёмником
  • Синтаксис: begin();
  • Параметры: Нет.
  • Возвращаемые значения: Нет.
  • Примечание: Вызывается 1 раз в коде setup.
  • Пример:
IR.begin(); // Инициируем работу с ИК-приёмником

Функция check();

  • Назначение: Проверка наличия принятых с пульта данных.
  • Синтаксис: check([ УДЕРЖАНИЕ ]);
  • Параметры:
    • УДЕРЖАНИЕ - необязательный параметр, типа bool - указывающий что необходимо реагировать на удержание кнопок пульта.
  • Возвращаемые значения: bool - приняты или нет, данные с пульта.
  • Примечание: Если функция вызвана без параметра, или он равен false, то функция будет реагировать только на сигналы с пульта при нажатии его кнопок, а если указать true, то функция будет реагировать, как на нажатие, так и на удержание кнопок пульта.
  • Пример:
if(IR.check()){ ... ;} // Если приняты данные с пульта, при нажатии его кнопки if(IR.check(true)){ ... ;} // Если принимаются данные с пульта, при удержании кнопки

Функция protocol();

  • Назначение: Получение, установка или сброс протокола передачи данных.
  • Синтаксис: protocol([ ПАРАМЕТР ]);
  • Получение протокола: Если функция вызвана без параметра, то она вернёт строку из 25 символов + символ конца строки. Биты данной строки, несут информацию о типе протокола передачи данных пульта, данные которого были приняты последними. Данную строку можно использовать для установки протокола ИК-передатчику, или ИК-приёмнику (см.ниже).
  • Установка протокола: Если функция вызвана с параметром в виде строки из 25 символов протокола + символ конца строки, то после этого, функция chek(), будет реагировать только на пульты, соответствующие указанному протоколу передачи данных.
  • Сброс протокола: Если функция вызвана с параметром IR_CLEAN, то функция chek() опять станет реагировать на сигналы с любых пультов.
  • Получение параметров протокола: Если функция вызвана с параметром int, от 0 до 17, то она вернёт не строку протокола, а значение типа int с одним из параметров протокола передачи данных пульта, данные которого были приняты последними:
    • 0 - тип кодировки:
      • IR_UNDEFINED - тип кодировки не определён;
      • IR_PAUSE_LENGTH - кодирование длинной паузы;
      • IR_PULSE_LENGTH - кодирование длинной (шириной) импульса (ШИМ);
      • IR_BIPHASIC - бифазное кодирование;
      • IR_BIPHASIC_INV - бифазное кодирование с инверсными битами;
      • IR_NRC - пакеты повтора идентичны, а первый и последний пакеты специальные;
      • IR_RS5 - кодировка PHILIPS с битом toggle;
      • IR_RS5X - кодировка PHILIPS с битом toggle;
      • IR_RS6 - кодировка PHILIPS с битом toggle.
    • 1 - несущая частота передачи данных (в кГц);
    • 2 - заявленное количество информационных бит в 1 пакете;
    • 3 - заявленное количество информационных бит в пакете повтора;
    • 4 - длительность паузы между пакетами (в мс);
    • 5 - длительность импульса в стартовом бите (в мкс);
    • 6 - длительность паузы в стартовом бите (в мкс);
    • 7 - длительность импульса в стоповом бите (в мкс);
    • 8 - длительность паузы в стоповом бите (в мкс);
    • 9 - длительность импульса в бите рестарт или toggle (в мкс);
    • 10 - длительность паузы в бите рестарт или toggle (в мкс);
    • 11 - позиция бита рестарт или toggle в пакете (№ бита);
    • 12 - максимальная длительность импульса в информационных битах (в мкс);
    • 13 - минимальная длительность импульса в информационных битах (в мкс);
    • 14 - максимальная длительность паузы в информационных битах (в мкс);
    • 15 - минимальная длительность паузы в информационных битах (в мкс);
    • 16 - флаг наличия стартового бита (true/false);
    • 17 - флаг наличия стопового бита (true/false);
    • 18 - флаг наличия бита рестарт или toggle (true/false);
    • 19 - тип пакета повтора (0-нет, 1-с инверсными битами, 2-идентичен информационному, 3-уникален);
  • Возвращаемые значения: Зависят от наличия и типа параметра.
  • Примечание: Если ранее был установлен протокол, то попытка получения протокола, или параметров протокола, вернёт значения установленного ранее протокола, а не протокола передачи данных пульта, данные которого были приняты последними.
  • Пример:
IR.protocol("AeQQV~zK]Kp^KJp[@@@@@@@Bp"); // Устанавливаем протокол. Теперь приёмник будет получать данные, только от пультов телевизора ELENBERG. IR.protocol(IR_CLEAN); // Сбрасываем ранее установленный протокол. Теперь приёмник снова будет реагировать на любые пульты. if(IR.check()){ Serial.println(IR.protocol()); } // Получаем протокол. Как только приёмник получит данные, в мониторе высветится строка из 25 символов протокола. if(IR.check()){ Serial.println(IR.protokol(12)); } // Получаем один из параметров протокола. Как только приёмник получит данные, в мониторе отобразится максимальная длительность импульса информационного бита в микросекундах.

Переменная data

  • Значение: Возвращает код кнопки, принятый с пульта;
  • Тип данных: uint32_t.
if(IR.check()){ Serial.println(IR.data); } // Выводим код нажатой кнопки, если он принят

Переменная length

  • Значение: Возвращает размер кода кнопки, в битах;
  • Тип данных: uint8_t.
if(IR.check()){ Serial.println(IR.length); } // Выводим размер кода нажатой кнопки, если он принят

Переменная key_press

  • Значение: Возвращает флаг, указывающий на то, что кнопка пульта нажимается а не удерживается;
  • Тип данных: bool.
if(IR.check(true)){ if(IR.key_press){Serial.println("PRESS");} // Текст будет выведен 1 раз, когда кнопка нажимается else {Serial.println("HOLD ");} // Текст будет выводиться постоянно, пока кнопка удерживается }

Применение:

  • управление роботами, движущимися, летающими и плавающими моделями, бытовой и специализированной техникой.
  • включение/выключение освещения, обогрева, вентиляции, полива и т.д.
  • открывание/закрывание дверей, жалюзи, мансардных окон, форточек и т.д.

В сегодняшней статье будет рассматриваться подключение ИК приемника TSOP34836 к плате Aduino UNO. Для этих целей можно применить любой имеющийся у вас приемник, совместимый с вашим пультом по частоте. Назначение выводов показано на рисунке.

1. Vout – выход приемника.
2. GND – «земля», общий провод.
3. Vcc – питание.
Передача данных от ИК пульта к приемнику осуществляется по протоколу RC5, представляющий из себя последовательность импульсов. Подключение осуществляется по следующей схеме.

А собрав, получаем примерно следующее:

Для обработки данных, передаваемых пультом, используем библиотеку IRremote, данная библиотека прикреплена к статье. Вставляем следующий код:

#include "IRremote.h" IRrecv irrecv(11); // Указываем пин, к которому подключен приемник decode_results results; void setup() { Serial.begin(9600); // Выставляем скорость COM порта irrecv.enableIRIn(); // Запускаем прием } void loop() { if (irrecv.decode(&results)) // Если данные пришли { Serial.println(results.value, HEX); // Отправляем полученную данную в консоль irrecv.resume(); // Принимаем следующую команду } }

Теперь в консоле COM - порта можно наблюдать код нажимаемой клавиши в HEX.


Вот и все, теперь можно использовать эту схему в ваших устройствах. Ниже приведен пример одного из практических применений ИК - приемника.

В качестве демонстрации будет показано, как с помощью ИК-пульта управлять сервомашинкой.

Схема устройства:

Вот так оно должно выглядеть:

Для работы устройства используем следующий код:

#include "Servo.h" #include "IRremote.h" IRrecv irrecv(11); decode_results results; Servo servoMain; int servPoz = 90; //Начальное положение сервы int lastPoz = 0; void setup() { irrecv.enableIRIn(); servoMain.attach(10); // Servo присоединен к 10 выводу servoMain.write(servPoz); } void loop() { if (irrecv.decode(&results)) { int res = results.value; Serial.println(res, HEX); if(res==0xFFFF906F)// Если нажата кнопка "+" { lastPoz=res; servPoz++; servoMain.write(servPoz); } else if(res==0xFFFFA857)// Если нажата кнопка "-" { servPoz--; lastPoz=res; servoMain.write(servPoz); } else if(res==0xFFFFFFFF)// Если кнопку удерживают { if(lastPoz==0xFFFF906F) servPoz++;// Удерживают "+" if(lastPoz==0xFFFFA857) servPoz--;// Удерживают "-" servoMain.write(servPoz); } irrecv.resume(); delay(100); } }

Пульт используется какой-то китайский, при нажатии "+" серва вращается в одну сторону, при нажатии "-", в другую.