Arduino и IR-пульты. Один пульт на несколько устройств.

Тема в разделе "Arduino & Shields", создана пользователем AlexKooper, 2 дек 2015.

  1. AlexKooper

    AlexKooper Нуб

    У меня дома есть телевизор с большим пультом с кучей кнопок . И приставка цифрового тв, с маленьким пультом. И DVD-плеер, с тяжелым неудобным пультом.[​IMG]
    Почитав про универсальный пульт на ардуине (там, где смартфон и блютуз участвуют), загорелся идеей сделать нечто подобное. Но по иному принципу: задействовать неиспользуемые (в обычном режиме неиспользуемые) кнопки ТВ-пульта для управления прочими устройствами.
    В моём случае - переключение каналов на ТВ-приставке с ТВ-пульта кнопками "вверх" и "вниз". Также управление громкостью приставки (влево и вправо) , открытие списка каналов (кнопка enter,ОК) и закрытие меню каналов (ексит). Управление DVD - используется на ТВ блок кнопок (плей стоп пауза перемотки).
    Принцип работы: ловим ИК-приёмником сигнал с ТВ-пульта, если нажата одна из нужных кнопок - передаём ИК-диодом код другого пульта. Нпример, поймали код "влево" от ТВ-пульта - передаём код "влево" от ТВ-приставки.

    Где взять коды.
    Отключаем (я заархивировал) библиотеку RobotIRremote. Качаем Arduino-IRremote-master.zip
    С библиотекой Arduino-IRremote-master идут примеры кода - берём скетч IRrecvDump, загружаем (модифицируем под свой номер вывода ИК-приёмника, у меня 2) и смотрим в мониторе порта данные (светим пультом на приёмник). Понадобится ХЕКС код кнопки (для приёма нужного сигнала) и ХЕКС-код с типом сигнала (NEC, SONY RC5 и т.п.) для передачи.

    Собствено, скетч (кнопки имитации DVD пока не сделаны, только ТВ-приставка)
    Тип кодов ТВ-пульта - RAW, приставки - NEC

    Код (C++):
    #include <IRremote.h>
    #include <IRremoteInt.h>

    /*
    * автор - AlexKooper
    *  Default is Arduino pin D11.
    *  You can change this to another available Arduino Pin.
    *  Your IR receiver should be connected to the pin defined here
    */

    int RECV_PIN = 2;
    volatile unsigned long  in_signal = 0;

    IRrecv irrecv(RECV_PIN);
    decode_results results;
    IRsend irsend;

    void setup()
    {
      Serial.begin(9600);
        pinMode(13, OUTPUT);
      irsend.enableIROut(38);
      irrecv.enableIRIn(); // Start the receiver
    }


    void dump(decode_results *results) {
      // Dumps out the decode_results structure.
      // Call this after IRrecv::decode()
      int count = results->rawlen;
      if (results->decode_type == UNKNOWN) {
        Serial.print("Unknown encoding: ");
      }
      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: ");
      }
      else if (results->decode_type == PANASONIC) {
        Serial.print("Decoded PANASONIC - Address: ");
        Serial.print(results->address, HEX);
        Serial.print(" Value: ");
      }
      else if (results->decode_type == LG) {
        Serial.print("Decoded LG: ");
      }
      else if (results->decode_type == JVC) {
        Serial.print("Decoded JVC: ");
      }
      else if (results->decode_type == AIWA_RC_T501) {
        Serial.print("Decoded AIWA RC T501: ");
      }
      else if (results->decode_type == WHYNTER) {
        Serial.print("Decoded Whynter: ");
      }
      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 = 1; i < count; i++) {
        if (i & 1) {
          Serial.print(results->rawbuf[i]*USECPERTICK, DEC);
        }
        else {
          Serial.write('-');
          Serial.print((unsigned long) results->rawbuf[i]*USECPERTICK, DEC);
        }
        Serial.print(" ");
      }
      Serial.println();
    }

    void loop() {
       decode_results  results;    
      if (irrecv.decode(&results)) {
        in_signal=results.value;
        Serial.println(results.value, HEX);
        dump(&results);
      if (in_signal==0xE0E006F9){ //кнопка вверх на ТВ-пульте
      digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
      irsend.sendNEC(0x807F22DD, 32);//кнопка вверх на ТВ-приставке
      delay(200);
      digitalWrite(13, LOW);   // turn the LED on (HIGH is the voltage level)
      in_signal=0;
      irrecv.enableIRIn(); // ВАЖНАЯ СТРОЧКА!!!!
    //ОХ ВАЖНАЯ СТРОЧКА!!!!
    //БЕЗ НЕЁ ПРИЁМНИК ПЕРЕСТАЁТ РАБОТАТЬ ПОСЛЕ irsend
    //УБИЛ НА ПОИСК ПРИЧИНЫ НЕДЕЛЮ!!!!
      };

      if (in_signal==0xE0E08679){ //кнопка вниз
      digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
      irsend.sendNEC(0x807F12ED, 32);
      delay(200);
      digitalWrite(13, LOW);   // turn the LED on (HIGH is the voltage level)
      in_signal=0;
      irrecv.enableIRIn();
      };

      if (in_signal==0xE0E046B9){ //кнопка вправо
      digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
      irsend.sendNEC(0x807F02FD, 32);
      delay(200);
      digitalWrite(13, LOW);   // turn the LED on (HIGH is the voltage level)
      in_signal=0;
      irrecv.enableIRIn();
      };

      if (in_signal==0xE0E0A659){ //кнопка влево
      digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
      irsend.sendNEC(0x807F32CD, 32);
      delay(200);
      digitalWrite(13, LOW);   // turn the LED on (HIGH is the voltage level)
      in_signal=0;
      irrecv.enableIRIn();
      };

      if (in_signal==0xE0E016E9){ //кнопка центр
      digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
      irsend.sendNEC(0x807F609F, 32);
      delay(200);
      digitalWrite(13, LOW);   // turn the LED on (HIGH is the voltage level)
      in_signal=0;
      irrecv.enableIRIn();
      };

      if (in_signal==0xE0E0B44B){ //кнопка ексит
      digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
      irsend.sendNEC(0x807FC03F, 32);
      delay(200);
      digitalWrite(13, LOW);   // turn the LED on (HIGH is the voltage level)
      in_signal=0;
      irrecv.enableIRIn();
      };


      irrecv.resume();
      }
    }
     
    Передающий диод подключен с 3 вывода (вывод 3 не задаётся в скетче, задан жестко в библиотеке) на землю. Люди делали напрямую, но я - последовательно с резистором на 100 Ом.
    [​IMG] [​IMG]

    Устройство (прототип) втыкается в разъём УСБ-флешки на лице ТВ-приставки, приёмник смотри вперёд (на зрителя), передатчик - назад, на ИК-приёмник приставки.
    Дополнительно факт распознавания кода (и срабатывания передатчика)подчеркивается работой зелёного диода на ардуине (встроенный, на 13 кажется выводе).
    Код можно оптимизировать, убрав анализ дампа и вывод в последовательный порт, но это мне не мешает пока.
    Готовое устройство скорее всего будет не торчать из порта УСБ, а заныкано за ТВ (запитать там есть чем), с выставленным хвостиком приёмника-передатчика. Если вообще будет сделано, устройство делал больше для практики программирования, чем для практического применения.

    Самая серьёзная проблема, с которйо столкнулся - после применения irsend параставал работать приём команд. Решилось вызовом irrecv.enableIRIn(); после срабатывания irsend.
     
  2. Salk

    Salk Гик

    Иии?
     
  3. AlexKooper

    AlexKooper Нуб

    Что и? Нигде не было описано решение этой проблемы, про сломавшийся приём после команды irsend. Тепероь описано. пользуйтесь.
     
  4. Raiken

    Raiken Нуб

    Вопрос, копирую ваш скетч в Arduino, а оно не компиляется, вылетает с ошибкой:
    Arduino: 1.6.6 (Windows 7), Плата:"Arduino/Genuino Uno"

    sketch_jan14a:49: error: 'class decode_results' has no member named 'address'

    Serial.print(results->address, HEX);

    ^

    sketch_jan14a:52: error: 'LG' was not declared in this scope

    else if (results->decode_type == LG) {

    ^

    sketch_jan14a:58: error: 'AIWA_RC_T501' was not declared in this scope

    else if (results->decode_type == AIWA_RC_T501) {

    ^

    sketch_jan14a:61: error: 'WHYNTER' was not declared in this scope

    else if (results->decode_type == WHYNTER) {

    ^

    exit status 1
    'class decode_results' has no member named 'address'

    Это сообщение будет содержать больше информации чем
    "Отображать вывод во время компиляции"
    включено в Файл > Настройки
     
  5. AlexKooper

    AlexKooper Нуб

    По первой ошибке - случайно, не забыли убрать из библиотек RobotIRremote? она конфликтует. Я её просто заархивировал в рар. Если не помогло - дальнейшие действия.
    Раз ругается на 3 последних добавленых пульта - скорее всего используется более ранняя версия библиотеки. Или поискать версию библиотеки как у меня
    // IRremote
    // Version 2.0.1 June, 2015
    // Copyright 2009 Ken Shirriff
    или для своей библиотеки, если есть примеры дампа, взять код процедуры оттуда.У меня оно лежало в у библиотеки папке examples, скетч IRrecvDump.ino

    Гугль говорит, что проблема может быть именно не в той версии библиотеки. Прикладываю свою. Кстати, у меня на свежей версии IDE не пошла компиляция для ардуино нано, откатился на 1.0.6 - заработало. В последней не было даже выбора, нано на 168 или 368 атмеге.
     

    Вложения: