Управляти Arduino за допомогою інфрачервоного (ІЧ) пульта дистанційного керування (ДК) дійсно просто. Сьогодні можна знайти досить дешеві і прості ІЧ-пульти для таких цілей. Спробуємо розібратися, що потрібно зробити для того, щоб ваш Arduino розумів команди з пульта.
Вступ
Зв’язок через ІЧ-порт - поширена, недорога і проста у використанні технологія бездротового зв'язку. Світло ІЧ-діапазону дуже схоже на видиме світло, за винятком того, що воно має дещо більшу довжину хвилі. Це означає, що ІЧ невидиме людським оком - ідеальне рішення для бездротового зв'язку. Наприклад, коли ви натискаєте кнопку на пульті від телевізора, інфрачервоний світлодіод вмикається і вимикається не один раз, а 38000 разів на секунду, щоб передавати інформацію до інфрачервоного датчика на телевізорі (наприклад, контролювати гучність або канал).
Спочатку коротко розглянемо внутрішню роботу загальних протоколів ІЧ-зв'язку. А потім перейдемо до прикладів, які дозволяють передавати і приймати ІЧ-дані за допомогою Arduino.
Для того щоб дізнатися, який протокол використовується в пульті дистанційного управління, потрібно зібрати схемку з ІЧ-приймачем, зняти осциллограмму сигналу і порівняти її з відомими протоколами.
Правда є один момент, ІК-приймач розрахований на роботу з однією несучою частотою, а в деяких протоколах значення несучих частот відрізняються - одні використовують 38 кГц (наприклад, протокол фірми Nec), інші 36 або 40. Тому одна і та ж схема не зможе працювати з усіма без винятку ІК-пультами дистанційного керування.
Одним з найпоширеніших протоколів роботи ІЧ ДК є протокол NEC, яких розглянемо детальніше.
Для передачі даних використовується несуча частота 38 кГц. Посилка складається з стартового імпульсу і чотирьох байтів даних - адреса, інвертоване значення адреси, команда, інвертоване значення команди. Адреса та команда передаються двічі для підвищення надійності.
Дані передаються молодшим бітом вперед. Кожен біт починається з пачки імпульсів несучої частоти. Тривалість пачки дорівнює 562 мкс. Шляхом зміни тривалості інтервалу між пачками імпульсів здійснюється кодування нулів і одиниць. При передачі логічної одиниці інтервал від початку поточної до початку наступної пачки імпульсів становить 2.25 мс, а при передачі логічного нуля - 1.125 мс:
Стартовий імпульс являє собою пачку імпульсів несучої частоти тривалістю 9 мс. Після подачі стартового імпульсу слідує пауза тривалістю 4.5 мс.
Посилка, що містить адресу і команду, передається одноразово, але при утриманні кнопки пульта дистанційного керування через кожні 108 мс випромінюється код повтору - пачка імпульсів несучої частоти тривалістю 9мс, пауза в 2.25 мс і пачка імпульсів тривалістю 562 мкс.
Існує також розширена версія протоколу NEC, в якій використовується 16-ти розрядні адреси.
Контролюючи відстань між прийнятими модульованими сигналами на вході приймача, можемо декодувати їх в послідовний потік бітів. Нижче представлений концептуальний вигляд, як працює пара ІЧ-передавач – приймач:
Для того щоб дізнатися, який протокол використовується в пульті ДК, потрібно зібрати схему з ІЧ-приймачем, зняти осциллограмму сигналу і порівняти її з відомими протоколами. Ми ж спробуємо нижче визначити протокол програмним шляхом.
Правда є один момент, ІК-приймач розрахований на роботу з однією несучою частотою, а в деяких протоколах значення несучих частот відрізняються - одні використовують 38 кГц, як розглянутий протокол фірми NEC, а інші можуть використовувати одну з доступних частот: 30 кГц, 33 кГц, 36 кГц, 38 кГц, 40 кГц і 56 кГц. Тому одна і та ж схема не зможе працювати з усіма без винятку ІК-пультами дистанційного керування.
Визначаємо протокол ДК та коди клавіш пульта
Щоб зібрати схему для тестування визначимося з необхідними комплектуючими. Вибираючи фотоприймач, розглядаємо лише моделі, в назві якої в кінці буде число 38 (TSOP4838, 31238, 2138, 1738 ...), тобто частота модуляції сигналу 38 кГц. Дану частоту підтримує більшість протоколів ДК.
Примітка: На блок-схемі фотоприймача AGC (Automatic Gain Control) зменшує коефіцієнт підсилення підсилювача в присутності шумових сигналів для того, щоб не отримувати помилкові імпульси, і тримає високим коефіцієнтом посилення, при отриманні даних. Рекомендується обирати моделі фотоприймача з AGC-4.
Ми використаємо модель UNO Arduino, але можна взяти і будь-яку іншу. Потім треба з’єднати Arduino з ІЧ-приймачем. У приймача є три виводи: живлення (Vs або VCC), земля (GND) і вихідного сигналу (OUT). Під’єднаємо OUT до 11 порту. Зверніть увагу, що OUT – це, зазвичай, вивід 1, а живлення і земля можуть мінятися місцями, в залежності від моделі. При неправильному підключенні фотоприймача від швидко нагрівається і виходить з ладу.
Будьте уважними! На схемі нижче використаний фотоприймач, в якого GND є виводом 3:
На наступному кроці нам необхідно завантажити бібліотеку для реалізації дистанційного керування. Бібліотека доступна за посиланням:
https://github.com/shirriff/Arduino-IRremote
Для завантаження, виберіть посилання "Downloads" в нижньому правому куті, потім - "Download as zip" і завантажте zip файл. Розархівуйте його і отриману папку Arduino-IRremote-master перейменуйте в IRremote.
Для інсталяції, перемістіть завантажену папку IRremote в arduino-1.0.x/libraries/IRremote, де arduino-1.0.x – папка з інтальованим вашим Arduino.
Далі, для інсталяції бібліотеки, в новому скетчі виберіть Sketch->Import Library->IRremote:
Вставляємо наведений нижче код в цей новий скетч і виконуємо компіляцію:
#include <IRremote.h>//Підключення бібліотеки IRremote.h
int RECV_PIN = 11;// Назначаємо вивід 11 для приєднання виходу приймача
IRrecv irrecv(RECV_PIN);
decode_results results;
void setup()
{
Serial.begin(9600);// Задаємо швидкість передачі послідовного порта
irrecv.enableIRIn();// Дозволяємо роботу приймача
}
// Створюємо серію "dump", в якій програма буде порівнювати результати, отримані з даними пультом і даними файлу IRremote.h. Якщо дані збігаються, програма покаже вам, який тип протоколу.
void dump(decode_results *results) {
int count = results->rawlen;
if (results->decode_type == UNKNOWN) {
Serial.println("Could not decode message");
}
else {
if (results->decode_type == NEC) {
Serial.print("Decoded NEC: ");
}
else if (results->decode_type == SONY) {
Serial.print("Decoded SONY: ");
}
else if (results->decode_type == RC5) {
Serial.print("Decoded RC5: ");
}
else if (results->decode_type == RC6) {
Serial.print("Decoded RC6: ");
}
Serial.print(results->value, HEX);
Serial.print(" (");
Serial.print(results->bits, DEC);
Serial.println(" bits)");
}
Serial.print("Raw (");
Serial.print(count, DEC);
Serial.print("): ");
for (int i = 0; i < count; i++) { if ((i % 2) == 1) { Serial.print(results->rawbuf[i]*USECPERTICK, DEC);
}
else {
Serial.print(-(int)results->rawbuf[i]*USECPERTICK, DEC);
}
Serial.print(" ");
}
Serial.println("");
}
void loop()
{
// У цьому циклі програма представлятиме коди, отримані за допомогою натискання клавіш пульта ДК, які потім можна використати в іншому проекті
if (irrecv.decode(&results))// Перевіряємо чи прийнятий код
{
Serial.println(results.value, HEX);
dump(&results);
irrecv.resume();// Приймаємо наступне значення
}
}
Відкриваємо монітор послідовного порта (Tools -> Serial Monitor), беремо пульт дистанційного керування і натискуємо на різні клавіші. На моніторі повинні з’являтися шістьнадцятиричні цифри.
Необхідно записати всі числа, які відповідають кнопкам. Наприклад, для пульту ДК, який був зображений на початку статті, коди будуть наступними:
PWR FF629D
CH FFE21D
|<< FF22DD
>| FFC23D
>>| FF02FD
- FFE01F
Plus FFA857
EQ FF906F
0 FF6897
100+FF9867
200+FFB04F
1 FF30CF
2 FF18E7
3 FF7A85
4 FF10EF
5 FF38C7
6 FF5AA5
7 FF42BD
8 FF4AB5
9 FF52AD
Отримані результати використаємо в наступному прикладі.
Керуємо світлодіодами з пульту ДК
Тепер ми вже достатньо знаємо, щоб перейти до дистанційного керування пристроями, приєднаними до Arduino. Зберемо таку схему:
В схемі чотири світлодіоди різного кольору (синій, червоний, жовтий, зелений) через опори 200 Ом підключені до відповідних портів Arduino (10, 9, 6, 5). Необхідно вибрати клавіші на пульті ДК, при натисканні яких змінювався б діод, який блимає, а при натискання клавіші PWR всі діоди б погасли. Код однієї з можливих реалізацій наведений нижче:
#include <IRremote.h>
int IR_Recv = 3; //IR-приймач Pin 3
int g_ledPin = 5; //зелений LED pin 5
int y_ledPin = 6; //жовтий LED pin 6
int r_ledPin = 9; //червоний LED pin 9
int b_ledPin = 10; //синій LED pin 10
int ledPins[] = {5, 6, 9, 10}; //масив з виводів усіх LED's
int ledStates[] ={0, 0, 0, 0}; //це означає, що початковий стан LED's є 0 = LOW
int i=0; //індекс LED для масиву
IRrecv irrecv(IR_Recv);
decode_results results;
//змінні, щоб заставити LED блимати, коли він вибраний
int ledState = LOW; //ledState для вмикання або вимикання LED
long previousMillis = 0; //збереження часу останнього оновлення LED
long interval = 1000; //інтервал для блимання (мілісекунди)
void setup(){
Serial.begin(9600); //запуск послідовного з’єднання
irrecv.enableIRIn(); //дозвіл роботи приймача
pinMode(g_ledPin, OUTPUT); //встановлення цифрового виводу на вихід
pinMode(y_ledPin, OUTPUT); //встановлення цифрового виводу на вихід
pinMode(r_ledPin, OUTPUT); //встановлення цифрового виводу на вихід
pinMode(b_ledPin, OUTPUT); //встановлення цифрового виводу на вихід
}
void loop(){
//декодування вхідного інфрачервого сигналу
if (irrecv.decode(&results)){
long int decCode = results.value;
Serial.println(decCode);
//кейс перемикання для використання вибраної клавіші дистанційного керування
switch (results.value){
case 0xFF02FD: //коли ви натисли клавішу >>|
//if/else, щоб переконатися, що LED ON або OFF, перш ніж перейти до наступного LED
if(ledStates[i]==0)
digitalWrite(ledPins[i], LOW);
else
digitalWrite(ledPins[i], HIGH);
Serial.println("Next LED");
//переконатися, що коли ми досягаємо останнього LED, то знову повертаємось до першого LED
if(i>=3)
i=-1;
i+=1;
break;
case 0xFF22DD: //коли натисли клавішу |<<
//if/else, щоб переконатися, що LED ON або OFF, перш ніж перейти до попереднього LED
if(ledStates[i]==0)
digitalWrite(ledPins[i], LOW);
else
digitalWrite(ledPins[i], HIGH);
Serial.println("Previous LED");
//переконатися, що коли ми досягаємо першого LED, то переходимо до останнього LED
if(i<=0)
i=4;
i-=1;
break;
case 0xFF906F: //коли натисли клавішу EQ
if(ledStates[i]==0){ //якщо LED вимкнений, то він буде увімкнений
Serial.println("Turns ON the LED Selected");
digitalWrite(ledPins[i], HIGH); //вмикання LED
ledStates[i]=1; //оновлення статусу LED
}
else{
Serial.println("Turns OFF the LED Selected"); //else: LED увімкнений, то він буде вимкнений
digitalWrite(ledPins[i], LOW); //вимикання LED
ledStates[i]=0; //оновлення статусу LED
}
break;
case 0xFF629D: //коли натисли клавішу PWR
Serial.println("Turns OFF all the LED's");
digitalWrite(g_ledPin, LOW); // вимкнути зелений LED
ledStates[0] =0; // оновити статус LED
digitalWrite(y_ledPin, LOW); // вимкнути жовтий LED
ledStates[1] =0; // оновити статус LED
digitalWrite(r_ledPin, LOW); // вимкнути червоний LED
ledStates[2] =0; // оновити статус LED
digitalWrite(b_ledPin, LOW); // вимкнути синій LED
ledStates[3] =0; // оновити статус LED
break;
default:
Serial.println("Waiting");
}
irrecv.resume(); // Прийняти наступне значення від натиснутої клавіші
}
// структура if заставляє LED блимати, якщо він вибраний, і вимикає
if(ledStates[i]==0){
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > interval) {
// зберегти час останнього блимання LED
previousMillis = currentMillis;
// якщо LED вимкнений, то увімкнути його і навпаки:
if (ledState == LOW)
ledState = HIGH;
else
ledState = LOW;
// встановлюємо LED у відповідності зі змінною ledState:
digitalWrite(ledPins[i], ledState);
}
}
}
Замість висновків
Тепер ви вмієте дистанційно керувати різними пристроями, використовуючи пульт ДК та Arduino. Надіюсь, що ви не обмежитесь повторенням прикладів статті, а будете експериментувати. З задоволенням розмістимо статті з вашими екпериментами на сайті.