TinyPCRemote – An ATtiny85 Based Infrared PC remote control

Here’s a cheap way to build your own fully customisable infrared PC remote control. If you already have a suitable infrared remote control going spare you can build one of these for under £4, it will allow you to use most infrared remote controls to issue keyboard commands (single characters or a string) on your PC. Using a surplus remote control it could be used as a cheap media centre remote control with XBMC etc. or would be great for causing some mischief by covertly taking control of someone’s computer. I’ve tested it on several Linux and Windows boxes and one Mac and it has worked fine on them all so far.

At the heart is an 8 pin ATtiny85 microcontroller running at 16MHz using the internal oscillator with a Vishay TSOP31238 IR sensor handling the IR reception and USB implemented with V-USB. Each remote control button can trigger a single keyboard character or series if characters as well as meta keys such as shift and alt.

I couldn’t find any guides for using V-USB on the ATtiny85 under the Arduino environment so have detailed what I did in full here. Other than changing the default PIND, pin and timer settings the key seems to be that when using the internal oscillator like I am here it needs to be calibrated for each individual chip as the timing for USB is so critical.

Schematic and Stripboard layout

Here is the schematic for the USB infrared receiver:

and a stripboard layout:

 

Parts List:
Atmel ATtiny85-20PU Microcontroller
8 pin DIP socket
Vishay TSOP31238 IR sensor
100nF ceramic capacitor
1 x 2K2 resistor
2 x 68R resistors
2 x 3.6V Zener diodes (must be 0.5W or less)
Through hole male USB A connector
Stripboard, 18 holes by 6 rows

 

Code
You can download my TinyPCRemote code for the ATtiny85 on Github here.
You will also need: vusb-for-arduino and Tiny-tuner

 

Getting your remote control codes
To get the codes from your chosen remote control I’ve provided a sketch in the above repository that can be run on an Arduino or compatible board which will output the code on the serial monitor as each button is pressed, it’s designed so that you can just plug the IR sensor straight into the headers across Ground, D13 and D11 as shown below:

Once the sketch is loaded on the Arduino open the serial monitor at 9600 baud and press each button on your remote control in turn and you will see the corresponding code output on the serial monitor, don’t worry if the code repeats for each button press. Simply copy and paste the codes into the TinyPCRemote sketch and define the key/s that you want it to press when detected, replacing the existing definitions and duplicating as necessary for as many buttons as you need. There will be an upper limit as to how many can be configured, limited by flash and RAM, I haven’t tested to find the limit but it should allow for plenty of codes.

 

V-USB Configuration
The USB side of things is handled by V-USB, a very useful open source software-only implementation of the USB 1.1 standard for Atmel AVRs created by Objective Development. I used the vusb-for-arduino variant.

Unzip the file and copy the UsbKeyboard directory to your Arduino library location and restart the Arduino IDE if it was running. Now you need to edit a couple of files to change the port and pin numbers to be compatible with the ATtiny85.

Firstly edit usbconfig.h and under “Hardware Config” change

#define USB_CFG_IOPORTNAME D
to
#define USB_CFG_IOPORTNAME B

and

#define USB_CFG_DMINUS_BIT 4
to
#define USB_CFG_DMINUS_BIT 0

and under “Optional Hardware Config” change:

#define USB_CFG_PULLUP_IOPORTNAME D
to
#define USB_CFG_PULLUP_IOPORTNAME B

Note that we’re not actually connecting the pullup via a pin but this still needs to be set to a valid port in order to compile.

Optionally you can also change the manufacturer and device name in the following defines:

#define USB_CFG_VENDOR_NAME
#define USB_CFG_DEVICE_NAME

Finally, in UsbKeyboard.h change:

PORTD = 0; // TODO: Only for USB pins?
DDRD |= ~USBMASK;
to
PORTB = 0; // TODO: Only for USB pins?
DDRB |= ~USBMASK;

 

Programming the ATtiny85
Programming the ATtiny85 can be accomplished via an Arduino and the ArduinoISP sketch that is included in the examples section of the Arduino IDE or a dedicated ICSP device.

To program the ATtiny85 via an Arduino connect it as follows:

Arduino ATtiny85
D13 Pin 7
D12 Pin 6
D11 Pin 5
D10 Pin 1
5V Pin 8
GND Pin 4

 

