ИК пульт Arduino: устройство ДУ для управления многими девайсами

Окей, картинка слегка вводит в заблуждение, на этом ИК пульте Ардуино не «более 9000» кнопок, а ровно 400. И вы можете управлять 20 девайсами через инфракрасный (ИК) интерфейс, используя до 20 различный действий.

Что это?
Это универсальный пульт, основанный на плате Ардуино.

Зачем создавался этот проект?
Первое — я узнал больше про Ардуино.

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

Как он работает?

  • Поверните первую кнопку, чтобы выбрать устройство, которым нужно управлять.
  • Поверните вторую кнопку, чтобы выбрать действие, которое вы хотите произвести с устройством.
  • Долгое нажатие на кнопку (которая является не только крутилкой, но и кнопкой), «захватывает» ИК сигнал, отсылаемый другим пультом, который вы хотите клонировать
  • Или просто коротко нажмите на кнопку, чтобы отослать ИК сигнал
  • Конечно, пульт имеет ИК приёмник, который «захватывает» ИК сигнал от пультов, которые вы собираетесь «клонировать», и ИК светодиод, чтобы посылать сигналы. Данные сохраняются на карту MicroSD, так что вы можете выключить ваш пульт (и плату Ардуино), а она сохранить всю информацию о сигналах на карте MicroSD. Также на пульте есть два датчика угла поворота (крутилки), по 20 позиций на каждом, таким образом дающих 400 кнопок. Каждая крутилка является также и кнопкой. Еще есть светодиод, который сообщает о том, посылает или получает наш пульт ИК сигналы. Девайс работает на литий-ионной батарейке 18650, так что он портативный. И, наконец, есть выключатель, так что вы можете включить и выключить пульт.

Что вам будет нужно:

  • Плата Ардуино (для финального проекта я использовал Ардуино нано, так как она меньше по размеру)
  • Перемычки
  • 2 датчика угла поворота (я использовал KY-040)
  • 1 ИК приёмник (я использовал KY-022)
  • 1 кардридер MicroSD для Ардуино
  • 1 карта MicroSD
  • 1 ИК светодиод
  • 1 светодиод любого цвета
  • 1 батарейка 18650
  • 1 слот под батарейку 18650
  • 1 зарядник для литиевых батарей (TP4065)
  • 1 повышающий конвертер (с <5V до 5V)

В зависимости от того, где вы всё это купите, цена может сильно варьироваться.

Перед тем, как мы начнём:

В первых шагах нашей инструкции я объясню, как я использую каждый модуль Ардуино. Если вы уже мастер Ардуино, вы, возможно, захотите сразу перейти к заключительной части проекта на шаге 7. Если вы новичок в Ардуино, вы, скорее всего, захотите ознакомиться с первыми шагами:

  • Шаг 1: Как использовать светодиод?
  • Шаг 2: Как использовать кардридер MicroSD?
  • Шаг 3: Как использовать датчик угла поворота? (KY-040)
  • Шаг 4: Как использовать кнопки? (Зажатие и длинное\короткое нажатие)
  • Шаг 5: Как использовать ИК ресивер? (KY-022)
  • Шаг 6: Как отправлять ИК протоколы?

Затем идут интересные части проекта:

  • Шаг 7: Окончательная схема (с кабелем USB)
  • Шаг 8: Окончательная схема (портативная, с аккумулятором)
  • Шаг 9: Окончательная схема (с напечатанным на 3D принтере корпусом)

И, наконец, я не профессионал в платах Ардуино… Финальный проект работает отлично, но если вы найдёте ошибку в схеме или в коде, пожалуйста, дайте мне знать!

Шаг 1: Как использовать светодиод?

В финальный проект я добавил светодиод, чтобы быть уверенным, что код работает.

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

Здесь вам понадобится только диод и резистор, чтобы защитить диод. Если вы еще не прочитали статью, посмотрите короткое руководство по Ардуино. Я использовал практически такой же код.

int LED = 4;//LED is connected to pin 4
void setup() {
  // initialize digital pin LED as an output.
  pinMode (LED, OUTPUT);
}
void loop() {
  // put your main code here, to run repeatedly:
  digitalWrite(LED, HIGH );// turn the LED on (HIGH is the voltage level)
  delay(1000);// wait for a second
  digitalWrite(LED, LOW );// turn the LED off (LOW is the voltage level)
  delay(1000);// wait for a second
}
Файлы

Шаг 2: Как использовать кардридер MicroSD?

