DIY USB IR Receiver

63,189

399

48

About: I'm an embedded ICT student.

In this tutorial, I'm going to show you how to make a small, cheap (less than $5) USB IR receiver.
The microcontroller used acts as a standard keyboard, so it should work on every computer.
With this receiver you can use a remote control to control things on your computer.

I made this instructables based on one of my previous instructables. The difference is that it's a lot smaller and it acts as a keyboard, so you don't need extra software on your PC.

Let's get started!

Teacher Notes

Teachers! Did you use this instructable in your classroom?
Add a Teacher Note to share how you incorporated it into your lesson.

Step 1: Parts

For this instructables you'll need a few parts:

A digispark(clone) (gearbest)
A 38kHz IR receiver (ebay)
A remote control

You'll also need some tools:

A soldering Iron
A PC with the arduino software installed

Step 2: Soldering the IR Receiver

First you need to bend one leg (OUT) of the IR receiver so it goes into P2 and the other legs go into 5V and GND.

After that you need to add a little piece of heat shrink (or tape) to the horizontal part of the IR receiver.

Place the IR receiver back on the digispark and solder the three legs together.

The only thing you need to do now is clip of the useless part of each leg.

Now you're done with the hardware part.

Step 3: Getting the Keycodes of the Remote

In this part you need to see what code is "connected" to every button on the Remote control. We need to do this, because every remote uses other codes for every key.

To do this, I used the setup and program of my previous instructables. I just opened the serial monitor to see which code was send. If you don't have an arduino for getting the codes, you can also use the part you just made. This is a little more difficult, but it gives you the same result.

First you need to install the digiusb drivers. Goto this link and on the right click "download zip". After you've downloaded the zip extract all the folder "DigisparkExamplePrograms-master" to any directory you like.

The goto "DigisparkExamplePrograms-master/C++/DigiUSB Windows Driver/" and click "installdriver".

After you've done that, you need to follow these instructions to install the right boards in the arduino IDE.

Now copy this code to a new arduino project and upload it to your digispark.

/*************************************
* This code is written by Laurens Wuyts
* For questions: laurens.wuyts@gmail.com
* 
* 
* Microcontroller: ATtiny85
* Dev board:       Digispark
* 
*************************************/
#include <DigiUSB.h>

uint8_t situation = 0;
uint8_t START = 0;
uint8_t x = 0;
uint8_t BIT = 0;
uint8_t Id = 0;
uint8_t Id_inv = 0;
uint8_t Data = 0;
uint8_t Data_back = 0;
uint8_t Data_inv = 0;
uint8_t Repeat = 0;
uint8_t sended = 0;

uint16_t Time_old = 0;
uint16_t Time = 0;
uint16_t TimeDelta = 0;
 
void setup(void) {
  attachInterrupt(0, IR_Read, FALLING);
  
  pinMode(1,OUTPUT);
  digitalWrite(1,LOW);

  DigiUSB.begin();
}
 
void loop(void) {
  if(sended == 1) {
    DigiUSB.println(Data_back, DEC);
    sended = 0;
  } else {
    DigiUSB.delay(10);
  }
}

void IR_Read(void) {
  digitalWrite(1,HIGH);
  Time = micros();
  if (Time_old != 0) {
    TimeDelta = Time - Time_old;
    if ((TimeDelta > 12000)&&(TimeDelta < 14000)) {
      START = 1;
      x = 0;
      situation = 1;
      Id = 0;
      Id_inv = 0;
      Data = 0;
      Data_inv = 0;
    } else if ((TimeDelta > 10000)&&(TimeDelta < 12000)) {
      situation = 2; // repeat
    } else if ((TimeDelta > 1500)&&(TimeDelta < 2500)) {
      situation = 3; //"1"
      BIT = 1;
    } else if ((TimeDelta > 1000)&&(TimeDelta < 1500)) {
      situation = 3; //"0"
      BIT = 0;
    } else situation = 5; 
    if (situation == 3) {
      if (x < 8) {
        Id |= BIT;
        if (x < 7) Id <<= 1;  
        x++;
      } else if (x < 16) {
        Id_inv |= BIT;
        if (x < 15) Id_inv <<= 1;
        x++;
      } else if (x < 24) {
        Data |= BIT;
        if (x < 23) Data <<= 1;
        x++;
      } else if (x < 32) {
        Data_inv |= BIT;
        if (x < 31) {
          Data_inv <<= 1;
        } else {
          
          /* DO SOMETHING HERE */
          sended = 1;
          
          Data_back = Data;
          Repeat = 0;
        }
        x++;
      }
    } else if (situation == 2) {
      if(Repeat == 1) {
        
        /* DO SOMETHING HERE */
        /*sended = 1;*/
        
      } else {
        Repeat = 1;
      }
    }
  }
  Time_old = Time;
  digitalWrite(1,LOW);
}

