IRLib Tutorial part 3a: Sending IR Codes

In this lesson we will demonstrate how to send IR codes to a TV, DVD, DVR/cable box or any other device that uses an infrared remote. You will need…

  • a 38 kHz IR receiver module,
  • an IR LED and driver circuit such as described in part 1 of this tutorial,
  • a TV, DVD, DVR or whatever device to control,
  • an IR remote control for that device so we can obtain the proper codes.

Begin the process by wiring an IR receiver to pin number 11 on your Arduino as described in part 1 of this tutorial. Hook up an IR LED and a driver circuit also described in part 1 of this tutorial. If you are using Arduino Uno it will connect to pin 3. On the Arduino Leonardo you should use pin 9

Now you should load the IRrecvDump sketch from the examples folder of the IRLib library. We will use this sketch to determine what codes your infrared remote is transmitting. Run the sketch and open the serial monitor. This is the same process described in part 2 of this tutorial. Write down the received codes for all of the major functions of your device such as power on, channel up and down, volume up and down, rewind, fast-forward, play, stop etc. Also make note of the protocol and the number of bits. Here is what the dump for the power on function looks like on my Magnavox TV
Decoded RC5: Value:180C (13 bits)
Raw samples(24): Gap:30014
Head: m850 s900
0:m900 s900 1:m1700 s900 2:m900 s900 3:m850 s900
4:m850 s900 5:m850 s900 6:m900 s850 7:m900 s1750
8:m900 s850 9:m1750 s900 10:m900
Mark min:850 max:1750
Space min:850 max:1750

As before, you only need to concern yourself with the first line of text. The protocol is “RC5” the code is “180C” and it uses 13 bits.

We are going to presume that you are using a remote that has a protocol that this library understands. If the top line of the dump says “Decoded Unknown” then you will have to skip ahead to section on how to program your own protocol in a future lesson of this tutorial.

Now load the following sketch named “IR_serial_remote” which is shown here. It is also available in the latest update to IRLib version 1.1 which was uploaded to GitHub on April 21, 2013 or later. This upgrade to the library also contains some other minor enhancements and a copy of the “IRservo” example used in part 2 of this tutorial.
#include

IRsend My_Sender;

int protocol;
long code;
int bits;
void setup() {
Serial.begin(9600);
}

long parseHex (void) {
long Value=0; char C;delay(100);
while (Serial.available()>0) {
C= tolower(Serial.read());
if ((C>='0')&&(C<='9')) C=C-'0'; else if ((C>='a') && (C<='f')) C=C-'a'+10; else return Value; Value= C+(Value<<4); }; return Value; } void parseDelimiter () { char C; while(Serial.available()>0) {
C=tolower(Serial.peek());
if( (C>='0') && (C<='9') )return; if( (C>='a') && (C<='f') )return; C=Serial.read();//throwaway delimiters delay (5); } } // enum IRTYPES {UNKNOWN, NEC, SONY, RC5, RC6, PANASONIC_OLD, JVC, NECX, HASH_CODE, LAST_PROTOCOL=HASH_CODE}; void loop() { if (Serial.available ()>0) {
protocol = Serial.parseInt (); parseDelimiter();
code = parseHex (); parseDelimiter();
bits = Serial.parseInt (); parseDelimiter();
/* Serial.print("Prot:"); Serial.print(protocol);
Serial.print(" Code:"); Serial.print(code,HEX);
Serial.print(" Bits:"); Serial.println(bits);
*/
My_Sender.send(IRTYPES(protocol), code, bits);
}
}

Upload the sketch and open the serial monitor. We will type in the protocol number, function code, and the number of bits for one of the functions that you wrote down. For example to turn on my TV I would type in

3,180c,13

The “3” is the number of the protocol that I’m using. If you look in “IRLib.h” at about line 50 you will see the following enum definition.

enum IRTYPES {UNKNOWN, NEC, SONY, RC5, RC6,
PANASONIC_OLD, JVC, NECX, HASH_CODE,
LAST_PROTOCOL=HASH_CODE};

