ИК дистанционное управление компом через DigiSpark

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Задумал сделать дисташку для компа на дижиспарке, но выяснилось что стандартная библа IR-Remote занимает в 3 раза больше места, чем есть в дижиспарке. Альтернативная библа Ir-Remote для Tiny оказалась неюзабельной из-за вечно ожидающих while. Накатал свой обработчик IR-Remote. Места вообще не занимает, нет никаких while , но занимает внешнее прерывание и таймер0.  Обработчик писал под имеющийся у меня пульт от ресивера Pioneer, но по идее алгоритм совместим со всеми пультами стандарта NEC, и может ещё какими. Потом проверял из любопытства пульты, что нашёл дома - пульт от телека JVC подошёл, а от самсунга -нет.  Если снять ремарку с 23 строки, то можно печатать коды клавиш в любой текстовый редактор. Для эмуляции клавиатуры нужна библа от адафрута, о её возможностях рассказывал тут недавно. Только это оригинальная версия адафрута, её переделывать не нужно.  Стандартный фотоприёмник типа TSOP подключается на порт PB2, изменять нельзя, привязано к прерыванию.   Скетч:

// Скетч дистанционного управления для DigiSpark и V-USB библиотеки TrinketHidCombo for DigispArk
// ****TSOP подключен к порту PB2****////// 
volatile uint8_t m=0, complete=0,tcnt=0, startflag=0;
uint32_t irdata=0,keydata=0 ;
#include <avr/delay.h>
#include "TrinketHidCombo.h"
void setup() {
DDRB|=(1<<DDB1); //P1 (LED) OUT в скетче не использован
PORTB|=1<<PB2; // подтяжка PB2 не помешает.
GIMSK|=1<<INT0; //interrupt int0 enable
MCUCR|= 1<<ISC00; //Any logical change on INT0 generates an interrupt request
GTCCR|=1<<PSR0; TCCR0A=0;
TCCR0B= (1<<CS02)|(1<<CS00); // divider /1024 
TIMSK=1<<TOIE0;//interrupt Timer/Counter1 Overflow  enable
TrinketHidCombo.begin(); // start the USB device engine and enumerate
}
void loop() {

  if (complete) { // если был принят код
//  TrinketHidCombo.println(keydata,HEX); //снять ремарку ниже что бы печатать код клавиш    
// ниже пример управления винампом
if (keydata==0x7B845AA5) TrinketHidCombo.pressKey(0x03, KEYCODE_W );TrinketHidCombo.pressKey(0, 0);  //Cntrl-Shift-W  Hot-Key Запуск winamp
if (keydata==0x7D825AA5) TrinketHidCombo.pressKey(0, KEYCODE_X); TrinketHidCombo.pressKey(0, 0); // (X)  Play
if (keydata==0x7C835AA5) TrinketHidCombo.pressKey(0, KEYCODE_V); TrinketHidCombo.pressKey(0, 0); // (C)  Stop
if (keydata==0x7F805AA5) TrinketHidCombo.pressKey(0, KEYCODE_B); TrinketHidCombo.pressKey(0, 0); // (B)  next
if (keydata==0x7E815AA5) TrinketHidCombo.pressKey(0, KEYCODE_Z); TrinketHidCombo.pressKey(0, 0); // (Z)  prev.


ms_delay(200);// во избежание слишком частого повтора ввода клавиш
complete=0;
 }
  _delay_ms(1);//сдерживать поллинг USB на пустых циклах
  TrinketHidCombo.poll(); // check if USB needs anything done
  
}

ISR (INT0_vect){
  if (PINB& 1<<2) {   // Если лог1
      TCNT0=0;
      }
  else { tcnt=TCNT0; // если лог 0
          if (startflag){ if (30 > tcnt  && tcnt >2) {if (tcnt > 15&&m<32) {irdata|=((uint32_t)1<<m);} 
          m++;
          } } 
          else  startflag=1; 
        }
 }  
ISR (TIMER0_OVF_vect) {
 //если сработало это прерывание, значит конец посылки
if (m) {complete=1; m=0; startflag=0; keydata=irdata; irdata=0; // если индекс не 0, то создать флаг конца
  } 
}

void ms_delay(uint16_t x){ // функция задержки с USB поллом 
for (uint16_t m=0; m< (x/10); m++){ _delay_ms(10); TrinketHidCombo.poll(); }
}  
  

 

rucoda
Offline
Зарегистрирован: 29.02.2016

Круто! Такую функцию умять в такую маленькую платку

а TSOP подключается напрямую или ему нужны резисторы? Digispark же только 5В имеет.

А чтобы печатать коды клавиш, видимо, надо снять ремарку с 20 строки?

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

rucoda, TSOP напрямую. Ему вроде бы по даташиту рекомендовалось резюк, но и без него всё работает идеально. Я как написал этот пост и собрал дисташку, с тех пор пользуюсь -не единого глюка. Редко такое бывает, что сам доволён) Кстати спустя некоторое время поапалась библа для ИК, специализированная под диджиспарк. Но её не тестировал, т.к. уже не актуально было. А сейчас и адрес забыл где находил, (но на форуме где-то ссылку написал). Про ремарку -да.

 

