RC5 Decoder


I completed this design a number of years ago when I was still learning to program.  In fact, this was my first “proper” project that I directed my new-found programming skills towards.  My programming skills have improved by many orders of magnitude since, and with that in mind I was a bit ambivalent about whether to put this project up on my site.  I only like to showcase my best work, and although this really was my best work back in 2009, it’s nowhere near up to my current standards.

That said, I constantly find myself receiving emails from people who want to have a copy of the code and/or PCB design files.  It seems I’m not the only one who is intrigued by IR communication methods.

I have therefore decided that I will publish this old work on my site for the benefit of others who are also learning.  The information is a literal copy of the original article I wrote for a very old version of my website, back in the days when I used to hand code the HTML.  I have simply copied and pasted the information into this post.

Known Problems:

  1. The code for the LCD and the RC5 decoding is mixed in to one C file, although obviously they are separated into their own relevant functions.  These should ideally be made into their own libraries, particularly the LCD code.  I have in fact used the LCD code in other projects and during that time I have made huge improvements to it and I’ve made it into my own library.  The LCD code provided in this project is basically a skeleton solution, suitable for this particular application but not a lot else.
  2. In practice I found this version of the LCD code to be a bit hit-and-miss.  It works fine with the LCDs stated in the BOM, but when I tried it with other LCDs it sometimes worked and sometimes didn’t – so bare that in mind.
  3. The RC5 decode solution provided here analyses the RC5 data stream in real time, bit-by-bit, as it is received by the IR receiver.  There is some error detection that throws out the stream if it is not deemed to conform to expected RC5 standards, but you might want to have a play with this.  In practice I found it to be reliable with a number of different RC5 remotes.
    A better solution to this problem is to do a post-analysis on the received data.  That is the technique being employed by version 2 of my RC5 decoder, which is currently in development as a kind of side project that I work on every now and then.
  4. The IR receiver listed in the BOM is very important because it filters out ambient noise.  The code relies upon that.  If you try to use a simple IR LED to detect an RC5 stream you will experience noise problems because the code is not designed to account for it.

RC5 Decoder V2 is in development!

It should be noted that there is an RC5 Decoder V2 in development.  The new version will receive remote control data streams and provide post-analysis of the data.  This is an improvement because it will allow the project to decode other protocols as well, simply by adding new libraries.  Also, the LCD code has been significantly improved and broken out into a separate library.  The V2 version, when released, will be published on this site.

RC5 article from old version of brianhoskins.uk follows

What follows is an article I wrote for the first version of my website that details the RC5 decoder development, provides explanation, and also provides all of the design files you’ll need to repeat my work.

What is an RC5 Decoder?

If you’re a computer geek, you might think I’m claiming to have built a project that decrypts the RC5 block cipher. I wish that were the case, and indeed if it were I’d certainly be earning a lot more money than I am now! But alas, this project refers to a much simpler idea – the RC5 protocol for wireless (infra-red) communication. If you’ve used a television remote control before, then it’s quite possible that you’ve used one that transmits RC5 coded commands. In that case your television will be acting as an RC5 decoder; receiving the infra-red data stream from your remote control, decoding it and acting upon the command it has received.

The project described here can receive an RC5 coded infra-red data stream, decode it, and display the address, command and toggle data on an alpha-numeric LCD.


What is the point of this project? Well for me it was an educational experience. I had been busy learning assembly and C for PIC Microcontrollers and, whilst I had already written a number of experimental programs to help with my education, this was my first attempt at a complete microprocessor based project. Thus, this project served no other purpose than academic value. In practice, though, you could use this project in any application that requires remote control of equipment via infra-red communication. I have used my decoder firmware to display information about the commands that were received, but the project software could be easily modified to act upon the commands that are recieved and control practically anything you want with it. If you do create something useful/interesting with this project, please let me know!

RC5 Explained

The heart of this project is based upon receiving and decoding an RC5 data stream. So, I guess the first question to ask is: “what does an RC5 data stream look like?” A second one might be: “how does it work?” and a final one would be: “how can I decode it?”. These are all questions I had to ask of myself before I could come up with a working design, and hence this section shall answer those questions.

  • What does RC5 look like?