After you've done that, goto "DigisparkExamplePrograms-master/Python/DigiUSB/Windows/" and open "monitor.exe". In this window the keycode is printed when you press a button. Just note the button and then the code you see. You'll need them later on.

Step 4: Digispark Sketch

Ok now the "real" code for the Digispark.

In this code you need to add the keycodes you got in the previous step. For example if the "mute" key has code 100 you change:

#define mute	240
to
#define mute	100

!! Attention !!

When you define a new key, you can't use spaces in the name.

And for adding functions go into the loop function and add/change the key you like.

When you have any question at all, feel free to ask!

/*************************************
* This code is written by Laurens Wuyts
* For questions: laurens.wuyts@gmail.com
* 
* 
* Microcontroller: ATtiny85
* Dev board:       Digispark
* 
*************************************/

/**** Define Remote control keys ****/
#define Power     64
#define key_1     32
#define key_2     160
#define key_3     96
#define key_4     16
#define key_5     144
#define key_6     80
#define key_7     48
#define key_8     176
#define key_9     112
#define key_0     136
#define vol_up    224
#define vol_down  208
#define ch_up     72
#define ch_down   8
#define mute      240
#define next      172
#define prev      164
#define up        6
#define down      134
#define left      166
#define right     70
#define playpause 156
#define key_stop  180
/************************************/

#include "TrinketHidCombo.h"

uint8_t situation = 0;
uint8_t START = 0;
uint8_t x = 0;
uint8_t BIT = 0;
uint8_t Id = 0;
uint8_t Id_inv = 0;
uint8_t Data = 0;
uint8_t Data_back = 0;
uint8_t Data_inv = 0;
uint8_t Repeat = 0;
uint8_t sended = 0;

uint16_t Time_old = 0;
uint16_t Time = 0;
uint16_t TimeDelta = 0;
 
void setup(void) {
  /* Use INT0(P2) on the Digispark */
  attachInterrupt(0, IR_Read, FALLING);
  
  pinMode(1,OUTPUT);
  digitalWrite(1,LOW);

  TrinketHidCombo.begin();
}
 