Calibrating the oscillator
The timing for USB is critical and the oscillator for each individual ATtiny85 chip will almost certainly need to be calibrated, to do this download TinyTuner from here and put it in your Arduino libraries directory. You are also going to need an FTDI adapter or some other sort of serial converter so you can read the output.
Connect your ATtiny85 up to the Arduino and use the burn bootloader function of the Arduino IDE to set it to run at 8MHz by choosing the “ATtiny85 @ 8MHz (internal oscillator;BOD disabled)” board setting under Tools > board and then using the Tools > Burn Bootloader option. Note that as with the ATtiny84 this doesn’t actually burn a bootloader, all we are doing is setting the relevant fuses to configure the microcontroller, in this case we are temporarily setting it to run at 8MHz as tiny-tuner won’t run at our final 16MHz speed.
Load the “Interactive_to_Serial_with_Details” TinyTuner sketch from the tiny-tuner examples onto the ATtiny85, connect PB3 (pin 2) to RXD on the FTDI adapter and PB4 (pin 3) to TXD as well as 5V and ground.

Now open a terminal app on your PC and connect to the port of the serial adapter, eg. on linux “miniterm.py /dev/ttyUSB1“, reset the ATtiny85 and you should get a welcome message, now repeatedly press x slowly (once a second or so is fine) until you get a result like:

Copy-and-paste the following line of code at the top of setup…
OSCCAL = 0x9C

Copy the result from tiny-tuner into the TinyPCRemote sketch replacing the OSCCAL = 0x9C; line in setup() as appropriate.

 

Final Setup
Once you have entered the OSCCAL calibration value and your remote control codes along with the resulting keys you want to be entered  then you are ready to load the TinyPCRemote sketch onto the ATtiny85.

First use the burn bootloader function again to set the ATtiny 85 to 16MHz by using the “ATtiny85 @ 16MHz (internal PLL;4.3V BOD)” board setting then upload the sketch in the normal manner.

If you are testing it on a breadboard as I did when developing it then you will probably had to disconnect the connections to the Arduino for the USB to work, I got away with just disconnecting the SCK connection (wire from Arduino D13 to ATtiny pin 7/PB2).

If you now plug the the TinyPCRemote into a USB port hopefully pressing the remote control buttons will result in the corresponding characters appearing on your screen as if typed on your keyboard.

If not run dmesg and look for any errors, if everything is working you should see something like the following (I don’t know how you can view similar logs on Windows or Mac):

input: zorg.org TinyPCRemote as /devices/pci0000:00/0000:00:13.5/usb1/1-9/1-9.2/1-9.2.1/1-9.2.1:1.0/input/input18
generic-usb 0003:4242:E131.0006: input,hidraw2: USB HID v1.01 Keyboard [zorg.org TinyPCRemote] on usb-0000:00:13.5-9.2.1/input0

Note that I’ve changed the manufacturer and device names in usbconfig.h to be zorg.org and TinyPCRemote respectively.

If you get device descriptor read errors like:

usb 1-9.2.1: new low-speed USB device number 28 using ehci_hcd
usb 1-9.2.1: device descriptor read/64, error -32

then your computer is seeing the device but you probably have a timing problem. Make sure your ATtiny is set to 16MHz using the internal PLL and that you have calibrated it correctly using tiny-tuner.

 

