Introduction: ATtiny85 IR USB Receiver

Hello makers!
this is an instructable to build a working USB IR receiver using an Attiny85 microcontroller.
I started this project to overcome the lack of support (at least complete support) for some IR remotes in the GNU/Linux OS. Following this instructions you could build a programmable USB IR receiver that works with any IR remote for a few bucks.

First of all, this instructable wouldn't exists without the hard work of the people that created the libraries that I use here:

Sometimes is not easy to find the right owner of a library, so in case I made a mistake, please leave a comment and I would solve the issue ASAP.

This guide exists because I didn't find a complete tutorial/guide working out of the box (it may exist, but I couldn't find it) so I gathered all the info available on the web and after a good amount of trials and errors I came up with a complete guide to build a working USB IR receiver that actually works pretty well.

The main sources of information that I have followed:

Step 1: Some Considerations

    • I don't own an AVR ISP programmer and I don't really fancy buying one so I have used an Arduino to program the attiny85
    • I don't care about any other OS than GNU/Linux so I don't know if this is gonna work otherwise.
    • there are other IR libraries but I couldn't make them work not even with an arduino. Consider though that I started with a limited knowledge about IR libraries. Maybe I could make them work now after the experience acquired dealing with a fair amount of issues. Anyway, I was lost and desperate before finding the library that Seejaydee provided and I have used that ever since (many thanks man!).
    • There are other hardware configurations, but I have only used the one that uses 5V to power the attiny85 and two 3.6V 0.5W zener diodes to clamp the voltage of the data lines, it works out of the box so I didn't mess with other configurations.
    • You can use a 16Mhz crystal or you can use the tinytuner library to calibrate the internal clock of your attiny85. I strongly advice the use of the crystal, it's much more stable and probably will spare you a lot of headaches.
    • I'm using here two different bootloaders for the attiny85:

    a) Rowdy Dog Software version, it has integrated a serial interface that is very cool and is very small so you have more space for your program and other libraries. The problem is that for some reasons even though it works pretty well, after some time the usb device got disconnected (you can find the issues with the command dmesg). I don't know if this is a problem of the core or a mixed combination of the core plus the chosen libraries so after a while I decided to use this core just to decode the remote keys and calibrate the clock (when not using a 16Mhz crystal). After that, I just burn the Mellis bootloader and upload the definitive sketch that doesn't use the serial interface.

    b) Mellis version, stable bootloader, I have used this in many projects. I would've used this bootloader always if it had included a serial interface. I use this core in the final sketch after decoding all the keys on my remotes.

    Step 2: Let's Start With the Hardware

    Tools you need:

    • an arduino compatible board
    • a serial to usb adapter to decode your remote keys (just use an FT232RL)
    • a PC with GNU/Linux installed and the arduino IDE properly configured, I'm using arduino IDE 1.8.0
    • an IR remote to test your device (even a crappy one like those found in arduino starter kits will work)
    • a multimeter to debug your board (I hope you won't need it, good luck!)

    The list of materials:

    • 1 attiny85
    • 2 68R resistors
    • 1 1.5K resistor
    • 1 4.7K resistor
    • 1 16Mhz crystal
    • 1 22pF capacitor
    • 1 0.1uF capacitor
    • 1 10uF capacitor
    • 2 3.6V 0.5W zener diodes
    • 1 USB type A male connector
    • 1 strip pin with 6 pins to program and debug the board.
    • 1 IR sensor TSOP31238
    • a lot of coffee to keep you awake

    Before soldering the definitive board, you'd probably want to make a breadboard prototype for testing purposes, following the schema attached to this instructable should be enough to build it up.

    To connect the attiny85 to the PC, the final design uses an USB type A connector that is soldered into the board, but for the prototype you will need to make an USB cable that you can connect to a breadboard:

    Solder into a small piece of perfboard 4 pins, then cut an old USB cable and solder the pins to 4 of the wires inside the usb cable:

    • red is VCC (5V)
    • black is GND
    • white is D-
    • green is D+

    Keep everything together with hot glue.

    Now we need to connect the ISP programmer (Arduino), the USB to serial adapter (FT232RL) and the IR sensor to the attiny85.

    You can leave connected all together so you would be able to burn different bootloaders, load sketches and check out the serial port without changing wires,

    To do so, connect everything following these instructions:

    ISP programmer (Arduino):
    this allows us to burn bootloaders and load sketches

    • attiny85 PB0 (pin5) to pin11 (MOSI) in arduino
    • attiny85 PB1 (pin6) to pin12 (MISO) in arduino
    • attiny85 PB2 (pin7) to pin13 (SCK) in arduino
    • attiny85 RESET (pin1) with pullup (4.6k to VCC) to pin10 in arduino
    • attiny85 VCC to 5V in arduino
    • attiny85 GND to GND in arduino

    usb to serial adapter (FT232RL) :
    this allows us to check the serial port

    • attiny85 PB0 (pin5--> RX) to TX in the FT232RL
    • attiny85 PB2 (pin7--> TX) to RX in the FT232RL
    • attiny85 GND (pin4) to GND on the FT232RL
    • since the attiny85 is already powered by the arduino you don't need to connect the 5v on the FT232RL, otherwise connect: attiny85 VCC (pin8) to 5V on the FT232RL

    usb to serial adapter (FT232RL) only for the clock calibration
    (just for the bootloader "ATtiny85 @ 8MHz (internal oscillator;BOD disabled)")

    • PB4 (pin3--> RX) to TX in the FT232RL attiny85
    • PB3 (pin2--> TX) to RX in the FT232RL attiny85
    • GND (pin4) to GND on the FT232RL
    • since the attiny85 is already powered by the arduino you don't need to connect the 5v on the FT232RL, otherwise connect: attiny85 VCC (pin8) to 5V on the FT232RL

    If you use a 16Mhz crystal, connect it to the Attiny85 pins PB3 (pin2) and PB4 (pin3) and connect each pin to GND as well through a 22pF cap each.

    Filter Attiny85 VCC with a 0.1uF and 10uF capacitors connecting them in parallel to GND

    Connect the IR sensor output pin to the attiny85 PB1 (pin6), power it up.

    Build and connect the usb interface:

    • GND (black wire): connect it to the common GND (all grounds are connect together)
    • D- (white wire) connected to attiny85 PB0 (pin5) through a 68R resistor, connect it also to ground through a 3.6V 0.5W zener and pull it up to VCC with a 1.5K resistor
    • D+ (green wire) connected to PB2 through a 68R resistor, connect it to ground through a 3.6V 0.5W zener
    • 5V, you can leave it unconnected since everything is powered up by the Arduino at this stage, otherwise connect it to the attiny85 VCC

    The zener diodes are connected so that the anodes are tied to GND and the cathodes are connected to the data lines D+ and D-.

    Step 3: Final Design

    For the final design you could use perfboard with through hole components or etch your own board and use smd components. To learn how to etch a board, just google it, there are awesome tutorials available online.

    I have etched my own board and I'm very happy with the final results (small, stable and robust board).
    Yeah, I know that the cut sucks, but I couldn't use any power tool so late in the night and I just cut the board with my tin snip scissors.

    By the way, the traces on the images are not bare copper, they have been treated with a nasty chemical that slightly tins the copper (it is suspected to induce cancer, so use it with great care, latex globes and a dust mask):
    http://www.ebay.com/itm/1-pz-A2207-Preparato-chimico-agente-di-stagnatura-90g-TELSTORE/152106663870

    Use the schematics above to design your layout or you can just use my pcb footprint to etch your board.

    Step 4: Dealing With the Software

    The circuit in this project is very easy, the software instead requires a bigger effort.

    We need at least 2 libraries (one more if you are not using a crystal) plus 2 bootloaders to make this work. When I started this project I tested some libraries, sometimes they didn't work and many times they were just not configured to work with an Attiny85 out of the box (I didn't know that yet). Then I did find issues with the libraries / bootloaders overlapping interrupts. Finally I had to deal with a fair amount of errors when I connected the final circuit to my PC.
    I didn't have this guide though, so I think you would be all right, just follow the steps in this instructable, if you do that without making mistakes you should be fine :)

    We need now to install and configure a few libraries:

    • v-usb for arduino library: this library allows the microcontroller to be recognized by the PC as a HID USB Keyboard, and we'll use it to send key strokes to the PC. This library needs some changes to be compatible with the attiny85
    • tinytuner library only if you won't use a 16Mhz crystal. You will need then to calibrate the internal clock of the microcontroller. This library works out of the box.
    • Attiny-IR-library to interact with the IR sensor. This library works out of the box.

    We need also 2 bootloaders:

    • Dog Software version, with the serial interface available. This bootloader needs a small tweak to work with the attiny85 as it uses the timer1 for the millis() function and will not work with the IR library. We need to change the timer to timer0.
    • Mellis version, stable bootloader that we will use in the final stage. This works out of the box.

    Step 5: Installation and Configuration of the V-usb Library

    Download the library from https://code.google.com/archive/p/vusb-for-arduin...
    Unzip the file and and copy the folder libraries/UsbKeyboard into your sketchbook libraries folder.

    Now you need to edit a couple of files to be compatible with the ATtiny85 (it is configured to work with arduino):

    A) edit usbconfig.h:

    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

    under "Optional Hardware Config" change:

    #define USB_CFG_PULLUP_IOPORTNAME D
    to
    ##define USB_CFG_PULLUP_IOPORTNAME B

    To create a full "boot compliant HID" specification (otherwise no multimedia keys will work), change also:

    #define USB_CFG_INTERFACE_SUBCLASS 0 // Boot
    to
    #define USB_CFG_INTERFACE_SUBCLASS 0x01 // Boot

    and

    #define USB_CFG_INTERFACE_PROTOCOL 0 // Keyboard
    to
    #define USB_CFG_INTERFACE_PROTOCOL 0x01 // Keyboard

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

    #define USB_CFG_VENDOR_NAME

    #define USB_CFG_DEVICE_NAME

    B) edit UsbKeyboard.h:

    change:

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

    to

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

    To allow keycodes further than 101 change also:

    0x25, 0x65, // LOGICAL_MAXIMUM (101)
    to:
    0x25, 0xE7, // LOGICAL_MAXIMUM (231)

    and

    0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
    to:
    0x29, 0xE7, // USAGE_MAXIMUM (Keyboard Application)

    You may need to edit also these 3 files:

    usbdrv.h
    usbdrv.c
    UsbKeyboard.h

    and everytime you see PROGMEM add "const" before the variable type name
    (ex: PROGMEN char usbHidReportDescriptor[35] ==> PROGMEM const char usbHidReportDescriptor[35])

    If this is not clear visit http://forum.arduino.cc/index.php?topic=391253.0#...

    You can avoid all this changes if you just download the library attached (I made all this changes myself) and just extract it inside your sketchbook libraries folder:

    UsbKeyboard configured for attiny85

    Edit: recently I have discovered that Alejandro Leiva (https://github.com/gloob) has been taken care of this library and seems to work well as well. You can also try his version with the necessary changes that I made to make it work with the attiny, so if you want to check this out just extract it inside your sketchbook libraries folder.

    UsbKeyboard configured for attiny85 (Alejandro Leiva version)

    Step 6: Installation of the Attiny-IR and Tinytuner Libraries

    A) Attiny-IR library:

    download it from
    https://drive.google.com/open?id=0B_w9z88wnDtFNHlq...
    then unzip it into your sketchbook libraries folder.

    B) Tinytuner library:

    This is only needed if you are not using a 16Mhz crystal, but believe me, even though it works also without the crystal, it is much more stable with it and they cost a few cents, so keep it simple, use a crystal and skip this library.

    Not convinced yet? ok, download the library from
    https://storage.googleapis.com/google-code-archive...
    then unzip it into your sketchbook libraries folder.

    We are done with the libraries, now we move on to install the bootloaders.

    Step 7: Installation and Configuration of the Bootloaders

    We are going to install two bootloaders the Mellis one is according to my experience more stable and we will use it in the final sketch. The other one developed by Rowdy Dog Software is an awesome core, very small and with an integrated serial interface available, but my remote crashed after some time with it so we will use this bootloader just to calibrate the attiny85 internal clock and to decode our remote buttons.

    I know that there are available libraries to give the attiny85 serial capabilities, but then you will need to tweak the libraries that use the serial object...I like better this procedure.

    Let's start with the installation:

    A) Mellis bootloader:

    just open the Arduino IDE preferences and add in the "Additional Boards Manager URLs:

    https://raw.githubusercontent.com/damellis/attiny/ide-1.6.x-boards-manager/package_damellis_attiny_index.json

    Then open the Arduino IDE boards manager and search for attiny, install the boards from Mellis.
    Now you should see the Arduino ID the ATtiny25/45/85 and ATtiny24/44/84 boards.

    B) Rowdy Dog Software tiny bootloader:

    download the bootloader from
    https://storage.googleapis.com/google-code-archive...

    Unzip the file and copy the tiny folder inside your sketchbook/hardware (create this folder if it do not exists yet). then move to the folder sketchbook/hardware/tiny/avr/ and:

    1) copy the file Prospective Boards.txt into the file boards.txt

    2) edit the file platform.txt and make some changes:

    Uncomment the variable compiler.path and leave it pointing to the folder hardware/tools/avr/bin/ inside your arduino installation folder:

    compiler.path={PATH_TO_YOUR_ARDUINO_FOLDER}/hardware/tools/avr/bin/

    change also
    compiler.S.flags=-c -g -assembler-with-cpp
    to
    compiler.S.flags=-c -g -x assembler-with-cpp

    Then change the following variables making sure everything is in its place (those files must exist, otherwise point the variables to the right paths):

    tools.avrdude.cmd.path={runtime.ide.path}/hardware/tools/avr/bin/avrdude

    tools.avrdude.config.path={runtime.ide.path}/hardware/tools/avr/etc/avrdude.conf

    tools.avrdude.cmd.path.linux={runtime.ide.path}/hardware/tools/avr/bin/avrdude

    tools.avrdude.config.path.linux={runtime.ide.path}/hardware/tools/avr/etc/avrdude.conf

    3) edit the file cores/tiny/core_build_options.h and change:

    #define TIMER_TO_USE_FOR_MILLIS 1
    to
    #define TIMER_TO_USE_FOR_MILLIS 0

    This is very important, otherwise the IR receiver will output zeros for every button. This statement configures the timer0 for the millis() function leaving the timer1 available to the IR library. The final sketch will disable the timer0 anyway so you won't have available neither millis() and delay() functions. You may have available delayMicroseconds() and micros() functions instead.

    This bootloader is minimal, but has included Serial object support:

    Attiny85 PB2 (pin7) is TX and PB0 (pin5) is RX

    You can have a configuration with the ISP programmer (arduino) and the serial to usb adapter connected at the same time so you don't need to change wires too often:

    Now we have both the libraries and the bootloaders installed and properly configured, the hardest work is completed and we can start testing things up.

    Step 8: Burning Bootloaders and Uploading Sketches

    I strongly advice to activate the verbose output under the Arduino IDE preferences so you can figure out any eventual issue.

    To burn a bootloader into the Attiny85 you need to upload the ISP example to the Arduino and then select the programmer Arduino as ISP.

    Now place a 10uF capacitor between the reset and ground pins on the arduino (it's not needed for the burning process, but it is to upload sketches to the attiny85).

    Now the arduino is ready to burn bootloaders and load sketches. You just need to select the right board compatible with your attiny and burn it.

    To load an sketch into the Attiny85, load it into the arduino IDE and click on "Upload using programmer".

    IMPORTANT: when uploading the sketch there are 3 steps, compilation, writing and verifying. If the compilation and writing did work successfully, but the verifying process fails, it is possible that the sketch would work anyway.

    Step 9: Calibrate the Attiny85 Internal Clock (skip This If You Use a Crystal)

    In case you decide to not use the 16Mhz crystal you need to calibrate your attiny85 clock, so we are going to need a bootloader with a serial interface available and we'll use the tinytuner library to get the correct calibration.

    Follow the next steps

    • select under tools the Arduino as ISP programmer
    • select the board "ATtiny85 @ 8MHz (internal oscillator;BOD disabled)"
    • I assume that you have the ISP connection ready as described before connect otherwise do the connections
    • burn bootloader
    • this bootloader has configured different pins for the serial interface, use this configuration only for the current bootloader

    - PB4 (pin3--> RX) to TX in the FT232RL attiny85
    - PB3 (pin2--> TX) to RX in the FT232RL attiny85
    - GND (pin4) to GND on the FT232RL
    since the attiny85 is already powered by the arduino you don't need to connect the 5v on the FT232RL, otherwise connect: attiny85 VCC (pin8) to 5V on the FT232RL

    • upload the tinytuner example to the attiny85
    • open the screen program to monitor the serial communication: screen /dev/ttyUSB0 9600
    • reset the attiny85 connecting the RESET pin (pin1) to GND (just a moment), A welcome message should display on the screen window
    • Continue sending single 'x' characters (no carriage-return; no line-feed) until the calibration finishes
    • annotate somewhere the value of the calibration (OSCCAL = 0x). This is the value that you will need to declare on the final sketches

    Step 10: Decode Your Remote Buttons

    Now it's time to decode our remote buttons and assign them to specific key strokes in the PC, to do that follow the next steps:

    • select the board "ATtiny85 @ 16MHz (internal PLL;4.3V BOD)" if you don't use a crystal, "ATtiny85 @ 16 MHz (external crystal; 4.3 V BOD" otherwise, then burn it
    • load the sketch: https://github.com/venumz/ATtiny85-USB-IR-receive...
    • If you don't use a crystal, uncomment the row that contains the OSCCAL variable and assign it to the value that you found when you did the calibration of the clock
    • I assume that the sensor is connected as described before, otherwise connect it
    • I assume as well that the FT232RL serial to usb adapter is connected, otherwise connect it
    • reset the attiny85 connecting the RESET pin (pin1) to GND (just a moment)
    • hit repeatedly the buttons of your remote and checkout the screen window, you need to annotate the last number for each record, every button may produce 2 different numbers

    Example:

    RECEIVED D44 3396
    RECEIVED 544 1348

    Annotate 3396 and 1348 in association to the button you just hit, then you must decide what do you want to do with that button. For example I could want that button to send the multimedia keycode "Volume up", then I need to find the ID for that keycode. To do that, download the PDF: http://www.usb.org/developers/hidpage/Hut1_12v2.p...

    Look out for section "Keyboard/Keypad Page" page 53 and use the numbers in the column Usage ID (Dec) to bind your remote buttons to keyboard codes. In our example we can see that the keycode for "Volume up" is: 128.

    Edit the file the file UsbKeyboard.h inside the UsbKeyboard library from the v-usb package that we installed before and add to the existing defines if it's not already there:

    #define KEY_VOL_UP 128

    When we are done with all our remote/s buttons and all the defines in the file UsbKeyboard.h are ready we can move to the last step.

    Step 11: Loading the Final Sketch and Hope for the Best!

    We now have all the remote buttons decoded, the file UsbKeyboard.h is filled with our keycodes, so now we can load into the arduino IDE the definitive sketch from:

    https://github.com/venumz/ATtiny85-USB-IR-receiver...

    This file is the exact file that I'm using for my receiver, and it is working for 2 different remotes, so clearly you'd need to update it in order to work with your remote/s.

    If you don't use a crystal, uncomment the row that contains the OSCCAL variable and assign it to the value that you found when you did the calibration of the clock

    Notice that in the loop function there are a lot of statements like this one:

    if(results.value==3405 || results.value==1357) { // arrow up

    if(lastStroke!=results.value)
    UsbKeyboard.sendKeyStroke(KEY_ARROW_UP);

    }

    You must create your own statements, one per button in your remote. In the "if" condition you must put in the results.value the values that you have found decoding your remote and as the argument of the UsbKeyboard.sendKeyStroke method you must put one of the already defined keycodes in the file UsbKeyboard.h.

    The condition "if(lastStroke!=results.value)" is needed because some remotes send the same code twice per hit, and this prevents the second hit. I'm not totally sure and It may depend on the IR protocol that has programmed into your remote (I'm not really an expert in IR protocols) but according to my experience with my own remotes, every button can produce 2 different codes and while you press and hold the button, it sends the same code, but if you hit the button again it sends the other one. So it seems that the codes are sent in an alternate way, i guess it is a standard mode to know how many times you really hit the button.

    Ok, we are almost done, just upload the final sketch, connect it to the PC and see how it goes.

    For this step, is better if you unplug both the arduino and the usb to serial adapter and only then, plug the USB into your PC port (in case something goes wrong your circuit will be simpler to debug).

    If everything worked fine, when you open a terminal and send the dmesg command you should see something similar to the first image on this step. If there were issues, you should have errors like those found in the second image and you must start debugging your circuit and/or the software. One of the source of the initial errors that I had was an USB hub that wouldn't work with my IR receiver (others worked though)...so it's better for this final step to plug the IR receiver directly to your PC port. Eventual errors could be difficult to find, but at the end, like me, you would learn a lot and the price to pay is worth it, I assure you.

    That's all folks, let me know if you notice any errors in this instructable and enjoy your brand new IR USB receiver!

    Comments

    author
    venumz (author)2017-02-25

    I have added further information regarding the usb to serial adapter connections:

    The bootloader "ATtiny85 @ 8MHz (internal oscillator;BOD disabled)") needs a different pin configuration:

    PB4 (pin3--> RX) to TX in the FT232RL attiny85
    PB3 (pin2--> TX) to RX in the FT232RL attiny85

    Notice that the other bootloaders use:

    PB0 (pin5--> RX) to TX in the FT232RL attiny85
    PB2 (pin7--> TX) to RX in the FT232RL attiny85

    Anyway, if you use the crystal, don't bother as we use this bootloader only for calibration purposes.

    author
    tomatoskins (author)2017-02-09

    This is great! Thanks for sharing your receiver!

    About This Instructable

    3,829views

    53favorites

    More by venumz:ATtiny85 IR USB Receiver
    Add instructable to: