Go Down

Topic: IR Remote Controll For Arduino (Read 4233 times) previous topic - next topic


Hello. I have recently developted a program allowing the Arduino to capture sony IR remote control codes using the original sony protocoll (Note: some newer Sony remotes use RC6 this won't work here). I developed this program for a robot to be controlled by a remote control. The code may not be elegant but it is sufficient. ENJOY!

#include <stdio.h>

#define IR_PIN 2    //Pin recieving IR data
#define indicator 13

boolean flag;       //Flag
unsigned int command;      //Stores command bit string
unsigned int ir_mask2;      //Masks address code
unsigned long ir_mask;    //Loads variable ir_string
unsigned int ir_bit_seq;   //Records bit sequence in ir string
unsigned int ir_string;    //Stores ir string

void setup()
 attachInterrupt(0, read_ir_bit,FALLING); //Interrupt trigger on falling edge
 ir_bit_seq = 0;

void read_ir_bit(void)
 if(ir_bit_seq == 0)
   for(int i = 0; i<20; i++)
   ir_bit_seq = 1;
   ir_mask = 1;
 if(digitalRead(IR_PIN)) //If low then run if statement
   ir_string = ir_string & ~ (int)ir_mask;  //Stores 0 in bit
   ir_string = ir_string | (int)ir_mask;    //Stores 1 in bit
 ir_mask = ir_mask << 1;    //Shifts ir_mask by one to the left
 ir_bit_seq++;             //ir_bit_seq is incrimented by one
 if(ir_bit_seq == 21)
  ir_mask2 = 63;
  ir_string = ir_string & ir_mask2;
  command = ir_string;
  flag = true;
  ir_bit_seq = 0;
  ir_string = 0;
  ir_mask = 0;
void loop()
 int i;
  flag = false;


Thanks youngrobot!

I was looking for a Sony IR that used an interrupt rather than being blocking.

However, I tried your example (unmodified) and ran into a problem. I was wondering if you've seen it.

After reading a few keys I get a return for the previous key the first time I press a different key - almost like it's buffered somehow.

For example, pressing "1", "2", "2", "3", "3", I might get 0 (ok), 0, 1, 1, 2.

I've never had this problem using the same hardware setup and the blocking code I've been using for a while now. It doesn't look it's due to "auto-repeat" either.

Again, just wondering if you've seen this or have any ideas.

Thanks for the example, though, I like how you handled the header.  :)
"Data is not information, information is not knowledge, knowledge is not understanding, understanding is not wisdom."
~ Clifford Stoll


I noticed the same intermittent 'repeat/buffering' behaviour. I placed a delay(400); before the serial.print(command); and that seemed to calm it down some. Still playing with it.



Feb 08, 2009, 08:22 pm Last Edit: Feb 08, 2009, 08:22 pm by BroHogan Reason: 1
That was the first thing I tried too - didn't seem to help much for me.

Since my PCB has the IR sensor connected to Pin 4 I simply jumpered Pin 4 to Pin 2 to get the interrupt. That should work fine, but I was afraid it might be involved somehow in the problem - good to know you've seen the same behavior.
"Data is not information, information is not knowledge, knowledge is not understanding, understanding is not wisdom."
~ Clifford Stoll


Feb 08, 2009, 09:00 pm Last Edit: Feb 08, 2009, 09:01 pm by youngrobot Reason: 1
I believe I have found the solution to your problem.

With my remote control it is very hard to just send one IR command. I will often end up sending 2 or 3.

In my interrupt routine I end up displaying those extra IR commands.

However in your blocking program BroHogen you do not end up displaying those extra IR commands.

I believe that is the problem you are encountering. You might try to quickly press one button to get just one IR command.

Also differnet remote controlls have different timing structures. Mine as you can see is 900 useconds.

I hope I have solved your problem.   :)

Thankyou for your input.




Thanks for your reply.
However, as I said in my first post, it doesn't look it's due to "auto-repeat". I say this because it is not a repeat that I'm seeing, it is more like the buffering of the previous entry - even if I wait a few minutes and press a key, I often get a return value for previous key. The next return will be correct. (I am getting only 1 return / key) It's weird.

I almost wonder if it has something to do with using delayMicroseconds() in the interrupt. I know it's better than using delay() but I think it disables interrupts - not that I can relate that to the problem!

Anyway, it's a mystery to me.

So I take it that you don't see the problem using your test sketch?
"Data is not information, information is not knowledge, knowledge is not understanding, understanding is not wisdom."
~ Clifford Stoll


I am very puzzled by the behavior you are seeing.

Obviously I am not encountering the same problems you are encountering.

You might try vary the delay of 900 useconds, since there are different pulse widhts.

Also you could try varying the IR command size, because there are differnet sizes, my remote is 21 bits.