17 comments on this post.
  1. Sam:

    Thanks a million, I was looking for this everywhere. If I wanted to use this with a crystal, what changes in software?

    Sam

  2. Nathan Chantrell:

    Just removing the OSCCAL line should be enough, no need to calibrate if using a crystal but everything else should be fine as is. Just put a crystal and bypass caps on and use the correct “burn bootloader” option to set the fuses.

    Cheers,
    Nathan

  3. Carl:

    Would this work on an arduino uno?

  4. Nathan Chantrell:

    Yes, you would still have to add the USB connector/diodes/resistors though, you can’t use the Uno USB connector for V-USB.

    The connection shown on the schematic going from D- on the USB plug to pin5/PB0 on the ATtiny would have to go to D2 on the Arduino instead and the one going from D+ to pin7/PB2 would have to go to D4. You wouldn’t have to make the changes in usbconfig.h or do the calibration.

    In the main code you would need to drop the OSCCAL = 0x9C; line and change TIMSK&=!(1<

    and change:
    #define IRpin_PIN PINB
    #define IRpin 4

    to

    #define IRpin_PIN PINB
    #define IRpin 3

    and

    pinMode(4, INPUT); // Make sure IR pin is set as input

    to

    pinMode(11, INPUT); // Set IR pin as input

    and put the IR receiver across ground, D13 and D11 as shown in picture for the code learner above.

    That should do it.

  5. Eric Söderman:

    I really appreciate your detailed blog post. Thanks!

  6. smching:

    I want to use a crystal for this circuit, but I have a question.

    According to your circuit, the TSOP31238 IR is connected to Tiny85 Pin3, this will occupied the pin for crystal. Based on Tiny85 datasheet, the crystal must connect to Pin2 & Pin3 of Tiny85.

    Should I connect the TSOP31238 IR to Pin6 of Tiny85 since Pin6 is not using currently.

  7. Nathan Chantrell:

    Yes, pin 6 would be fine, note that pin 6 is PB1/Arduino D1 so in the code you would have to change the 4 to 1 in these 2 lines:


    #define IRpin 4

    pinMode(4, INPUT);

  8. smching:

    Thank you very much. This is what I’m looking for my project.

  9. oliver:

    The tinycodereader always assumes that pin 3 (digital pin 11) is used. Thus it only works on the Uno’s. On the ATMEGA 2560 Digital pin 11 is actually mapped to pin 5. Why digitalread(11) wasn’t used I don’t know. But in its current form, IRPin 3 needs to be changed to IRPin 5 for the 2560. Only took me 2 hrs to figure out why it wasn’t working :)

  10. Nathan Chantrell:

    Glad you sussed it. If I recall correctly there are timing issues with digitalRead and infrared, doing a direct read is faster.

  11. oliver:

    Also took me a little while to figure out that I had to install the attiny libs into my sketchbook’s hardware directory to get those boards to show up.

    Unfortunatly on the current Ubuntu LTS (12.04) tinytuner fails to compile :(

  12. Nathan Chantrell:

    What’s the error? I was using 12.04 (with Arduino 1.0.1) when I did this, just checked and it is still working on 12.10 and Arduino 1.0.3.

  13. oliver:

    Well using a 12 MHz crystal now so it’s ok (I will try compiling it again later), but alas. I think It is using the crystal right and V-usb is configured right, it does show up as a usb keyboard with my usbid name.

    However I get no keys from it. I’ve added the loop to always print KEY_A initially (so loop() { usb.update(); sendKey(KEY_A); but then it doesn’t even get recognized anymore. So it’s very picky as to when sending of keys is allowed. I quickly checked with a scope and the crystal is nicely resonating and the IR receiver is nicely sending pulses on input (also the keyscanner program ran just fine on the atmega of course).

    So kinda puzzled as to why it won’t work on the tiny. Gotta figure out a way to output some debugging first :)

  14. Tom Ellingham:

    Fantastic write up. Nathan, fancy making the USB stick for me? I’m happy to do the programming! This would be so handy in my line of work…

  15. Temoor:

    Hi folks,

    Is there a way to make Attiny85 emitter that complements this little gadget? I just need to send a few inputs such as scrolling with a mouse but using IR instead. Is this possible?

  16. P Mehta:

    What other AVR can be used instead of ATTiny85? We have difficulty procuring ATTiny85 in India. ATMega8L, ATMega16A, ATMega32A, ATMega168, ATTiny2313A-PU are the only available options. Thanks in advance and need not to mention that it was indeed a great article!

  17. Nathan Chantrell:

    @P Mehta It could be modified to work with anything that can be loaded with an Arduino bootloader so any of those should be possible. I’d probably use the 2313 as it is smallest and can be used with the arduino-tiny bootloader.

    @Temoor Yes, hardware wise you would just need to replace the IR receiver with an IR emitter and resistor. There is some code here using a modified version of Ken Shirriff’s IR library that works on the ATtiny and could be used as a basis to build a transmitter from.
    https://github.com/TKJElectronics/ATtinyRemote
    I used Ken’s library when I made my web based IR remote control here:
    http://nathan.chantrell.net/20120119/building-a-web-based-infrared-remote-control/

Leave a comment





Notify me of followup comments via e-mail. You can also subscribe without commenting.

By submitting a comment you agree that it can be reproduced under the same licensing terms as the rest of the content on this site.