Jaeheon Shim
Hi! I'm Jaeheon Shim, a computer programmer and technology enthusiast who lives in Columbus, Indiana. I like contributing to open-source development projects on GitHub, working on my own web-based applications, and writing articles on my blog Learn The Technology. In my free time, I manage CAMEO's public website and provide free tech assistance to friends and family :).

How To Easily Send IR Signals Using The ATtiny85

If you are like me and are trying to make a device that secretly turns off TV’s on display at Wal-Mart using an ATtiny85 to send the IR signals, you might have come across the problem of actually sending the IR signals using the ATtiny. The problem is that it is extremely hard to use the IRlib library with an ATtiny85, and even if you did find out a way to use it, the microchip requires OSCCAL tuning. For me to tune the microchip, I need an oscilloscope, which I don’t have steady access to. (Hey KeySight, what about a sponsorship?) So I needed to find out how to send the IR signals manually. The way IR works is by flashing an led at 38khz, and then varying the amount of time the led is flashing. This sends a binary code to the receiver – such as a TV or air conditioning unit – and the receiver tells the device to do what it was commanded by the transmitter.

How does infrared communication work?

Now the problem is, there is not really a lot of documentation out there. Only a few forums and YouTube videos from foreign countries.  While there are application specific pieces of code written for specific purposes, there is no one fits all solution for the ATtiny85. Here’s the code that I used. It works for any IR signal, as it sends the raw data of each IR signal manually.

int IRledPin = 1;

void setup() {
pinMode(IRledPin, OUTPUT);

}

void loop()
{
SendIRCode();

delay(5000);
}

void IR(long microsecs) {

cli();
while (microsecs > 0) {
digitalWrite(IRledPin, HIGH);
delayMicroseconds(10);
digitalWrite(IRledPin, LOW);
delayMicroseconds(10);
microsecs -= 26;
}
sei();
}

void SendIRCode() {
IR(500);
delayMicroseconds(1500);
IR(1500);
delayMicroseconds(500);
delay(65);
IR(500);
delayMicroseconds(1500);
IR(1500);
delayMicroseconds(500);
}

Let me explain how this code works in more detail.

int IRledPin = 1; 

This just defines the pin that the anode of your infrared led is connected to. Although you probably want to use a driver circuit for the LED to make sure that it is bright enough.

void setup() {
pinMode(IRledPin, OUTPUT);
}

Nothing much here, just defining that the IRledPin should be treated as an output.

void loop()
{
SendIRCode();
delay(5000);
}

This section of the code is the loop. I just made it so that the SendIRCode function runs every 5 seconds.

void IR(long microsecs) {

cli();
while (microsecs > 0) {
digitalWrite(IRledPin, HIGH);
delayMicroseconds(10);
digitalWrite(IRledPin, LOW);
delayMicroseconds(10);
microsecs -= 26;
}
sei();
}

Now, this is the interesting part. Since the led must flash at a frequency of 38 kilohertz per second, we must do some calculations to make this happen. First of all, 1 second divided by 38,000 is equal to roughly 0.000026. This means that the led must flash on and off within 26 microseconds. The led will also keep flashing for the amount of time according to the IR code. So to do this, we use a while loop. How long we flash the LED is determined by the value passed through the function IR as an argument, microsecs. Since this is the amount of time we have to keep flashing the LED for, the while(microsecs>0) ensures that the loop runs as long as the value in microsecs is greater than 0. In this loop, we first have digitalWrite(IRledPin, HIGH);. This turns the LED on. Take note that performing this action itself takes about 3 microseconds, which explains the next line of code: delayMicroseconds(10);. Remember that we have to turn the LED on and off in 26 microseconds, which gives us 13 microseconds for each on/off. Since changing the state of the LED takes 3 microseconds, we only have to have a delay of 10 more microseconds for the final value to equal 13. We do this once more to turn the LED off, giving us an elapsed time of 26 microseconds, which is subtracted from the total time to be elapsed with this bit of code: microsecs -= 26;. This concludes the IR function.

void SendIRCode() {
IR(500);
delayMicroseconds(1500);
IR(1500);
delayMicroseconds(500);
delay(65);
IR(500);
delayMicroseconds(1500);
IR(1500);
delayMicroseconds(500);
}

Now comes the fun part! This function defines the actual IR code to be fed into the IR function, which makes the LED flash. It was very tedious to type out every individual number into the IR code, you should probably come up with a code that does it for you. Actually, now that I think about it, I could have used a list and then a for loop to carry this out. But I didn’t. Genius, right? For every positive number from your IR code, type that in between the parentheses in IR();. And do the same for the negative numbers, except this time in delayMicroseconds();. If that doesn’t make sense, here’s the IR code that would correspond to the code above:

+500, -1500  +1500, -500

The code after the 65-millisecond delay is exactly the same.

So there you have it. Flash that code to your ATtiny 85 using your Arduino as Isp, and you are ready to make your own remote control for whatever purpose. Enjoy! (Oh, and don’t tell walmart.)

You may also like...

8 Responses

  1. Julius Caesar says:

    You are such a good guy…..
    But I wanna know how did you turn hex to “+500, -1500 +1500, -500”?!
    Did you used any kind of hex online converter?!plz help.

    • Jaeheon Shim says:

      I didn’t use an online converter, however after doing some Googling, I found this website that is basically a converter for your needs. You can visit it here: https://irdb.tk/convert/. I hope this works for you, and if it doesn’t be sure to let me know here or email me and I will get back to you as soon as I can to resolve this issue. Also, I’m glad you enjoyed my content!

  2. kebkyelin says:

    please what is the full skitch with the library bro?!!
    i mean i reseved this error message—-
    exit status 1
    ‘SendIRCode’ was not declared in this scope

    • Jaeheon Shim says:

      The reason you received that error is that I made a mistake in the code before. For some reason, there was a character that shouldn’t have been there. It should work fine now, I tried compiling it myself. Thank you very much for pointing this out; I probably wouldn’t have found it otherwise! There aren’t any extra libraries that you should need… do let me know if you need any extra help!

  3. Marc says:

    Thank you for making this tutorial. I had a question about 2 parts of the code: When you send your code “+500, -1500 +1500, -500”, is it required to send it twice within the SendIRCode() function, or will once work? Is the 65ms delay also required (and why 65ms?)? Thanks again!

    • Jaeheon Shim says:

      First of all, sorry for the late reply. To answer your question, it is ideal to send their codes a second time in case the TV does not get it the first time. This will greatly improve success with the code. The 65ms delay is required because without it the TV could read the two signals as one, and it would not function. The delay is 65ms long because if it was longer the TV could register the series of signals as separate signals, and if it was too short it could register it as one big signal. I hope that makes sense!

  4. Like says:

    Like!! Great article post.Really thank you! Really Cool.

  5. Eldar says:

    thx for the great article.Why do u use cli(); and sei();.U enable and disable interrupts but not use them somewhere in the code?

Leave a Reply