Firstly, to find out what an RC5 data-stream looks like, you can employ one of two techniques. Either you can try to find some written reference to an RC5 data-stream, or you can try to measure one. I did both. For written references, google is your friend. You will find that I am not the first Electronics hobbyist to try to decode an RC5 data-stream – far from it in fact. Plenty of other Engineers/hobbyists have done this before! That said, I haven’t yet found anyone else who has designed a solution using the C language so if C is your poison you’ve probably come to the right place.

If you do take the time to trawl google results you’ll probably do well to find a diagram better than this one:

RC5 Protocol provided by davshomepage

This diagram was found at davshomepage and I think it is a good rendition of the RC5 protocol. This particular diagram is showing the following information:

  • Start Bits: 11 (these are always logic 1)
  • Toggle: 0
  • Address: 00000
  • Command: 000001

It also clearly shows the timing for a single RC5 encoded bit, as well as the timing for one full transmission in its entirety. If the logic levels look a bit weird to you, it’s because they’re Bi-Phase (Manchester) encoded. We’ll get to that later.

So that’s pretty much answered the first question, “what does RC5 look like”, but just for completness I’m going to show you what it looks like if you try to measure it. In order to do this experiment, I purchased an IR receiver device sensitive to 36Khz (because RC5 uses 36Khz modulation) with a demodulator built inside. You can receive the stream using a simple photodiode if you want, but then you’re going to have to demodulate it and you’ll need to concern yourself with other problems such as gain control and noise reduction etc. You can buy very small modules that have all of these features built in, so my opinion is why burden yourself with the hassle? Don’t reinvent the wheel, life is too short! The little module I used was a TSOP2236 which you can buy readily from Farnell.

All you need to do to start experimenting with one of these devices is to connect it up to a power supply and you’re good to go. If you read the datasheet it’ll start telling you about using pull-up resistors and connecting some capacitive filters etc, which is all very relevant and important to include in your final design but for the purpose of just playing around and experimenting you don’t need any of that stuff – power connections are all you need to do.

So, with some power connections made (I’d show you a picture but what’s the point – it really is that simple) we’re ready to receive an RC5 data stream. All we need now is an RC5 generator. For this I used an old Philips Universal Remote Control set up for TV and VCR modes. Philips designed the RC5 protocol, so most of their older equipment uses it. I also experimented with a universal remote application for Windows CE and that worked fine as well. You need to be a little bit careful here because your IR receiver package will receive your datastream regardless of the protocol – it won’t care whether it’s RC5 or not. It’s easy to recognise an RC5 protocol though, just compare it to the diagram on the previous page, paying particular attention to the start-bits and the number of bits in total. The data stream should also be Manchester Coded (or bi-phase coded, same thing). What’s Manchester Coding? We’ll get to that in the next section.

So, with the RC5 generator to hand and my IR module connected up to a power supply, I just need to press a button on the remote control and the IR module should recieve the infra-red light, demodulate the data stream, and output a manchester coded packet of data on its output pin. To see this, we need to connect the output pin to a Digital Storage Oscilloscope. If you don’t have one of these then you’re not going to be able to do the experiment yourself, but you don’t really need to unless you’re particularly interested – just check out my results on the next page!

RC5 data stream captured on Tektronix TDS3032. Data = 08, Address = 05.

This is what an RC5 Data Stream looks like if you measure it. I captured this shot using the Single Sequence Aquisition mode on my Tektronix DSO. To generate the RC5 I used an old Universal Remote Control set to VCR mode. I happen to know from previous experiments that a VCR remote is assigned Address number 5, so if you decode this stream (I’ll show you how next) you’ll find that the address is indeed 05. Also, I pressed number “8” on the Remote and, again from previous experience, I have found that the numbers 0 – 9 on the keypad are encoded as Data 00 – 09 respectively.

San Bergmans has compiled a small list of some RC5 codes on his website here. The list is by no means exhaustive, but it gives you the general idea. In addition to San’s listed codes, there are also codes for satellite receivers, CD players, and lots of other stuff. I have found through my studies that the RC5 protocol is not fully populated (i.e. not all of the possible addresses / commands have been used) so it is possible to make up your own little address and command codes to control your own equipment, without fear of inteference with other commercial products.

San’s site is also a good reference if you’re hoping to learn more about the RC5 protocol or indeed any of the other Remote Control protocols that exist!

Zoomed into one bit of RC5 data.