void loop(void) {
  if(sended == 1) {
    /* Assign functions to the buttons */
    if(Data_back == vol_up) {
      TrinketHidCombo.pressMultimediaKey(MMKEY_VOL_UP);
    } else if(Data_back == vol_down) {
      TrinketHidCombo.pressMultimediaKey(MMKEY_VOL_DOWN);
    } else if(Data_back == next) {
      TrinketHidCombo.pressMultimediaKey(MMKEY_SCAN_NEXT_TRACK);
    } else if(Data_back == prev) {
      TrinketHidCombo.pressMultimediaKey(MMKEY_SCAN_PREV_TRACK);
    } else if(Data_back == key_stop) {
      TrinketHidCombo.pressMultimediaKey(MMKEY_STOP);
    } else if(Data_back == playpause) {
      TrinketHidCombo.pressMultimediaKey(MMKEY_PLAYPAUSE);
    } else if(Data_back == mute) {
      TrinketHidCombo.pressMultimediaKey(MMKEY_MUTE);
    } else if(Data_back == Power) {
      TrinketHidCombo.pressSystemCtrlKey(SYSCTRLKEY_SLEEP);
    } else if(Data_back == key_0) {
      TrinketHidCombo.pressKey(KEYCODE_MOD_LEFT_SHIFT, KEYCODE_0);
      TrinketHidCombo.pressKey(0, 0);
    } else if(Data_back == key_1) {
      TrinketHidCombo.pressKey(KEYCODE_MOD_LEFT_SHIFT, KEYCODE_1);
      TrinketHidCombo.pressKey(0, 0);
    } else if(Data_back == key_2) {
      TrinketHidCombo.pressKey(KEYCODE_MOD_LEFT_SHIFT, KEYCODE_2);
      TrinketHidCombo.pressKey(0, 0);
    } else if(Data_back == key_3) {
      TrinketHidCombo.pressKey(KEYCODE_MOD_LEFT_SHIFT, KEYCODE_3);
      TrinketHidCombo.pressKey(0, 0);
    } else if(Data_back == key_4) {
      TrinketHidCombo.pressKey(KEYCODE_MOD_LEFT_SHIFT, KEYCODE_4);
      TrinketHidCombo.pressKey(0, 0);
    } else if(Data_back == key_5) {
      TrinketHidCombo.pressKey(KEYCODE_MOD_LEFT_SHIFT, KEYCODE_5);
      TrinketHidCombo.pressKey(0, 0);
    } else if(Data_back == key_6) {
      TrinketHidCombo.pressKey(KEYCODE_MOD_LEFT_SHIFT, KEYCODE_6);
      TrinketHidCombo.pressKey(0, 0);
    } else if(Data_back == key_7) {
      TrinketHidCombo.pressKey(KEYCODE_MOD_LEFT_SHIFT, KEYCODE_7);
      TrinketHidCombo.pressKey(0, 0);
    } else if(Data_back == key_8) {
      TrinketHidCombo.pressKey(KEYCODE_MOD_LEFT_SHIFT, KEYCODE_8);
      TrinketHidCombo.pressKey(0, 0);
    } else if(Data_back == key_9) {
      TrinketHidCombo.pressKey(KEYCODE_MOD_LEFT_SHIFT, KEYCODE_9);
      TrinketHidCombo.pressKey(0, 0);
    } else if(Data_back == up) {
      TrinketHidCombo.pressKey(0, KEYCODE_ARROW_UP);
      TrinketHidCombo.pressKey(0, 0);
    } else if(Data_back == down) {
      TrinketHidCombo.pressKey(0, KEYCODE_ARROW_DOWN);
      TrinketHidCombo.pressKey(0, 0);
    } else if(Data_back == left) {
      TrinketHidCombo.pressKey(0, KEYCODE_ARROW_LEFT);
      TrinketHidCombo.pressKey(0, 0);
    } else if(Data_back == right) {
      TrinketHidCombo.pressKey(0, KEYCODE_ARROW_RIGHT);
      TrinketHidCombo.pressKey(0, 0);
    }
    sended = 0;
  } else {
      TrinketHidCombo.poll();
  }
}

/* Read the IR code */
void IR_Read(void) {
  digitalWrite(1,HIGH);
  Time = micros();
  if (Time_old != 0) {
    TimeDelta = Time - Time_old;
    if ((TimeDelta > 12000)&&(TimeDelta < 14000)) {
      START = 1;
      x = 0;
      situation = 1;
      Id = 0;
      Id_inv = 0;
      Data = 0;
      Data_inv = 0;
    } else if ((TimeDelta > 10000)&&(TimeDelta < 12000)) {
      situation = 2; // repeat
    } else if ((TimeDelta > 1500)&&(TimeDelta < 2500)) {
      situation = 3; //"1"
      BIT = 1;
    } else if ((TimeDelta > 1000)&&(TimeDelta < 1500)) {
      situation = 3; //"0"
      BIT = 0;
    } else situation = 5; 
    if (situation == 3) {
      if (x < 8) {
        Id |= BIT;
        if (x < 7) Id <<= 1;  
        x++;
      } else if (x < 16) {
        Id_inv |= BIT;
        if (x < 15) Id_inv <<= 1;
        x++;
      } else if (x < 24) {
        Data |= BIT;
        if (x < 23) Data <<= 1;
        x++;
      } else if (x < 32) {
        Data_inv |= BIT;
        if (x < 31) {
          Data_inv <<= 1;
        } else {
          
          /* DO SOMETHING HERE */
          sended = 1;
          
          Data_back = Data;
          Repeat = 0;
        }
        x++;
      }
    } else if (situation == 2) {
      if(Repeat == 1) {
        
        /* DO SOMETHING HERE */
        sended = 1;
        
      } else {
        Repeat = 1;
      }
    }
  }
  Time_old = Time;
  digitalWrite(1,LOW);
}