You can send that “RC5” is the third protocol. In my examples I will also be using protocol 5 which is “PANASONIC_OLD” which is the protocol used by my Scientific Atlantic SA 8300 HD cable box/DVR.

After typing in the protocol number, code, and number of bits in the serial monitor you should press enter or click on the “send” button. The Arduino should decode this information and send the proper signals from your IR LED. If you want to make sure that what you are typing is getting parsed you can uncomment the “Serial.print…” statements near the end of the sketch.

Here are the details on how the sketch works…

We start by including the IRLib.h file for the library. We create the sender object and create some integers to store the protocol number, code, and number of bits. The setup routine simply initializes the serial port.

The standard Serial objects include routines for parsing integers in decimal format coming across the serial line but it does not include parsing hexadecimal values so we’ve written a little routine called

long parseHex (void)

Which accepts characters “0” through “9” and “A” through “F” either upper or lower case and converts it into an integer value. We also have a routine called

void parseDelimiter ()

It skips over any commas, blanks or other extraneous characters which you use as a separator.

The main loop simply looks for serial characters available, parses them, and then sends them using the send method as follows

My_Sender.send(IRTYPES(protocol), code, bits);

Note that because the protocol is actually an enum rather than an integer we have to typecast it when passing it to the send method.

Of course it would be quite tedious to have to look up the protocol number, hex codes, and number of bits every time you wanted to send a function. So we’re going to write a program which will send that serial data from your PC to the Arduino. We will create a “virtual remote control” in which you can click on buttons on it will send that serial data to the Arduino which will in turn control your device.

In part 3b we will show you how to use a Python script to create just such a virtual remote and send the codes from your PC or laptop to the Arduino.