rucoda
Offline
Зарегистрирован: 29.02.2016

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

    PORTB |= (1<<1); 
    ms_delay(200);// во избежание слишком частого повтора ввода клавиш
    PORTB &= ~(1<<1);
Появляется чувство уверенности
Shino Kuyo
Offline
Зарегистрирован: 08.06.2016

if (keydata==0x7B845AA5) TrinketHidCombo.pressKey(0x03, KEYCODE_W );TrinketHidCombo.pressKey(0, 0);

а можно поподробнее про синтаксис? можно было сделать просто if (keydata==0x7B845AA5) TrinketHidCombo.pressKey(0x03, KEYCODE_W ); ?

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Shino Kuyo, про синтаксис подробнее можно посмотреть в библиотекe TrinkedHidCombo. Код отпускания клавиши сократить нельзя. Попробуйте нажать кнопки на клавиатуре и не отпуская их продолжить работу. Получится?)

Shino Kuyo
Offline
Зарегистрирован: 08.06.2016

dimax, в библиотеке ничего такого не нашел, потому спросил.

нашел там такое:

#define MMKEY_KB_VOL_UP 0x80 // do not use
#define MMKEY_KB_VOL_DOWN 0x81 // do not use
#define MMKEY_KB_MUTE 0x7F // do not use
не скажете, почему do not use?
 
ну и у Вас:
TrinketHidCombo.pressKey(0x03, KEYCODE_W );TrinketHidCombo.pressKey(0, 0); //Cntrl-Shift-W
а в библиотеке 0х03 это #define SYSCTRLKEY_WAKE 0x03
или я что-то не так понял?
dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Shino Kuyo,

(1) там 2 типа мультимедийных кнопок громкости, стандартные без букв _KB_.   О тех что с буквами -не помню для чего они.

(2) Для понимания какая кнопка эмулируется -важен не только скан-код кнопки, но и функция которая его вызывает. В моём случае 0x03 - это код двух зажатых клавиш.

#define KEYCODE_MOD_LEFT_CONTROL    0x01
#define KEYCODE_MOD_LEFT_SHIFT        0x02

Но если бы я вызывал код 0x03 через функцию pressSystemCtrlKey()  то сэмулировалась бы кнопка "WAKE"

Shino Kuyo
Offline
Зарегистрирован: 08.06.2016

TrinketHidCombo.println(keydata,HEX);

печатает в блокнот нули в столбик: 0 0 0 0 0 0 0 0

куда копать не скажете?

вот это непонятно: моём случае 0x03 - это код двух зажатых клавиш.

#define KEYCODE_MOD_LEFT_CONTROL 0x01 #define KEYCODE_MOD_LEFT_SHIFT 0x02

0х01 прибавляем 0х02 = 0х03? :)

вот тут нашел похожий проект http://www.instructables.com/id/DIY-USB-IR-receiver/?ALLSTEPS

скетч для получения кодов пульта выдает вот что, вместо нулей:

42
37
40
16
6
41
53
22
41
50
37
8
1
0
26
36
20
42
19
37
40
57
37
0
40
 
это я просто нажимаю одну и ту же кнопку на пульте, значения все время разные. пульт вроде RC-6
dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Shino Kuyo, если печатает 0 , ( но всё включено правильно! ) -значит неподдерживаемый стандарт пульта. Попробовать другой пульт.

Shino Kuyo
Offline
Зарегистрирован: 08.06.2016

хочется именно этот пульт из-за эогономичности :(

Shino Kuyo
Offline
Зарегистрирован: 08.06.2016

попробовал другой пульт

EC13FB00
EC13FB00
EC13FB00
E41BFB00
E41BFB00
E41BFB00
E51AFB00
E619FB00
1
1
1
 
при зажатии кнопки выдает 1.
 
т.е. не будет эффекта зажатой клавиши на клавиатуре?
dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Shino Kuyo, (1) Для поддержки неподдерживаемых пультов нужно переписывать основной алгоритм программы, понятное дело что я этого делать не буду :)  (2) эффект зажатой клавиши - это от вас зависит. Настройте программу так, что б при входящей "единичке" повторялся бы  последний полный код.

Shino Kuyo
Offline
Зарегистрирован: 08.06.2016

понятно, что не будете))

боюсь программа (Kodi (XBMC)) будет эту "единичку" воспринимать как цифру и реагировать как на цифру. эх.

Shino Kuyo
Offline
Зарегистрирован: 08.06.2016

привинтил пульт от apple tv2

все вроде бы работает, но как "нажать" мультимедиа клавишу? play|pause конкретно

 

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

if (keydata == какой-то код) TrinketHidCombo.pressMultimediaKey(MMKEY_PLAYPAUSE);

Shino Kuyo
Offline
Зарегистрирован: 08.06.2016

ага, спасибо! я писал просто PressMMKey