This shot is merely a close-up of the data on the previous page, using the zoom function on the instrument. The zoom function is quite handy for seeing the fine details of your aquisition, and I used it here to zoom in on one single bit of the Manchester encoded data.

The RC5 protocol specifies that one single bit should be 889uS long but in practice, with my Remote Control, I found that it actually measured 812uS (see the cursor readings on the right hand side of the image), which is approximately 10% outside of that which the protocol specifies. This has implications for the design of an RC5 Decoder, because it means that the system will need to measure the length of a single bit of the encoded data, to account for inaccuracies in the RC5 generator. Thanks to Manchester Encoding, this is actually quite easy. The whole point of Manchester Encoding is that it is self-clocking. This is what I’m going to talk about next, and in the process of talking about Manchester Encoding it’ll become clear how the RC5 data can be decoded.

  • How do I decode RC5?

Now, to answer that question it’ll be necessary to talk about Manchester Encoding. Once the details of Manchester Encoding are understood, it will then be quite a simple task to analyse an RC5 stream and see how it might be decoded. We’ll do this later using the stream I captured on previous pages, and see if we do indeed arrive at Address: 05, Data: 08. Once all of this has been understood, we are then presented with the problem of how to accomplish the decoding task using an Electronic solution. I came up with a software based solution which I shall present later on!

Manchester Encoding

Before I get into Manchester Encoding, I want to illustrate the problem that arises when your data stream is not Manchester Encoded.

Usually, digital data communication requires at least two separate lines – clock and data. The clock line is required for synchronisation purposes, so that the receiver knows when to sample the incoming data. For example, suppose I were to transmit an 8-bit data stream comprised of the data, “10001100“. This data stream might look something like that illustrated below:

Now, it’s not immediately obvious that the data above is equal to 1001100 is it? That’s because you don’t know where the data starts or where it ends, or even how long a single bit is. It would seem that the first logic 1 is a single bit, but how do you know? It could be 1, 2 3, or any amount of bits long. And, if we accept for the moment that it is 1 bit, then is that a logic 0 at the start? Or does the data start with the logic 1? And where does it end – how many logic 0’s are there on the end of that stream?

To make matters worse, what if I were to transmit 00000000? That’s a perfectly valid data stream, but without any kind of synchronisation technique (a clock) your only option for data recovery would be to agree a communications speed up-front with the transmitter.  In fact, some communications protocols do exactly that! RS232, for example, relies upon us both agreeing – transmitter and receiver – that we’ll talk at a certain BAUD rate before we can exchange any data.  After we’ve agreed the BAUD rate, we each have to trust the other’s internal clocks to be stable and accurate, so that 9600 BAUD means the same thing to me as it does to you.  Communication in this manner works for small data packets.

In regular wired data communication busses, a clock line is normally included so that you know where to sample the line in order to recover the correct data. Data is either sampled on the rising edge or falling edge of the clock, depending on how the system has been designed. To illustrate a rising edge system, see the diagram overleaf which shows how the above signal could be sampled and recovered using a clock signal.

Recovering Data with a clock

The following diagram shows how the previous data is recovered using a clock signal:

With the addition of the clock signal it is suddenly easy to reconstruct the data. Data is only sampled on the rising edge of the clock line, and in this manner the original data (10001100) is correctly reconstructed.

Manchester Encoding – A Self-Clocking Communications System

In order to get around the problems caused by long strings of logic 1’s or logic 0’s, where there is no clock to aid data recovery, a clever person came up with Manchester (also called binary phased shift) keying. I’m not actually sure who that clever person was – answers on an email!

In Manchester Coding, logic 1’s and logic 0’s are no longer represented by simple high and low voltages. Instead, they are represented by a rise in logic level and a fall in logic level respectively. This is illustrated below:

Note that in some systems this is the other way around – a logic 0 can be represented by the low to high transition and the logic 1 by the high to low. It depends how the system has been designed.

To see how this method effects the previous transmission data 10001100, the data below has been generated using Manchester Code logic levels:

If you trace through the above diagram, you should be able to see that the original logic 1’s and logic 0’s are represented by low-high and high-low transitions. If you’ve understood this correctly, then a little further thought should convince you that the problematic data stream described earlier (00000000) would now be transmitted as a long string of high-low transitions under the Manchester Coding scheme. The clock signal is easily extracted from a manchester coded transmission, even when there are long periods of logic 1’s or 0’s! Also, the start point and stop point of the transmission is more easily determined.

