Arduino, DigiSpark, ATTiny85, IR, пульт ДУ

От какой-то фоторамки у меня остался пульт и ИК приёмник. Они долго лежали у меня «на всякий случай» и такой случай настал. У меня нет телевизора и его роль выполняет старый ноутбук, на котором я смотрю ютуб. Я решил, что стоит сделать удалённое управление с пульта ноутбуком, для удобного просмотра https://youtube.com/tv не вставая с кресла.

Сразу отмечу, что всё, что описано ниже, это результат моих опытов и моих выводов. Всё может работать совершенно не так, а я идиот. У меня была цель сделать, чтобы заработало конкретно у меня, так что вот.

В качестве микроконтроллера я использую DigiSpark, она же ATTiny85 с USB в комплекте. Он может эмулировать клавиатуру, что мне как раз понадобится. Гребёнки на плате уже были припаяны, так что я просто соединил проводами приёмник и плату. Думаю, что по фото понятна распиновка приёмника и как он подключен к плате.

Существуют готовые библиотеки для работы с ИК приёмником. В ATTiny всего 6кб под программу (2кб загрузчик), так что не все они подойдут. Я же решил написать свой велосипед под свой конкретный случай. Разумеется, я подсматривал в готовые библиотеки, чтобы понять общий принцип работы. Просто было интересно разобраться в работе ИК пультов.

Если в двух словах, то принцип работы следующий. Когда вы нажимаете кнопку на пульте, ИК передатчик включается на длинный период и гаснет. Это означает начало передачи. Затем вспышками разной длинны времени передаются данные. Короткая вспышка (500-600) кодирует ноль, а длинная (1600-1700) кодирует единицу. В других пультах и приёмниках возможно всё иначе. Все эти данные были получены экспериментально.

Сначала я проводил эксперименты на Arduino UNO и написал простой код:

int irPin = 2;


void setup() 
{

  Serial.begin(9600);

  while (!Serial) {}


  pinMode(irPin, INPUT);

  Serial.println(F("Program started!"));

}


void loop() 
{
  int s = pulseIn(irPin, HIGH);
  if(s)
 {
 Serial.println(s);
 }

}

Функция pulseIn(pin, value) считает длину сигнала на заданном пине в микросекундах. В данном случае, она считает сколько времени на пине, к которому был подключен ИК приёмник, держится высокий уровень. Если сигнал так и не пришёл, то возвращается 0. С помощью этого нехитрого скетча, мне удалось выяснить длительность стартового сигнала и количество передаваемых бит.

Далее, нужно было принять всю посылку и преобразовать её в число. Я делал это  в цикле. Оказалось, что первые биты во всех посылках одинаковые и их можно не трогать. В моём случае, принимались 20 бит, но переводились в код только последние 8 (с 12, по 20).

void loop() {
  int i, data[20];
  int s = pulseIn(irPin, HIGH);
  if(s > 4000) {
    for(i = 0; i < 20; i++)
      data[i] = pulseIn(irPin, HIGH);
    
	int result = 0;
    for(i = 12; i < 20; i++)
      if(data[i] > 1000)
        result |= (1 << (20 - 1 - i));
    
	delay(400);
	Serial.println(result)
  }
}

Код должен быть понятен. Получаем длительность сигнала. Если она больше заданного значения (в данном случае 4000), значит за этим сигналом будут следовать данные. В цикле записываем длительности сигналов в массив. Затем берём последние 8 элементов из массива и переводим их в целое число по правилам описанным выше. На этом, мы разобрались, как работать с пультом и приёмником.

Теперь, при нажатии на соответствующую кнопку на пульте и принятии её приёмником, мы должны передавать это нажатие на компьютер, эмулируя нажатие кнопок на клавиатуре. Для этого есть файл DigiKeyboard.h. К сожалению, в нём почему-то отсутствуют коды всех стрелочек, кроме левой. Пришлось гуглить и вставлять недостающие коды. Весь окончательный скетч есть на GitHub.

После загрузки кода, подключаем DigiSpark к компьютеру по USB и видим, что нажатые кнопки на пульте транслируются в нажатия кнопок клавиатуры.

Для управления https://youtube.com/tv достаточно стрелочек, enter и esc. Для поиска на сайте есть экранная клавиатура. Это вполне удобно. На оставшиеся кнопки можно повесить, например, запуск браузера на весь экран сразу с ютубом или всё, что нужно.