I used this website to gather how the IR commands are encoded: http://www.ustr.net/infrared/sony.shtml

The behavior you are encountering is really puzzling, and unfortuanatly i can not think of a better solution.



Feb 09, 2009, 01:41 am Last Edit: Feb 09, 2009, 01:45 am by retrolefty Reason: 1
Well I think your bit timing interrupt routine is correct as there never seems to be a garbled value sent, just intemittenly a repeat of the last button hit followed by the new button pressed. That is sometimes even when nothing has been pressed for many seconds and you hit a button you get two values, one of the previous button pressed many seconds ago and one value of the new button pressed.

I wonder if this might be some kind of serial communication buffering problem and nothing to do with the IR decode routine? Maybe sometime I'll try the software serial routines instead of the hardware interrupt UART and see if this symptom changes.

I also noticed that if I hold down a button so that the value repeats, I get like 4 values at a constant rate and then there is like a single value 'gap' and then the value repeats again, so 4 values, a one value delay and then 4 values, etc.

Again when I placed a delay of 400 before the print statement I can get real good results, no repeats (unless I hold the button down to long) and never a sign of the prior button value sent when a new button is pressed. With the delay I feel I could use this routine reliably in a application and I thank you very much for sharing it with us. The community grows with every contribution.  :)



As far as I can see everything is the same in our settups. However the remote control could be differnet.

Do any of you have a storage osciliscope? You might try capturing the IR command, and compare it with my remote controll specifications.

The start pulse is a low pulse of 2,850 us.

The high of each bit is 500us long.

The low of a 0 bit is 750 us long.

The low of a 1 bit is 1850 us long.

I rechecked my setup and I am not seeing any of the problems you guys are encountering. I don't see the repeats of prior commands, nor the 4-pause-4 when holding a button down.



Feb 09, 2009, 05:41 am Last Edit: Feb 09, 2009, 05:44 am by imagitronics Reason: 1
I don't claim to be an expert on any of these topics, but there are a couple of things I noticed in the code that concern me:

1) First off, in your interrupt function read_ir_bit(), you make a call to delayMicroseconds(). I'm fairly certain that timing functions (including serial) do not work inside an interrupt routine.

2) I believe the preferred method for handling interrupts is to simply set a few variables or bitmasks and then return processing to the rest of your code. For example, things might work out better if read_ir_bit() simply modified a volatile boolean variable irCommandIncoming = true; and then allow the main code loop to process that bit? it's just an idea.

3) also, though your function is named read_ir_bit() it appears to be reading the entire code, thus I would guess that every time the pin is FALLING (which happens numerous times during a single command) you start another interrupt routine. Once the interrupt is triggered by the falling edge, I would disable the interrupt while reading the rest of the command.

These are all just educated guesses. I'll try to play with it a bit myself when I have some free time.




I think you have a 12 bit remote.

For example, you hold down a button and you get three commands of 12 bits. The first 12 bits will be stored and then the program will wait. Then the second command comes in and you get 21 bits of information and 3 bits which are trashed. Finally the third command comes and fills up 12 bits of storage, so when you press another (4th command) button you end up getting the first 6 bits of the 3rd command in the variable ir_string. The 4th command is trashed.

If you have a 12 bit IR command then change the ir_bit_seq limit from 21 to 12.

Let me know if this is the solution.

ps: I believe delayMicroseconds() works in interrupt routines, unlike delay().



You nailed it!   :)
Thanks so much for pursuing this! Especially since it was working for you. I had no idea Sony had 12 bit and 21 bit remotes.

It does have a hair trigger and I easily get double entries, but that should be easy to solve.

I'm sure your code will be helpful to many as the blocking code that seems popular for the Sony can present problems. (I think there is a NEC library that is interrupt driven also.) You might consider putting it on the Playground to give it a better future. I think there is a section of IR Remotes.

Once again, Thanks!
"Data is not information, information is not knowledge, knowledge is not understanding, understanding is not wisdom."
~ Clifford Stoll


Very good!  8-)

I made your suggested change and removed the delay I had used to mask the problem. Now I see no sign of the delayed 'buffering' problem!

It's somewhat hard (without adding delay) to press a button short enough such that only one value is sent, but that is the nature of the remotes automatic repeat function and not your program.

If used in an application one should check each value received and throw away any sequentially received duplicate values. It's not hard to build a command protocol around that minor restriction.

Again, a very nice contribution. And you received immediate feedback from multiple users and testing and you might otherwise not have discovered this symptom for awhile. Again community works well for all, users and contributors.  ;)

Thank you;



I am so glad I was able to help, and thank you so much for your input. I will be posting the finished robot soon.



I'm glad to see this worked. I'm anxious to find a use to play around with it.

Go Up