Shino Kuyo
Offline
Зарегистрирован: 08.06.2016
if (keydata==0x10A87EE) TrinketHidCombo.pressKey(0, KEYCODE_ARROW_UP);     TrinketHidCombo.pressKey(0, 0);
if (keydata==0x10987EE) TrinketHidCombo.pressKey(0, KEYCODE_ARROW_LEFT);   TrinketHidCombo.pressKey(0, 0);
if (keydata==0x15C87EE) TrinketHidCombo.pressKey(0, KEYCODE_ENTER);        TrinketHidCombo.pressKey(0, 0);
if (keydata==0x10687EE) TrinketHidCombo.pressKey(0, KEYCODE_ARROW_RIGHT);  TrinketHidCombo.pressKey(0, 0);
if (keydata==0x10C87EE) TrinketHidCombo.pressKey(0, KEYCODE_ARROW_DOWN);   TrinketHidCombo.pressKey(0, 0);
if (keydata==0x10387EE) TrinketHidCombo.pressKey(0, KEYCODE_ESC);          TrinketHidCombo.pressKey(0, 0);
if (keydata==0x15F87EE) TrinketHidCombo.pressMultimediaKey(MMKEY_PLAYPAUSE);
 
а если не писать TrinketHidCombo.pressKey(0, 0); то будут при зажатой клавише циклично передаваться код клавиши?
Maltsev.v.v
Offline
Зарегистрирован: 17.03.2017

Добрый день. Подскажите пожалуйста, а как снять коды HEX с пульта (keydata==0x7B845AA5)?

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Maltsev.v.v, посмотрите пристально на 20 строчку скетча в топике.

Maltsev.v.v
Offline
Зарегистрирован: 17.03.2017

Спасибо огрмное, теперь разобрался 

Maltsev.v.v
Offline
Зарегистрирован: 17.03.2017

День добрый, подскажите пожалуйста, как научить digispark с Вашем скетчем, запускаться после перезагрузки ОС.

Пример реализации http://obruboff.ru/no-detect-usb-tiny-device-after-reboot-problem/.  

PS. Ваша программа самая универсальная для пультов, из всех что пробовал. только она спасобна работаеть с пультом от тв Samsung, lg

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Maltsev.v.v, за полтора года пользования пультом со скетчем из топика у меня такой проблемы не было. Так что судя по данному факту можно предположить, что скетч и библиотека тут не причём.

Maltsev.v.v
Offline
Зарегистрирован: 17.03.2017

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

Dmitriyxz
Offline
Зарегистрирован: 17.08.2017

Здравствуйте.

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

ISR (TIMER0_OVF_vect) {

происходит ошибка 

**\AppData\Local\Temp\arduino_build_872810/..\arduino_cache_21940\core\core_ATTinyCore_avr_attinyx5_LTO_disable,TimerClockSource_default,chip_85,clock_8internal,bod_disable_d7c462c19b85cdde3cc6d96586b2daa1.a(wiring.c.o): In function `__vector_5':

C:\Arduino\hardware\ATTinyCore\avr\cores\tiny/wiring.c:128: multiple definition of `__vector_5'

в чём может быть причина, и главное как её решить. 

причина необходимост прошивки через програматор http://arduino.ru/forum/obshchii/attiny85-i-zaderzhka-zapuska

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Dmitriyxz, причина в том, что ардуиновский аддон дижиспарка и аддон тини используют разные таймеры для системных функций. Соответссно в одном случае компилится без проблем, во втором получается что вы пытаетесь сесть на тот-же вектор, который уже заняла библа ардуины.   Вариантов решения два -долго курить конфиги ардуины что б корректно вырезать из них функции, занимающие таймеры. Либо полностью отключить все ардуиновские функции перейдя от setup(){}  loop(){}  к традиционным int main(){ while(1)} , второй способ разумеется повлечет за собой необходимость подключения нужных библиотек. В общем что так что эдак -задачка не для начинающих.

Dmitriyxz
Offline
Зарегистрирован: 17.08.2017

поменял:

  TIMSK = 1 << TOIE0;
  ISR (TIMER0_OVF_vect)
на
  TIMSK = (1 << OCIE0A);
  ISR (TIM0_COMPA_vect)
 
после всё работает без проблем.
dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Dmitriyxz, да, действительно, можно и такой  вариант- просто перенести на другое прерывание :)

roman12121993@g...
Offline
Зарегистрирован: 22.01.2018
Почему для УНО я не могу скомпилировать, выбрасывает ошибку?
Dmitriyxz
Offline
Зарегистрирован: 17.08.2017

Для UNO точно такое работать не будет, так как там нет эмуляции клавиатуры ( есть ардуинки на чипе ATmega32U4 - те умеют... и то код менять надо будет)

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

roman12121993, потому, что написано для attiny85.   Для UNO это нафиг не нужно. Используйте стандартную либу IRremote.

Dmitriyxz
Offline
Зарегистрирован: 17.08.2017

фото одной из модификаций DigiSpark...

Shino Kuyo
Offline
Зарегистрирован: 08.06.2016

приветствую снова)))

в общем работала эта плата хорошо. но надо бы ее прошить под другой пульт.

и вот тут облом! она просто определяется как клавиатура и все. никаких 5 секунд не ждет прошивки. сразу клавиатура.

она одноразовая?

yavalera
Offline
Зарегистрирован: 17.04.2018