12 комментариев на “Arduino, DigiSpark, ATTiny85, IR, пульт ДУ

  1. Александр

    Все конечно хорошо, но не совсем.
    На Serial.println(F(«Program started!»)); тратится время процессора, что дает неверные данные результатов будет не 20 а 32 как положено стандарту NEC

    Нравится

    1. Дмитрий Автор записи

      Не понимаю, о чём вы говорите. Serial.println(F(«Program started!»)); используется внутри setup — то есть выполняется один раз и ни на что не влияет. Кроме того, этот код представлен как иллюстрация того, как я разобрался в работе приёмника и не используется в скетче, который выложен на гитхабе.

      Нравится

  2. Александр

    #define irPin 2
    void setup() {
    Serial.begin(9600);
    pinMode(irPin, INPUT);
    }
    void loop() {
    int i;
    int data[32];
    int s = pulseIn(irPin, HIGH);
    int result = 0;

    if (s > 4000) { //запись значений с датчика
    for (i = 0; i < 32; i++)
    data[i] = pulseIn(irPin, HIGH);

    Serial.print("Код: ");
    for (i = 0; i 1000)
    data[i] = 1;
    else
    data[i] = 0;
    Serial.print(data[i]);
    }

    int adr = 0;
    int com = 0;

    for (i = 0; i < 8; i++) //извлекаем из массива неинвертированный сигнал (адрес и команду)
    adr |= (data[i] << 7 — i);
    for (i = 0; i < 8; i++)
    com |= (data[16 + i] << 7 — i);

    Serial.println(""); //выводим в Serial
    //Serial.println(adr, BIN);
    Serial.print("Адрес: "); Serial.println(adr);
    //Serial.println(com, BIN);
    Serial.print("Команда: "); Serial.println(com);
    Serial.println("———————————");
    }
    }

    Нравится

  3. Вячеслав

    Приветствую! А можно с помощью скетча, который на гитхабе получить коды кнопок пульта, в блокнот вывести, например?как можно модернизировать скетч для этой цели?

    Нравится

    1. Дмитрий Автор записи

      Да, можно. Под рукой нет на чём проверить, но что-то типа выкинуть блок switch-case, а написать просто что-то типа DigiKeyboard.println(result)

      Нравится

  4. Вячеслав

    также я поставил DATA_SIZE 24, так как при DATA_SIZE 20, у меня печатались двузначные коды кнопок. Пульт у меня Avermedia Box9

    Нравится

  5. Вячеслав

    //отладка. Установите значение 0 после поиска ваших кодов

    #define DEBUG 1

    #include «DigiKeyboard.h»

    #define MENU 237

    #define ESC 229

    #define AUTOPLAY 227

    #define ZOOM 232

    #define LEFT 236

    #define UP 234

    #define RIGHT 225

    #define DOWN 238

    #define ENTER 233

    #define IR_PIN 2

    #define DATA_SIZE 24

    #define START_BIT 4000

    int i, s, data[DATA_SIZE];

    void setup()

    {

      pinMode(IR_PIN, INPUT);

    }

    void loop()

    {

      DigiKeyboard.update();

      DigiKeyboard.sendKeyStroke(0);

      s = pulseIn(IR_PIN, HIGH);

      if(s > START_BIT)

      {

        for(i = 0; i < DATA_SIZE; i++)

          data[i] = pulseIn(IR_PIN, HIGH);

        int result = 0;

        for(i = 12; i < DATA_SIZE; i++)

          if(data[i] > 1000)

            result |= (1 << (DATA_SIZE — 1 — i));

        switch(result)

        {

          case MENU: break;

          case ESC: DigiKeyboard.sendKeyStroke(41); break;

          case AUTOPLAY: break;

          case ZOOM: break;

          case LEFT: DigiKeyboard.sendKeyStroke(0x50); break;

          case RIGHT: DigiKeyboard.sendKeyStroke(0x4f); break;

          case UP: DigiKeyboard.sendKeyStroke(0x52); break;

          case DOWN: DigiKeyboard.sendKeyStroke(0x51); break;

          case ENTER: DigiKeyboard.sendKeyStroke(KEY_ENTER); break;

        default:

          if(DEBUG)

            DigiKeyboard.println(result, HEX);

          else

            return;    

        }

        digitalWrite(1, HIGH);

        delay(400);

      }

    }

    Нравится

  6. Вячеслав

    Приветствую!

    Вопрос к Дмитрию, может сможете помочь:

    В Digispark есть стандартный пример из библиотеки DigisparkIRLib
    DigiIrDump.ino

    При заливке на плату определяется как неизвестное USB устройство (Сбой запроса на установку адреса USB)

    При этом, если залить пример DigiScope.ino (библиотека DigisparkUSB), USB устройство определяется нормально.

    В чем может быть проблема? Оба примера стандартные для Digispark.

    Нравится

    1. Дмитрий Автор записи

      Сейчас у меня уже не на чем попробовать воспроизвести вашу проблему, чтобы сказать что-то определенное.

      Нравится

Оставьте комментарий