Окей, картинка слегка вводит в заблуждение, на этом ИК пульте Ардуино не «более 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 будет находиться в другом положении, нежели до этого.
В любом случае, я надеюсь, что некоторым из вас понравился этот проект и вы попробуете повторить его!
И снова, если я допустил какие-то ошибки, свободно поправляйте меня. Если проект вам понравился — комментируйте его и делитесь с друзьями!