For these reasons, a Manchester Coded data stream is often refferred to as “self clocking”. No separate clock line is required under this scheme.

29 responses to “RC5 Decoder”

  1. Thank you, Sir. I was doing the project on this topic and my Ma’am asked why this coding and you actually have explained it why.

  2. Thank you very much for such an interesting article. I am trying to do the same thing for the last few days but i am unable to decode the protocol. Can you please send me the code ?

  3. oops!! I forgot to add rc5_code is a 16 bit integer, therefore in the declaration it should be:
    unsigned int rc5_code;

    • Good work!

      I definitely agree that sampling the entire datastream and then doing analysis afterwards is a better way forwards. This method also opens the door to developing multiple decode algorithms to deal with different protocols. You could develop a SIRC decoder algorithm, for example, and give yourself the ability to decode these data streams as well.

  4. Brian, think I found a more reliable way to read the data – by reading all the 12 bits in one go and then extracting the Address and Command.
    void process_data (void)
    char i;
    for(i=12; i>0; i–)
    while (RB0 != Sync)
    TMR0 = 0;
    while (TMR0 != Timer)
    rc5_code |= RB0;
    rc5_code <> 1;

    Address = (rc5_code>>6) & 0x001F
    Command = rc5_code & 0x003F
    I’ve not inserted a function to extract the toggle bit since I dont plan to use it right now, but I’m sure it can be done easily.


  5. Thanks Brian. But there are some glitches still. Sometimes I am not getting consistent results, for eg. the PWR button is supposed to give address:000 and command:012, but at times I get address:031 and command:038. This happens with other buttons also albeit randomly. Still trying to figure out why – maybe the start bits are getting in the way?

  6. Dear Brian, finally got the code working – actually the code was working, only the remotes that I had lying around were not RC5!!. Went out and got myself a specific RC5 remote and voila, its working now. Thanks for all the support.

    • This is excellent news – I am glad you were able to get it working in the end!

      I have found old Philips Universal Remotes to be a good RC5 source. They have the added advantage that you can select different types of equipment (e.g. Satellite, DVD, VCR, TV) which have different addresses. So in one single remote you can have a source of RC5 commands with multiple addresses!

      The code I provided you was written when I was just learning C. There are many improvements that could be made. If you make any, feel free to submit your improvements and if I like them I’ll incorporate them into my code! 🙂

      Best of luck.

    • Hello.

      I don’t have any books that are specific to the HiTech C compiler and I would be surprised if any exist. What you really need is a good book on C programming specific to PIC Microcontrollers. Once you have this knowledge then applying it to any specific compiler is just a case of reading the compiler’s manual. But the skills learned in the C language will apply to all compilers and all types of Microcontroller.

      I have many many Ebooks on Microcontroller programming and embedded systems. Contact me via the ‘contact’ tab and supply a correct email address if you would like to have a chat about some exchanges 🙂

  7. Brian
    Tried everything but could not get it to work. I did some math and concluded that at 20MHz, the TMR0 is overflowing. Setting a high prescaler also does not help since TMR0 does not start counting for 2 times prescaler cycles after a write operation (TMR0=0x00). I’m looking at two options now – either use TIMER1 or sample the IR pin after fixed delay periods. Would greatly appreciate your opinion on this.

  8. Update – the code is responding to key presses but the problem is that the data presented on the lcd is the same for any key, i.e 10101 for address and 110101 for command. The data_validate function is working and passing on the baton to the process_data function. The problem seems to be in this function, there appears to be no change in RB0 state (I’m using RB0 as the input), only the sync bit is inverting every cycle which accounts for the output. I’m still at it, will keep you posted.

  9. Hi Brian
    Unfortunately I dont have a scope. But like I mentioned in my last post, the data that gets thrown up is the same irrespective of the key I press on the remote and that is 15h, 35h, and 31h (I’ve rigged up the lcd to display the hex codes). After the first key press nothing happens. What seems significant here is that the address (15h) translates into 10101 and the command (35h) to 110101. The alternate 1’s and 0’s looks like the “sync” bit alternating between 1 and 0. Anyway, my experiments continue, I’ll keep you posted.

    • Okay thanks Hari I would be interested to know how you get on.

      I think if I was in your position, without any test instruments, my next move would be to try and get the circuit into a debug mode. You could then put breakpoints in the code and try to see what is going on.
      Alternatively, in the absence of an appropriate debug setup, you could write debug data to the LCD to try and tell you helpful things about what’s going on.

      This is how it should work if all is well:


      • Oh, just one more thing, can I safely assume that you’re definitely using a remote control that generates RC5 data?

        Most old Philips remotes (old because newer equipment would use the RC6 protocol) used the RC5 protocol and in my experience old Sanyo remotes always used it as well.

        In my experiments I got hold of a Universal remote and then plugged in codes for Philips TV, VCR and Satellite to use as a reference RC5 generator. But I also confirmed it was definitely generating RC5 on a ‘scope before I started 😉

        • Brian, your comment about RC6 protocol has given me food for thought. The remotes that I’m using are definitely not old. One is a Kenwood RC-405 and the other is a Cambridge audio one. They may well be RC6. Can I use a software based oscilloscope (using the pc sound card) to analyse the output of the TSOP? If so I can easily confirm the protocol.

  10. You’re welcome Brian. I just tried out your code using a 16f8777 with a 20MHz crystal to display on a 16X2 lcd. Its not working – the first key press (any key) throws up Command:21, Address:53 and Toggle:49. After this there is no response to any key press. I think its a timing issue as your code was written for an internal oscillator. The 16f8777 does not have an internal osc. Can you help me out here?

    • Hi Hari,

      I’ll have to take another look at the code on the weekend to see if I can offer any explanation for that. I wrote that software four years ago so my memory of it is vague.

      One thing I do remember though is that the software tests the length of the first bit received to see if it’s likely to be RC5 data or not. I think I measured this using a built in timer. The only condition under which the code should proceed with the data stream is if the measured pulse is around 889uS. In your case the code is clearly satisfied with this first measurement (unless you’ve removed it?) so in that case we can rule out any timing issue related to your clock.

      Do you have a ‘scope? It would be good to take a look at the output from your IR receiver. I’ve had some messages from people who could not get this project to work before and the cause in their case was that they were using a standard IR LED to receive the RC5 datastream. For this project you have to use a proper IR receiver module (I used a TSOP2236) because it filters out any noise in the data. My code relies upon this filtration because it does not attempt to take account of a noisy data stream.

  11. Brian, I wish you could publish the rest of the article on the rc5 decoder soon. This is the best explanation of the Manchester coding/encoding that I’ve read so far and now I’m thirsting for more!!!!. I’ve downloaded your code and it seems simple enough for me to implement, but all the same I’d like to read your step by step explanation of the code. Looking forward to reading more of your articles.

    • Thank you for the kind words Hari.

      You are quite right I really do need to finish this article. I will make it my mission for this coming weekend!

      Regarding the RC5 decoder software, please be advised that I was only a beginner at C programming for PIC microcontrollers when I wrote that code. There’s nothing wrong with it as such but it’s one of those things where, with the benefit of a lot of extra learning, I would definitely write it differently if I was to do it again.

      One of the major flaws in my original code is that it captures and decodes the RC5 data stream in real-time. I think it would be much better if the software simply captured an entire IR datastream, stored it in memory, and then conducted post-capture analysis on the data. This would open up many more doors in terms of support for other IR protocols.

      In any case if you can find a use for the original code you are welcome to it. If you make any improvements please send them back to me!



  12. hi can u please send me the c code for rc5 lcd display please its urgent i need to implement in 89c2051

  13. Hi Brian, I think I’m already to correctly read the code, just failure to pass the lcd, but I think that I am not properly storing the bits that I read. Saved in two different vectors the command and address?

    I’m doing a project for the university hence my interest in this project!

    This is my project Only Decode:

    Best Regards

  14. Hi Brian, Thanks for reply! I’ll be eagerly waiting! 🙂

    I’m trying to make a decoder in AVR but is complicated! I am not sure that the command I’m using, uses the RC5 protoco, it’s a command Philips TDT l! = / Only a few days ago came the TSOP1736, and decoding that appears on the LCD is very strange! I am using 8Mhz clck in AVR. Sory my bad english!

    Best Regards

    • Hello there, thanks for the interest.

      I haven’t uploaded all my RC5 Decoder stuff yet, I really need to get on to it and finish my report on it. I’m also in the process of tidying up the software. Will upload the code when I’m done!


Leave a Reply

Your email address will not be published.