24 thoughts on “IRLib Tutorial part 3a: Sending IR Codes

  1. If the top line of the dump says “Decoded Unknown” then you will have to skip ahead to section on how to program your own protocol in a future lesson of this tutorial.

    Hello do you have any sample for this ?

    • I’m sorry I haven’t gotten around to writing the blog entry on how to write your own protocols. I’ve been tied up with lots of other projects. I hope to be able to get to this in the very near future. In the meantime if you want to email me a dump from the IRrecvDump routine I might be able to look at your protocol and figure out what it is. If it’s an easy one I might be able to send you the code. What kind of device are you using? Cable box? DVR? DVD? Etc.

  2. I have the same problem as Tasos. I’m trying to decode a rc for an OSRAM led controller which uses RMAP protocol. I’ve been doing some research about this protocol but I there is no information.

  3. Hello

    my electronic is working i can manage my tv …

    but now trying to manage the aircooler without success

    please help i would really love to manage my aircooler.

    see my IRrecvdump below

    Decoded Unknown: Value:0 (0 bits)
    Raw samples(250): Gap:1678
    Head: m3350 s1750
    0:m400 s1300 1:m350 s1400 2:m350 s500 3:m400 s450
    4:m400 s450 5:m350 s1350 6:m400 s450 7:m400 s450
    8:m350 s1400 9:m350 s1350 10:m400 s450 11:m400 s1300
    12:m400 s450 13:m400 s450 14:m400 s1350 15:m350 s1350

    16:m400 s450 17:m400 s1300 18:m400 s1300 19:m400 s450
    20:m350 s550 21:m350 s1350 22:m400 s450 23:m300 s550
    24:m350 s1350 25:m450 s400 26:m350 s550 27:m350 s500
    28:m350 s500 29:m350 s500 30:m350 s550 31:m350 s500

    32:m400 s450 33:m400 s450 34:m400 s450 35:m350 s500
    36:m400 s500 37:m350 s500 38:m350 s500 39:m400 s450
    40:m400 s450 41:m400 s500 42:m350 s500 43:m350 s500
    44:m350 s500 45:m350 s500 46:m350 s550 47:m350 s500

    48:m400 s450 49:m350 s500 50:m400 s450 51:m350 s1350
    52:m450 s450 53:m350 s500 54:m350 s500 55:m350 s500
    56:m400 s500 57:m350 s1350 58:m350 s500 59:m350 s500
    60:m400 s450 61:m450 s450 62:m350 s500 63:m350 s500

    64:m400 s450 65:m400 s450 66:m400 s500 67:m350 s500
    68:m400 s1300 69:m350 s1350 70:m400 s450 71:m400 s450
    72:m400 s1350 73:m300 s550 74:m400 s1300 75:m400 s450
    76:m400 s450 77:m400 s500 78:m350 s1350 79:m400 s450

    80:m350 s500 81:m400 s1300 82:m400 s1300 83:m400 s1350
    84:m350 s1350 85:m400 s1300 86:m400 s1300 87:m400 s450
    88:m400 s500 89:m350 s500 90:m350 s500 91:m350 s500
    92:m350 s500 93:m400 s450 94:m400 s500 95:m350 s500

    96:m400 s450 97:m350 s500 98:m350 s500 99:m350 s500
    100:m400 s500 101:m300 s550 102:m350 s500 103:m400 s450
    104:m350 s500 105:m350 s550 106:m400 s450 107:m400 s450
    108:m400 s450 109:m350 s500 110:m400 s500 111:m300 s550

    112:m350 s500 113:m400 s450 114:m400 s450 115:m350 s500
    116:m350 s550 117:m350 s500 118:m400 s450 119:m400 s450
    120:m400 s450 121:m400 s450 122:m400 s500 123:m350
    Extent=132400
    Mark min:300 max:450
    Space min:400 max:1400

    Decoded Unknown: Value:0 (0 bits)
    Raw samples(250): Gap:16950
    Head: m3450 s1800
    0:m400 s1300 1:m400 s1300 2:m400 s450 3:m350 s500
    4:m350 s550 5:m350 s1350 6:m400 s450 7:m350 s500
    8:m400 s1300 9:m350 s1400 10:m350 s500 11:m400 s1300
    12:m400 s450 13:m350 s500 14:m350 s1350 15:m350 s1400

    16:m350 s500 17:m350 s1350 18:m350 s1350 19:m400 s450
    20:m400 s450 21:m400 s1350 22:m350 s500 23:m400 s450
    24:m400 s1300 25:m400 s450 26:m400 s450 27:m350 s550
    28:m350 s500 29:m400 s450 30:m400 s450 31:m350 s500

    32:m400 s500 33:m350 s500 34:m350 s500 35:m400 s450
    36:m400 s450 37:m350 s500 38:m400 s450 39:m350 s550
    40:m350 s500 41:m350 s500 42:m400 s450 43:m400 s450
    44:m400 s450 45:m450 s450 46:m400 s450 47:m350 s500

    48:m350 s550 49:m350 s500 50:m400 s450 51:m400 s1300
    52:m400 s450 53:m350 s500 54:m400 s500 55:m350 s500
    56:m350 s500 57:m350 s1350 58:m350 s500 59:m400 s450
    60:m400 s450 61:m350 s550 62:m350 s500 63:m350 s500

    64:m350 s500 65:m350 s500 66:m350 s500 67:m350 s550
    68:m300 s1400 69:m400 s1300 70:m400 s450 71:m400 s450
    72:m400 s1300 73:m350 s550 74:m350 s1350 75:m350 s500
    76:m400 s450 77:m350 s500 78:m350 s1350 79:m350 s550

    80:m350 s500 81:m300 s1400 82:m400 s1300 83:m400 s1300
    84:m350 s1350 85:m400 s1300 86:m400 s1350 87:m350 s500
    88:m400 s450 89:m350 s500 90:m350 s500 91:m400 s500
    92:m300 s550 93:m300 s550 94:m350 s500 95:m350 s500

    96:m350 s550 97:m300 s550 98:m350 s500 99:m350 s500
    100:m350 s500 101:m350 s500 102:m350 s550 103:m350 s500
    104:m350 s500 105:m350 s500 106:m350 s500 107:m450 s450
    108:m350 s500 109:m350 s500 110:m350 s500 111:m350 s500

    112:m350 s500 113:m350 s550 114:m300 s550 115:m300 s550
    116:m350 s500 117:m350 s500 118:m350 s500 119:m350 s500
    120:m350 s550 121:m300 s550 122:m300 s550 123:m350
    Extent=132450
    Mark min:300 max:450
    Space min:450 max:1400

    Thanks for helping
    regards

    • Air-conditioners tend to have very nonstandard remote and as you can see they are especially long sequences. They are very difficult to analyze. You would have to write your own custom routines to decode that protocol or you would have to use the raw send routines. You will have to increase the size of RAWBUF which is defined in IRLib.h at about line number 49. Make sure that it is longer than the number of samples you are receiving.

      My next project for the documentation is to explain how to write your own decoding protocol routines. That should help you write your own routines for your air-conditioning protocol.

  4. Hi, I’m using Adafruit datalogger, with Leonardo, so I have to use pin 9 which is the default pin in the library. My command is My_Sender.send(NEC,0xFF02FD,32);
    I upload it using IRsendDemo but it’s not working. Any ideas? Thank you.

  5. My mistake, I found out what was wrong after 3 hours !!! I changed the “if (Serial.read() != -1) {”
    with a standard loop “for (int i = 0; i < 23; i++) {" and it is not working. Now I have to figure out why !

    • Hi, my name is Ricard. I need to make a copy of an IR remote for a DVB-T with NEC signals. First, I have read the signals using NECIRrcv and all codes was received ok. Then I need to re-send these codes using IRLib or IRremote.h and led flashes but the signals isn’t accepted on my DVB-T receiver. Can you help me? Thank you!

      • You said that the LED flashes. Did you substitute a visible LED to check that out? Normally you can’t see an IR LED flash. How far away is the LED from your set-top box? Is the LED pointed directly at the device you’re trying to control? What kind of driver circuit are you using?

        • Some months with this project in pause, now is solved:
          The problem is in MSB and LSB. Inverting the bits, the signal is received ok.
          Example: If I send 00F7A05F with irlib, NECIRrcv read: FA05EF00
          00 _ _ _ = _ _ _ 00
          _ F7 _ _ = _ _ EF _
          _ _ A0 _ = _ 05 _ _
          _ _ _ 5F = FA _ _ _

          Thank you for your help.

  6. Hi,
    Is it possible to ‘clone’ an IR command and save it somewhere (without having to write it down).
    IRLib Tutorial part 3a explains how to manually discover codes using IRrecvDump then manually transmit them using IR_serial_remote, similarly for manually discovering then populating your excellent Python Virtual Remote Control with codes.
    But is there some way to directly clone codes (as with KS’s single-button example) which doesn’t involve manually passing the code details
    It would obviously be useful for a discovery event to record a captured IR code which could be easily saved somewhere for subsequent transmission on demand.

    It would also make handling and storing of IR codes a lot easier if the 3 parameters could be combined into a single entity (much more suitable and convenient for saving to file on SD etc).
    I can probably hack together a couple of suitable functions for my own purposes if needs be – perhaps a Combine() to return a single entity, and corresponding Uncombine() to separate out a single entity back to its constituent parameters suitable for transmitting – but I’ve mentioned it in case you think it could be a relatively quick and simple enhancement for you to add to your library yourself to give some new and useful extra functionality which might be welcomed by others.

    Perhaps IRrecvDump could also report protocol enum value as well as name, BTW (to save digging through IRLib.h for appropriate enum values).

    Thanks for all the huge efforts you must have taken in producing such an excellent contribution.

  7. Hi,

    – I use Arduino YUN for my project.

    – I use Digital IR Receiver Module (SKU:DFR0094)
    http://www.dfrobot.com/wiki/index.php/Digital_IR_Receiver_Module_(SKU:DFR0094)

    – I use Digital IR Transmitter Module (SKU:DFR0095).
    http://www.dfrobot.com/wiki/index.php?title=DIGITAL_IR_Transmitter_Module_(SKU:DFR0095)

    ==> My Digital IR Receiver Module use pin 11 and I can dump IR code : NEC, 1FE39C6 (32 bits)

    ==> My Digital IR Transmitter Module use pin 9, but he doesn’t send code. I test with différent s IR code and it’s each time KO.

    ==> for information I use default IRLibTimer.h :

    #elif defined(__AVR_ATmega32U4__)
    #ifdef CORE_TEENSY
    // it’s Teensy 2.0
    //#define IR_SEND_TIMER1 14
    //#define IR_SEND_TIMER3 9
    #define IR_SEND_TIMER4_HS 10
    #else
    /* it’s probably Leonardo */
    #define IR_SEND_TIMER1 9
    //#define IR_SEND_TIMER3 5
    //#define IR_SEND_TIMER4_HS 13
    #endif

    Can you help me please ? IRLibTimer.h it’s OK?

    Thank you very much for you help 😉

    Fabrice.

    • FYI my code :

      #include

      IRsend My_Sender;

      void setup()
      {
      Serial.begin(9600);
      }

      //send a code every time a character is received from the serial port
      void loop() {
      if (Serial.read() != -1) {
      My_Sender.send(NEC,0x1FE39C6, 32); // TURN ON
      }
      }

      • That should work. The Yun appears as a Leonardo and that should use pin 9 like you did. Try putting the transmitter extremely close to the device receiving it. If for some reason it’s not getting enough power the distance maybe too large. Also since the Yun draws extra power for the other processor and Wi-Fi, powering it off of your computers USB port may not be enough. Also if you have another Arduino can you set up a receiver to analyze the signal from the Yun and get a better idea of what it is you’re transmitting or if you are transmitting at all.

  8. Hi,
    is it possible to send RAW Code with the IRlib Library ?
    If I understand right, then this function is not implemented yet, is this right ?

    If it works with RAW Code, how can I send this.

    Thank you very much for you help !

    marCus

    • It depends on what you mean by RAW code. You can create an integer array with all of the timing values in it which is a kind of raw code. Look at the IRRecord example sketch. If it doesn’t detect the protocol it will store raw values and repeat them. Using that sample code you should be able to implement something on your own but keep in mind you are limited in the amount of storage available on Arduino so you can’t store lots of codes because you just don’t have room. You would do better to try to figure out the details of your protocol using one of the dump or analyze routines.

  9. Hello, Firstly thanks for sharing :). How to save(or record) the receiving codes to eeprom and after that send IR codes from eeprom?

    • We never put the other tutorial on how to do that but if you look at other examples on the Internet of how to use EEPROM you should be able to implement it yourself fairly easily.

      • I have Raw values for mitsubishi air conditioner. for example 18 degree ON command is; “3000,1750,400,1150,400,1150,350,450,400,400,350,500….”.If I change raw number without head number(3000,1795) like this”3000,1795,0,1,0,1,0,0,0,0,0,0….” can I send the code that form? Air conditioner understand this? Because my problem is; I am limited in the amount of storage avaliable on arduino as you said above.

        • Air conditioner codes are never well-documented so I really don’t know how that particular system works. Until I can get my tutorial written on how to implement new protocols you’re just going to have to play around with the code on your own. The reason we use decoders is to try to reduce all that data in just one 32 bit value so it is easier to store. So I understand your problem but short of analyzing every code that your remote produces and trying to reverse engineer the protocol there isn’t much you can do.

          • I used IRLib and my remote controller decode is http://i.hizliresim.com/4bJP7A.jpg . Also I send sony controller and decoded with use arduino and result is http://i.hizliresim.com/lvgdoQ.jpg . As you can see, Value and bit number looks like “0”. So, how can I learn “Value”(data) ?
            For example sony Value=A90
            sony data = 0xa90. How can I learn my data?

            NOTE: I am sharing “ir_airfel.cpp” document may be that is help to explain my problems http://i.hizliresim.com/8DydmW.jpg

          • Again this is because you have an unsupported protocol. You’re going to have to analyze the code and figure out how to support yourself. One thing I did note is that you have 100 received data points. You also mentioned this is an air conditioner. Air conditioners traditionally have extremely long sequences. You probably have overflowed the buffet because the buffer size is 100. The code will still work if you increase RAWBUF as high as 255 but that still may not be big enough. I really can’t help you to write code for a new protocol. My tutorial that explains how to do it is still a long way off. I’m busy working on IRLib version 2 which is a major rewrite.

Leave a Reply

Your email address will not be published. Required fields are marked *