Now upload the sketch to the digispark. Unplug and replug it into your computer, wait ~5sec and enjoy your remote control.

Step 5: Resume

In this tutorial, I showed how to make a low cost USB remote control.

I hope you liked it, please add suggestions what you want to see next, questions or improvements below.

Laurens

5 People Made This Project!

Recommendations

  • CNC Contest

    CNC Contest
  • Make it Move

    Make it Move
  • Teacher Contest

    Teacher Contest

48 Discussions

0
None
Alex Lillybear

23 days ago

Does anyone else know how to get rid of the repeat of last pushed button when pushing new button?
Quite annoying when I paus playback and then turn off the TV, the receiver repeats my paus command and turns on the video/netflix again (among other problems).
Any hints would be greatly appreciated.
Thanks!

(can't get Juan Antonio's code to work properly)

0
None
Juan AntonioP9

7 months ago

Thank you very much. Your instructions allowed me to build my own IR receiver. Anyway, after some days using it i saw a problem (maybe due to the codes my remote was sending). Some times, after pressing a key and then in a short time another different key, the second key was processed as a repetition of the first key. I tried changing the timing parameters but could not find a solution. As I could not find where the problem came from I ended looking at the NEC protocol and rewriting a part of the algorithm. Here is my code:

uint8_t STEP = 0;
uint8_t BIT = 0;
uint8_t Id = 0;
uint8_t Id_inv = 0;
uint8_t Data = 0;
uint8_t Data_inv = 0;
uint8_t Data_back = 0;
uint8_t sended = 0;

uint32_t Time_old = 0;
uint32_t Time = 0;
uint32_t TimeDelta = 0;
void loop(void) {
if (sended == 1) { // Key press
// Control all keys
sended = 0;
} else if (sended == 2) { // Repetition
// Control keys that you want to have repetitions
sended = 0;
} else {
TrinketHidCombo.poll();
}
}
void IR_Read(void) {
Time = micros();
TimeDelta = Time - Time_old;

if (TimeDelta > 100000 || (TimeDelta > 12500)&&(TimeDelta < 14500)) {
STEP = 0;
}
STEP++;
if (STEP == 1) {
if ((TimeDelta > 12500)&&(TimeDelta < 14500)) {
Id = 0;
Id_inv = 0;
Data = 0;
Data_inv = 0;
} else {
STEP = 0;
}
} else if((STEP>=2) && (STEP<34)) { //Accumulate the bit values between 0-31.
if ((TimeDelta > 1750)&&(TimeDelta < 2750)) BIT = 1;
else if ((TimeDelta > 625)&&(TimeDelta < 1625)) BIT = 0;
else STEP = 0;
if (STEP < 10) {
Id |= BIT;
if (STEP < 9) Id <<= 1;
} else if (STEP < 18) {
Id_inv |= BIT;
if (STEP < 17) Id_inv <<= 1;
} else if (STEP < 26) {
Data |= BIT;
if (STEP < 25) Data <<= 1;
} else {
Data_inv |= BIT;
if (STEP < 33) Data_inv <<= 1;
else {
if (Data^Data_inv == 0xFF && Id^Id_inv == 0xFF) {
Data_back = Data;
sended = 1;
} else {
STEP = 0;
}
}
}
}
else if ((TimeDelta > 40100)&&(TimeDelta < 42100)) {} // Ignore the First repetition block
else if ((TimeDelta > 10250)&&(TimeDelta < 12250)) {} // Ignore Begin of new repetition block
else if ((TimeDelta > 95750)&&(TimeDelta < 99750)) // End of a repetition block
{
// Repeat
sended = 2;
} else {
STEP = 0;
}
Time_old = Time;
}

1 reply
0
None
Alex LillybearJuan AntonioP9

Reply 4 weeks ago

I'm having this problem as well. I'm not really sure how to interpret your code.
Where you've put "//Control all keys", do I write every button keypress here, the ones I want to repeat as well as the ones that shouldn't repeat?
And then where you've written "// Control keys that you want to have repetitions". Do I put keys that should be able to repeat here? Like up or down for scrolling through lists?
If you still have your sketch maybe it would be possible for you to paste it here? So that we can see an example?
Thank you in advance!