Чтобы начать работать с СД картой, вам понадобится библиотека для чтения\записи файлов с СД карт. Но, для большего удобства, я соединил пин CS с пином 10 на Ардуино (а не с пином 4, как показано в предыдущем руководстве),(пины 10, 11, 12 и 13 используются для СД карт. Это руководство помогло мне понять, как сохранять полученные с других пультов для «клонирования» данных. Но мне нужно было упростить задачу, поэтому я добавил две вещи:

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

Первое, что я сделал:

В финальном коде я захотел хранить всю информацию в отдельных «.txt» файлах (отдельный ИК протокол для каждой кнопки). И имена файлов зависели от позиции датчика угла поворота.

  • Пример 1: Датчик 1 на позиции 1 (для устройства №1, например телевизора), и датчик 2 на позиции 3 (соответствует позиции ВКЛ). Таким образом, я хочу, чтобы файл назывался «1_3.txt»
  • Пример 2: датчик 1 на позиции 1(телевизор), датчик 2 на позиции 4 (громкость вверх). Файл называется «1_4.txt»
  • Пример 3: Датчик 1 на позиции 2 (радио), датчик 2 на позиции 3 (включить). Файл называется «2_3.txt»

Чтобы осуществить задумку, я установил имя файла как «string» (строковая переменная) и добавил к «string» два «integer» (числовые переменные), которые соответствуют значениям на датчиках. Получилось вот так:

int value1 = 100;
String middle = "_";
int value2 = 101;
String ext = ".txt";
String SDname;
SDname = value1 + middle + value2 + ext;

Второе, что я сделал:

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

Так что сперва я попытался заменить текстовую информацию в файлах, используя функцию «SD.remove()». Всё работало прекрасно с небольшим кодом на СД карте. Но, к сожалению, не работало с финальным кодом и всеми модулями (в шаге 7). Я не знаю почему.

Так что, простейшей функцией, которую я нашел для замены «SD.remove()», была функция FileSeek, которая искала нужную позицию в файле. Таким образом, в моём коде я шёл на позицию 0 и добавлял нужный текст. В этом случае файл не перезаписывался, но первые строки заменялись и этого мне хватало. Вот интересующая нас строка:

myFile.seek(0);

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

  • Создать текстовый файл, имя которого соответствует числовым позициям датчиков (value1 и value2)
  • Записать три строки в этот файл
  • Закрыть файл, переоткрыть его и заменить три первых строки
  • Затем зациклить предыдущие шаги, увеличивая значения в именах следующих шагов.
Файлы

Шаг 3: Как использовать датчик угла поворота? (KY-040)

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

Крутилки очень важны в универсальном пульте, так как с их помощью можно добиться 400 разных комбинаций кнопок, так как на каждой из них есть по 20 разных позиций! И если вы добавите третий датчик, то можете получить 8000 кнопок! Или же два датчика с 40 позициями дадут вам 1600 кнопок! Но на мой взгляд, 400 кнопок — предостаточно, чтобы управлять всеми ИК девайсами, которые вы когда-либо видели.

Я сделал 2 основных изменения в коде, который шел с руководством:

  • Первое, в предыдущей ссылке, каждый шаг датчика был кратен 2. То есть 0, 2, 4, 6… Я умножил это значение на 0.5, чтобы получить шаг, кратный 1: 0, 1, 2, 3, 4…
  • Второе, я хотел, чтобы значение датчика находилось между 0 и 19 (20 позиций). В коде, который вы можете опробовать по предыдущей ссылке, значения, которые сохранялись в переменной счетчика «counter» продолжали увеличиваться даже после 19.

Пример: после однократного полного вращения датчика, значение «counter» равно 21. И оно продолжит увеличиваться дальше — 21, 22, 23. После двух полных вращений датчика, значение увеличится до 41. И так далее. То же самое и с отрицательными значениями счётчика, если мы будем крутить датчик против часовой стрелки. Я хотел, чтобы в моём коде значение счетчика обнулялось при каждом полном прохождении круга. Если вы будете вращать датчик по часовой стрелке, у вас получится: 0, 1, 2, 3, 4, 5 ,6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 0, 1, 2, 3, 4, 5 ,6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 0, 1, 2, 3, 4, 5 ,6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20… Чтобы исправить недочёт, я использовал деление с остатком на 40 (перед умножением на 0.5).

Как бы то ни было, всё легко делается следующим кодом:

val1 = (counter % 40) * 0.5;

Созданием числовой переменной «val1» я заменяю переменную «counter».

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

#define outputA 6 //CLK
#define outputB 7 //DT
int counter = 0;
int aState;
int aLastState;
int val1;
void setup() {
  pinMode (outputA, INPUT);
  pinMode (outputB, INPUT);
  Serial.begin (9600);
  // Reads the initial state of the outputA
  aLastState = digitalRead(outputA);
}
void loop() {
  aState = digitalRead(outputA); // Reads the "current" state of the outputA
  // If the previous and the current state of the outputA are different, that means a Pulse has occured
  if (aState != aLastState) {
    // If the outputB state is different to the outputA state, that means the encoder is rotating clockwise
    if (digitalRead(outputB) != aState) {
      counter ++;
    } else {
      counter --;
    }
    Serial.println(counter);
    val1 = (counter % 40) * 0.5;
    Serial.print("Position: ");
    Serial.println(val1);
  }
  aLastState = aState; // Updates the previous state of the outputA with the current state

Файлы

Шаг 4: Как использовать кнопки? (Зажатие и длинное\короткое нажатие)

В этом шаге я использовал такой же модуль, как и в предыдущем шаге, KY-040, потому что у него есть кнопка для нажатия.

В моём финальном пульте мне нужна была кнопка по двум главным причинам:

  • Длинное нажатие, чтобы начать «захват» сигнала моим универсальным пультом
  • Короткое нажатие для отправки сигнала

Чтобы осуществить задуманное, я использовал библиотеку bounce. И далее я сделал следующее.

Чтобы создать долгое нажатие:

Для долгого нажатия в коде был создан цикл «while», исполняющийся пока кнопка зажата. В цикле находится счётчик, который увеличивается с каждым проходом по циклу. И если счетчик переполняется, то выполняется нужный код. В следующем примере выводится сообщение «Long pressed»

while ( value == LOW ) {
	debouncer.update();
    value = debouncer.read();
    debouncer.update();
    delay(5);
    if (counter > 100) {
      Serial.println("Long press!");
      delay(1000);
      counter = 0;
    }
    counter++;
  }

Чтобы создать короткое нажатие:

Я создал другой цикл, «if», код в котором выполняется, если счётчик из предыдущего цикла не превысил своего порога (по наитию, я выбрал здесь значение 5).

if (counter > 5) {
Serial.println("Short press!");     
delay(1000);   
}

И вот окончательный код:

#include 
#define BUTTON_PIN 5 int counter = 0; Bounce debouncer = Bounce(); void setup() { Serial.begin(9660); // Setup the button with an internal pull-up : pinMode(BUTTON_PIN, INPUT_PULLUP); // After setting up the button, setup the Bounce instance : debouncer.attach(BUTTON_PIN); debouncer.interval(5); // interval in ms } void loop() { // Update the Bounce instance : debouncer.update(); // Get the updated value : int value = debouncer.read(); while ( value == LOW ) { debouncer.update(); value = debouncer.read(); debouncer.update(); delay(5); if (counter > 100) { Serial.println("Long press!"); delay(1000); counter = 0; } counter++; } if (counter > 5) { Serial.println("Short press!"); delay(1000); } counter = 0; }
Файлы

Шаг 5: Как использовать ИК ресивер? (KY-022)

Чтобы захватывать ИК сигнал, я использовал ИК ресивер KY-022. Для этого шага и следующего, я использовал руководство, найденное на adafruit: Как использовать ИК библиотеку в Ардуино.

И я использовал пример, названный «comboDump.ino» в IRLib2. С этим примером вы можете выбрать протоколы, которые хотите, вместо использования всей библиотеки.

Здесь я обнаружил, что могу получить нужный протокол (используя myDecoder.protocolNum), номера битов (myDecoder.bits), и декодированные значения данных (myDecoder.value). Это важно, поскольку мне нужны три эти показателя, чтобы отсылать ИК в следующем шаге. Так что я решил отобразить их в моём коде:

Serial.println(myDecoder.protocolNum);
Serial.println(myDecoder.bits);
Serial.println(myDecoder.value);

Вы можете использовать готовый код из файла, который я прикрепил.

Файлы

Шаг 6: Как отправлять ИК протоколы?

Чтобы отправлять ИК сигналы, я использовал следующую часть руководства с adafruit. Я использовал такую же схему и такой же код.

Но сделал небольшие изменения:

при отправке я использовал номер протокола, номер битов и значение, записанные в предыдущем шаге. И я использовал их таким образом:

mySender.send(Protocol, Data, Bits);

Чтобы добиться этого я создал три строковых переменных, содержащих нужные данные. И я поменял строковые значения на числовые. Сейчас вы можете удивиться, почему я создал строковые переменные до того, как создал числовые, а не сразу переменные типа «integer»? Это зависело от всего кода, и я объясню, что к чему в следующем шаге.

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

Итоговый код выглядит так:

#include 
IRsend mySender;
void setup() {
  Serial.begin(9600);
}
void loop() {
  String line1 = "1";
  String line2 = "32";
  String line3 = "33454215";
  //mySender.send(1,33454215, 32);
  mySender.send(line1.toInt(), line3.toInt(), line2.toInt());
  delay(1000);
}
Файлы

Шаг 7: Окончательная схема (с кабелем USB)

И вот итоговая схема и итоговый код! Схема включает в себя всю электронику, о которой я писал в предыдущих шагах (все подключается к тем же пинам) и все части кода.

Но есть небольшие изменения:

  • Для подключения каждого 5V модуля и земли я использовал макетную плату.
  • В схеме 2 датчика-крутилки. Как я уже объяснял, я использовал тот же код, но создал новые переменные для второй крутилки.
  • Некоторые переменные имели одинаковые имена, поэтому я переименовал их
  • Для считывания данных, которые нужно отправить (сохранённые в текстовых файлах на карте MicroSD), я использовал функцию file.readStringUntil(). Мне нужна была информация из каждой строки, поэтому я использовал функцию file.readStringUntil(‘\n’), которая означает: читай строку пока не начнётся следующая строка. Вот что вы можете увидеть в соответствующем участке кода:
while (myFile1.available()) {
digitalWrite(LED_PIN, HIGH );
        delay(100);
        String line1;
        String line2;
        String line3;
        int One;
        int Two;
        long Three;
        if (it == 1) {
          line1 = myFile1.readStringUntil('\n');
          One = line1.toInt();
        }
        if (it == 2) {
          line2 = myFile1.readStringUntil('\n');
          Two = line2.toInt();
        }
        if (it == 3) {
          line3 = myFile1.readStringUntil('\n');
          Three = line3.toInt();
          mySender.send(One, Three, Two);
          myFile1.close();
        }
        it++;
      }
Файлы

Шаг 8: Окончательная схема (портативная, с аккумулятором)

Наконец, я захотел сделать этот пульт переносным, поэтому я добавил батарейку 18650 и слот для неё, зарядник для батарейки (модуль TP4056), преобразователь тока, чтобы питать Ардуино от батарейки, и выключатель.

К сожалению, преобразователь напряжения, который я использовал, не совсем подходит для моего устройства, так как имеет выход USB…

И я заменил макетную плату чем-то типа хабов, спаяв вместе соответственно 5V провода и провода заземления.

Шаг 9: Окончательная схема (с напечатанным на 3D принтере корпусом)

Также я спроектировал кейс для платы Ардуино и модулей. Он очень прост, не совсем эстетичен, но зато делает своё дело.

Кое какую электронику я оставил просто болтаться в кейсе, например плата Ардуино, кардридер MicroSD, но некоторые части были прикреплены к кейсу при помощи винтов (ИК ресивер, обе крутилки, выключатель). Красный и ИК диоды были видны из двух отверстий, проделанных в кейсе.

Чтобы избежать замыканий, все металлические части схемы были закрыты изолентой.

Также я спроектировал два диска с пиктограммами, которые отображают девайсы, которыми я управляю и тип сигнала, который я могу отправить.

И вот части, которые я спроектировал и напечатал на 3D принтере:

  • Тело кейса
  • Передняя панель (с отверстиями для ИК ресивера и ИК диода)
  • Задняя панель (с отверстиями для выключателя и красного диода)
  • И верхняя панель (с двумя большими отверстиями для дисков с пиктограммами)
Файлы

Шаг 10: Смотря в будущее

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

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

Но есть несколько вещей, которые можно исправить и улучшить:

  • В коде, иногда красный диод остаётся гореть. Это означает, что цикл не прекращается в какие-то моменты… Я пробовал найти ошибки в коде, используя «тэги» в циклах (например, я написал Serial.println(«tag1»);), но у меня никогда не получалось выйти на ошибку во время её поиска. Так что я полагаю, она еще в коде, и я попытаюсь исправить её позже.
  • Я думаю, что часть с коротким\долгим нажатием можно сделать более простой.
  • Когда я использую пульт с батарейкой, он не очень хорошо «захватывает» ИК сигналы. Похоже, плата Ардуино очень тормозит, потому что красный диод горит значительно дольше, чем при подключении от USB. Я полагаю, что это из-за моего конвертера вольтажа, потому что он выдает максимум 250mA, чего может попросту не хватать… Так что вскоре я заменю конвертер, чтобы исправить проблему.
  • И, наконец, я думаю, что пластиковый кейс очень велик, а схема внутри разбросана слишком хаотично. Может быть лучше будет сделать печатную плату? И пластиковый кейс с определённым местом под каждый модуль.

Заметка: очень важно помещать стрелки пульта в одно и то же положение перед началом работы. Почему? Потому что когда вы начинаете работу с пультом, датчики угла поворота будут иметь значение 0. Так что если они будут в других положениях, 0 будет находиться в другом положении, нежели до этого.

В любом случае, я надеюсь, что некоторым из вас понравился этот проект и вы попробуете повторить его!

И снова, если я допустил какие-то ошибки, свободно поправляйте меня. Если проект вам понравился — комментируйте его и делитесь с друзьями!

Игорь Самоделов
Игорь Самоделов

Рассказываю как сделать какую-либо вещь с пошаговыми фото и видео инструкциями.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *