Understanding Philips RC-5 Protocol
Understanding Philips RC-5 Protocol
PhilipsRC-5
Often in the development stage of a project, we think that it would be useful to use a
remote control. The most commonly used type of control is the remote control through
infrared, like that used in any television or audio equipment.
We have two alternatives: either we develop our communication protocol from scratch (and the
hardware of the transmitter) or we adopt one of the existing ones in the market.
Perhaps the most widespread and about which more information can be found is the one used by
Philips, called 'RC-5'. This protocol has been adopted by many other manufacturers, so it is
It is possible to find 'generic' remote controls for very little money.
This document contains the necessary information for us to decode the messages.
sent by these remote controls in our projects.
Features:
The most outstanding features of this protocol are summarized in the following lines:
5 bits for addressing and 6 bits for the command (7, in the case of RC5X)
Manchester encoding (Bi-phase coding)
Carrier frequency of 36KHz.
Constant time for each bit, of 1.778ms (64 cycles at 36KHz).
The protocol:
The protocol consists of a train of square pulses at 36kHz (the so-called 'carrier'). Each '1'
is encoded as 889 microseconds of pulses, and 889 microseconds of 'silence'. The '0' is
encode as 889 microseconds of 'silence' and 889 microseconds of pulses. The total length of
"0" and "1" are identical, and they are 1778 microseconds (or 1.778 milliseconds). The following graph illustrates
clearly this:
Within a bit, exactly 64 pulses fit if the carrier is 36KHz. That is, the period of
A 36KHz signal has a period of 1/36,000 = 27.78125... µs, which, when multiplied by 64, gives exactly 1778.
µs. This is a good piece of information to consider for the design of our receiver's software.
In order for the receiver to know what the remote sender is 'saying', it must be able to interpret the 'frames'.
of zeros and ones that it sends. Each frame is a command and is composed of 14 bits (15 in the
case of the RC5X). Of those 14 bits, the first 2 bits are for 'start': they are always '1'. The
the third bit is inverted each time a key is pressed and released again, in order to distinguish if
a key is held down or has been pressed more than once. The following 5 bits
correspond to the address of the receiving device, and the last 6 to the transmitted command. This
allows the use of the same remote control to command different devices, simply by assigning to
each one a different address code.
There is a variation of the RC5 code called RC5X that has 7 bits to determine the command.
which allows 128 different commands vs. the 64 commands of the traditional RC5). The shape of the frame
it is the same, but the second start bit (S2) is used as the command bit 7.
Both in direction and in command, the most significant bit (MSB) is transmitted first and by
least significant bit (LSB)
The full length of the frame is equal to 14 * 1.778 us = 24.892 us. If the key is kept pressed
stressed, the plot is continuously forwarded, but with a pause equivalent to 50 bits (50 x
1.778 us = 88.900 us) between one transmission and another. As we mentioned before, looking at the status of the third bit
we can determine whether it is successive keystrokes of the same key (the bit would change) or of a
same "long" pulse (the bit remains in the same state)
In that case, we should consult the following tables to know what the commands are.
predefined by Philips:
Addresses. Those that are blank are not available. List of assigned commands for TV and VCR by
assigned, and it's a good idea Philips.
use them for our projects.
We start from this theoretical part to program the reception of a command and the sending with RC-5 protocol.
TRAMA RC5
1 1 0 0 0 1 0 1 0 0 0 0 0 1
Second bit Start bit of RC5 (to '1'). In RC5X it is used as command bit 7.
4th, 5th, 6th, 7th and 8th (5 bits) Addresses. In this case it is worth 00101 = 5 HEX VCR
9th, 10th, 11th, 12th, 13th and 14th (6 bits) Command. In this case 000001 = 1 HEX Key 1
Example of use of TV1 and PROG+ button 0x3021 11 0000 0010 0001
1 1 0 0 0 0 0 0 1 0 0 0 0 1
If I press the PROG+ key again 0x3821 111000 0010 0001 (In blue, the bit that changes)
1 1 1 0 0 0 0 0 1 0 0 0 0 1
If we hold down a key, the same frame is sent at intervals of about 114 microseconds.
We connect:
GND 220 Ohm resistor Cathode Infrared diode Anode pin 5 PWM.
We put two buttons and an infrared EMITTER diode as seen in the graph.
Left button (pin 12) Send a burst to raise a channel (prog+).
FUNDAMENTAL
Raise or lower the channel by pressing one button or another, sending the information via the emitting infrared LED.
The greatest difficulty is sending a burst (frame) of information, with RC5 protocol, so that a TV or VCR can...
interpret correctly.
We are going to create a function called pulses to generate the 32 cycles of impulses. Each pulse has about 18.52.
high level microseconds and about 9.26 low level microseconds.
NOTE: Each instruction of the program takes about 8 microseconds to execute, so it is necessary to keep that in mind.
take into account when making our function.
void pulses()
{
// long time = micros();
}
// time = micros() - time; // measures the time in µs it takes to execute the loop.
//[Link](time);
The text in red, used for debugging, displays the total time of the 32 impulses, which must be given.
approximately 889 µs.
When used for the plot, you need to put the comment // back to avoid wasting time. This would make
that the plot instead of 25 ms becomes greater, which implies that the receiver would not interpret it well.
I obtained the delays of 11 and 3 by measuring the high level time and low level time (with the text in red, but between
the two lines of each level).
Next is the commented program. It is programmed for a TV. To switch channels up and down.
/* Result on screen when pressing button 2 (pin 11) for the 2nd time. */
Data to send: 11100000100001
1 10000000000000
1 1000000000000
1 100,000,000,000
0 10000000000
0 1000000000
0 100000000
0 10000000
0 1000000
1 100000
0 10000
0 1000
0 100
0 10
1 1
*/
}
long tiempo_trama = micros(); // We are going to measure the frame, which should be about 25 ms (25000 µs)
It could be REMOVED
// long tpo2 = micros(); // tpo2 measures the transmission time of the 2 start bits (1.5 actually)
// SEND the 2 start bits (The 1st part would be to send a zero for 889 µs. It would not do anything (not needed))
pulses(); // 2nd part of the first start bit. Pulse train 889 µs
space(); // 1st part 2nd start bit. Low level 889 microseconds
pulses(); // 2nd part of the 2nd start bit. End of sending two start bits. Pulse train 889 µs
// tpo2 = micros() - tpo2;
// [Link](tpo2); // Result 889+889+889 = approximately 2667.
void loop()
{
if (digitalRead(button1))
{
if (switch)
{
//data_one();
sendData(0x3020); // 0x3160 prog+ VCR
conmuta = 0; 0x3020 prog+ TV
}
else
{
sendData(0x3820); // 0x3960 prog + 2nd press VCR
conmuta = 1; 0x3820 prog+ 2 pulse TV
}
delay(100);
}
if (digitalRead(button2))
{
if (toggle)
{
//data_one();
sendData(0x3021); // 0x3161 prog- VCR
switch = 0; 0x3021 prog+ TV
}
else
{
enviarDato(0x3821); // 0x3961 prog- 2ª pulsacion VCR
conmuta = 1; 0x3821 prog+ 2 pulse TV
}
delay(100);
}
void pulses() // Deduced from a program: two high times and one low.
{
//long time = micros();
for (int i=0; i < 32; i++)
{
digitalWrite(pinIRSalida, HIGH); // Set the pinIRSalida (pin 5) to high. Pulse.
delayMicroseconds(11); We keep it at 18.52 µs = 11 + time it takes for one instruction
}
// time = micros() - time;
//[Link](time);
void space()
{
digitalWrite(pinIRSalida, LOW); // Sets pin 5 to low level. Does not send data.
delayMicroseconds(870); // Delay of 889 µs = 870 + instruction time
}
GND Anode of the infrared receiver Cathode Resistance of about 300K Vcc (5v)
From the cathode, we take an alpin 2 PWM connection. It corresponds with the 0 interruption of the Arduino.
Interrupt 0 on pin 2.
Interruption 1 on pin 3.
The Arduino MEGAIt has 4 more: interruption 2 (pin 21), 3 (pin 20), 4 (pin 19) and 5 (pin 18).
RISING it triggers when the pin goes from low to high HIGH)
FALLING it triggers when the pin goes from high to low (HIGH) LOW
void setup()
{
pinMode(pin, OUTPUT);
attachInterrupt(0, blink, CHANGE); // Executes the blink function when it changes
level on pin 2
}
void loop()
{
digitalWrite(pin, state); // it runs continuously, but only changes when it
produce a level change on pin 2 (interrupt 0)
}
detachInterrupt(interruption)
The use of interrupts is very good for controlling input data that should not wait in the loop.
loop and execute a function that is not in the loop.
In our case, the function of decoding a signal from a remote control will only be executed when it has been
produced the interruption, which causes a high level at pin 2 (interrupt 0).
Below is the program to receive data from a remote control using the RC5 protocol (Philips).
(We read data every 100 microseconds approximately, when an interruption occurs on pin2)
The program is commented and displays the received data on the screen in such a way that we begin to understand the
lines of code). Program name: receive_infrared_data_arduino.pde
void setup()
{
[Link](9600);
set pin mode(pulsador1, INPUT);
// INTERRUPTION. Execute the function "receive" when pin 2 goes HIGH
attachInterrupt(0, receive, HIGH);
}
void loop()
{
When button1 is pressed, we display the result on the screen.
if (digitalRead(button1) == HIGH)
{
[Link](" PRESSED ");
Times pressed
[Link](counter);
[Link](" RESULT = ");
[Link](result, HEX);
counter++;
It stays in this loop until button1 is released.
while (digitalRead(button1) == HIGH)
{
}
delay(300);
}
void receive()
{
long times[28];
boolean overflow = 0;
boolean error = 0;
int nb = 2;
int nbtotal = 0;
boolean cambia_nivel = 1;
// I initialize the times to zero.
for (int i=0; i < 28; i++)
{
times[i] = 0;
}
When we receive a positive impulse
if (!digitalRead(2))
{
We detected the first high level. We save the data times[1], about 7
while (!digitalRead(2))
{
times[1]++;
delayMicroseconds(100);
}
// If any time is less than 700 (7*100) microseconds, it gives an ERROR.
Each level is at least 889 microseconds.
if (times[1] < 6)
{
desbordamiento = 1;
error = 1;
}
If the first data is correct, that is, high level. Time over 7.
if (!error)
{
It can be done in several ways, tried, but I think this one is better refined.
I advise you to try other possibilities that you come up with. Objective: to be able to make the emitters and
detectors of other protocols like RC6, NEC, SONY, NOKIA, etc
27
3 10
46
5 19
66
7 10
8 15
9 18
10 15
11 18
12 6
13 10
14 7
15 10
16 6
17 10
18 6
19 10
20 15
21 10
22,834
Result obtained
11100101000001
3941
1
0 and 1 are the first start bit which is '1', otherwise we wouldn't display this screen.
The 22 is worth 834 *100 = 83400, which corresponds to the downtime between bursts.
101001011001100101010101101 It is missing the initial '0'. We take the odd numbers as the final result.
1 Pulsed channel.