0
None
MarkH43

6 months ago

Hi,. Great little project, many tx for sharing..... but one question I have is how can I produce the 'Ctrl, Alt, Left/Right Arrow',.. to mimic the Ubuntu screen switch.. within/from the code..
I have tried the following,.. but this does not generate the expected result:-
} else if (Data_back == ScreenRt) {
TrinketHidCombo.pressKey(0, KEYCODE_LEFT_CONTROL, KEYCODE_LEFT_ALT, KEYCODE_ARROW_RIGHT);
TrinketHidCombo.pressKey(0, 0);

thankyou...

0
None
ejohn

8 months ago

after getting the codes, I want to make a sender for other usage.
Any ideas? help

0
None
happohiken

9 months ago

Hello. Thank you for sharing this fine post.
I'd like to ask you for help. I've followed your instructions (installed drivers and so), but when I open monitor.exe, I get a popup with the following message: "no digiusb device detected". Do you know what could I do?
Thank you very much, best regards

1 reply
0
None
ejohnhappohiken

Reply 8 months ago

I got the same message because I choose the wrong board
"DigiSpark Pro (Default 16MHz)"

0
None
Pault274

2 years ago

Hi, Great instructable working like a charm. Having one problem. If I press a button to long it executes twice. Is there a way to increase a time out between button presses?

Greetings

4 replies
0
None
Bez4Pault274

Reply 10 months ago

I have the same problem. Is there a fix? I made this over a year ago and finally got it working but I have to press every button very briefly.

0
None
Laurens-WuytsBez4

Reply 10 months ago

You could try to disable the repeat functionality, but then it will only send a key every press and won't send again when you press long on a button.

To do this, you could delete/comment out this line:

else if (situation == 2) {

if(Repeat == 1) {

/* DO SOMETHING HERE */

// sended = 1; // << Comment out this line
} else {

Repeat = 1;

}

}

Laurens

0
None
Bez4Laurens-Wuyts

Reply 10 months ago

Thanks for replying Laurens. I figured out a similar work around just after I replied, just had to look at the code closer. Unfortunately that fix doesn't work well for volume up an down so I added "delay(185);" after every keypress except volume up and down and it now works really well. This delay works well for me in Kodi on an Rpi3.

0
None
Laurens-WuytsBez4

Reply 10 months ago

Ah, its good to hear that you got it working the way you want it. :).
Thanks for sharing your workaround for other people with the same problem!

Laurens

0
None
mark angelob3

1 year ago

Sir can I ask what will I exactly do with the monitor.exe when i try to open it, Error because i need python. And How many source code I need to compile on my digispark?

0
None
DylanD581

1 year ago

After coding this to work with an Apple Remote... every time I plug it into a different computer, do I have to download a river for it to work?

0
None
ПавелГ13

1 year ago

Hi! Please help!

Do I need a Python for work?

I don't understand where i can find this - "DigisparkExamplePrograms-master/Python/DigiUSB/Windows/" and open "monitor.exe" . Is it a python?

0
None
Alex Lillybear

2 years ago

Hi Laurens, I know it's been a while since you made this instructionable, but I'll try asking anyway.

I'm
trying to get my Harmony 525 to play nicely with this reciever, byt I
can't for the life of me get the monitor to register events. I've tried
by adding known NEC protocol devices to the Harmony, but no luck at all.
I was thinking maybe you could point me in the right direction?

Thanks for an exellent project!

1 reply
0
None
Alex LillybearAlex Lillybear

Reply 2 years ago

Nevermind, it's working now. Now I jest need to find a compatible remote with most of the functions I need. So far, Andersson R1 surround receiver has given me the most options on my Harmony 525. Thanks again!

0
None
Magicoolme

2 years ago

Hi, I build it but it works only if I press the key on the remote repeatedly very very very fast. What can it be?

0
None
sfriziona

2 years ago

Hi,

thanks for sharing this project, I followed instructions and found very easy.

Now
I got no experience with arduino but neeed to add some key , could someone point me in the right direction to find out how
to remap and assign new key and functions?

I got a programmable harmony remote and try to get it work with a raspberry Pi 3 with libreelec.

Thanks....