It is time to put my hands on the IR protocol.
The goal: To study IR protocol and gain the skills to work with it
Tools: a microcontroller PIC16f877A, an IR receiver TSOP1736(1738), devboard
Now, a piece of the information about the RC5 protocol as such.
The frequency: of the carrier is 36 KHz, so the period is about 27.8 us.
A modulation: in the RC5 protocol is realized in a next way: each single bit is divided by half in time. We seek for a transition, or the edge direction: the rising edge is one, the falling edge is 0 – the Manchester code.
One important thing we need to take into account – the transmitter amplifier usually is the common emitter configuration, so the logic should be inverted on a receiver side:
That’s the very basis of the coding scheme. Now to the modulation: each single bit is represented by 64 pulses, 32 which represent a high level will be switching with clock about 36KHz, and the low level you will get a constant level, no switching.
The data packet representation consists of 14 bits and has the next view:
Where:
S1, S2 – starting bits, always equal to 1, they will serve as an anchor to catch a start of transmission.
T – kind of checkbox, showing that the button on a remote is being hold, when it happened the T bit is toggling. An example of application: user wants to switch the tv to channel #2, without a T bit if user will hold the button long enough, it will produce 22 or 222 or 2222.
A4-A0 – an address, by this one system will determine what kind of device is receiving the signal. Here we have a list of devices and their addresses:
0 - TV
1 - TV2
2 - Teletext
3 - An extension for first two TVs
4 - A laser video player
5 - Videorecorder1
6 - Videorecorder2
7 - Reserved
8 - Satellite equipment?(SAT1)
9 - Extension for video recorders
10 - SAT2
11 - Reserved
12 - CD video player
13 - Reserved
14 - CD photo (no idea, what the heck is that)
15 - Reserved
16 - Pre-amplifier
17 - Reciever/tuner
18 - tape/vhs?
19 - Preamplifier 2
20 - CD
21 - Audio stand
22 - Satellite audio receiver(?)
23 - DCC record (?)
24 - Reserved
25 - Reserved
26 - Recording CD
27 - 31 - Reserved
Finally, С5-С0 – the command by itself, which also has the own specification. Everything has specification, smart guys developed the protocol.
0-9 - just numbers
12 - waiting mode
13 - Mute
14 - Setup
16 - Volume +
17 - Volume -
18 - Brightness +
19 - Brightness -
20 - Saturation +
21 - Saturation -
22 - Bass +
23 - Bass -
24 - Treble +
25 - Treble -
26 - Balance right
27 - Balance left
48 - Pause
50 - Fastforward
51 - Fastbackward
53 - Play
54 - Stop
55 - Record
63 - System choice (?)
71 - Display switch off(?)
77 - Linear function +
78 - Linear function -
80 - Up
81 - Down
82 - Menu
83 - Exit from menu
84 - Display the A/V status
85 - Left
86 - Right
87 - OK
88 - Picture in picture
89 - Picture shift
90 - Picture in picture - swapping pictures
91 - Strobe
92 - Multistrobe
93 - Image blocking
94 - Scan
95 - Choose picture in picture
96 - Mosaic
97 - Picture DNR(?)
98 - Save
99 - Strobe of the picture-in-picture
100 - Call for the main image
101 - Freeze of the picture-in-picture
102 - ? up
103 - ? down
118 - Alternative mode
119 - Options (different mode)
123 - Connect
124 - Disconnect
Time to move to the practice, that what I had:
The Chinese remote, I got it together with a TV tuner somebody gave away. There are different IR protocols, but by accident I found that this remote works with a Philips TV, so I made an “educated guess”.
To check my guess I brought the remote to my work lab and connected the LED leg to the scope:
You can think “why do I see such a weird waveform?”. Well this is because the signal we see there is from the transmitting LED, not from the receiver. So far so good, the theory seems to have an agreement with the practice – we have 14 bits in total, lets check the carrier frequency now:
The frequency is 38KHz! It was a quite wise decision to connect the remote to the scope first – it means that I need to buy 38KHz receiver, not 36KHz. Plus that something you certainly would be good to be aware of before coding the uC. Also, I stumbled at such words somewhere in the web:
The command data is a Manchester coded bitstream modulating a 36 kHz carrier. (Often the carrier used is 38 kHz or 40 kHz, apparently due to misinformation about the actual protocol.)
Due to misinformation, huh! Anyway, I do not care much, and I have a single remote, so not quite much of choices available for me.
The next movement for me is a building of the receiver. I had bought the TSOP1738 analogue, in the next package:
In that package the pinout is mirrored with respect to TSOP1736. The application diagram can be checked in the datasheet:
Good to have a scope handy, but sadly I did not have at the moment. If I would have it would be so easy to connect to the receiver input and check the signal type. Oh wait I have the one, built-in in Pickit2.
Connected, and pushing the “8” button:
There are clear two starting bits and the one could see 0b001000 = 8. The address is 0, since it is a remote from TV tuner. Now, how we can force our microcontroller to work with all this stuff? I developed my algorithm based on INTE and TMR1 interrupts.
The main difficulty in the program I met – we can’t trigger the absolute transmission starting point, what we see is is the edge, or already the middle of the Manchester coded bit S1. My algorithm is the next:
- Connect the receiver leg to the RB0 pin. Set INTEDG = 0, falling edge detection
- If the INTE interrupt is detected very first time then:
- Launch timer for the interval 1.25 ms (3/4 of one bit modulated at 38 KHz)
- Change INTEDG value on the inverted one
- If INTE interrupt happened not in the first time, then:
- Change INTEDG to the inverted one
- If INTEDG = bufer, launch TMR1 for 1.250 ms
- If TMR1 interrupt is detected, capture the RB0 state and put it to the buffer and save to the variable used for memory records
To make it simpler for understanding (for me as well), I made the next picture:
Put some attention to this picture: we have received byte 11000001001000. Using beforementioned algorithm we will get a bit different number: 10000010010001, the MSB 1 is lost, but we gained another 1 in the end, and the end always will be 1.
So what we need to do now is to simply remove this extra 1 in LSB part and parse the byte to determine an address and the command.
Okay, time to expose the code:
#include <htc.h> #include <stdio.h> #include "usart.h" #define _XTAL_FREQ 4000000 #define IRpin RB0 volatile static bit direction; //1 - rising, 0 - falling volatile unsigned char IRbyte; //recieved byte volatile bit buffer; //буфер для значений таймера volatile unsigned char bytecount; //количество байт __CONFIG(WDTDIS & UNPROTECT & LVPDIS & HS); void StartTimer() //refresh timer procedure { T1CKPS1 = 0; //no dividers T1CKPS0 = 0; T1OSCEN = 0; //internal ocs TMR1CS = 0; // Fosc/4 TMR1IE = 1; // TMR1 overflow interrupt TMR1H = 0b11111011; TMR1L = 0b00010110; //1.257ms TMR1ON = 1; // enable timer } void main() { TRISB0 = 1; //RB0 input init_comms(); //uart initialization printf("\r\nStart"); //debug message buffer = 0; //initial conditions IRbyte = 0; bytecount = 0; direction = 0; INTEDG = 0; //waiting fallinge edge interrupt GIE = 1; //go go go PEIE = 1; INTE = 1; while(1) { if (bytecount>13) //if we recieved already 14 bits { GIE = 0; //blocking interrups for a while printf("\r\nPressed button is %d", IRbyte); //throwing command to uart IRbyte = 0; //and back to 0 state bytecount=0; INTEDG = 0; buffer = 0; GIE = 1; } }//while(1) } void interrupt isr() { if (INTF) //RB0 { if (bytecount<1) //if this is a first time { direction = 1; //waiting rising edge interruption INTEDG = 1; StartTimer(); //launch the timer bytecount++; //increment counter of bits count } else //if not in the first time { direction = !direction; //change type of the edge interrup on the inverted one if (direction==buffer) //check if we can already relaunch the timer { StartTimer(); bytecount++; } //if (direction==buffer) INTEDG = direction; } //else INTF = 0; } //INTF else { //RB0 interrupt has higher priority if (TMR1IF) { buffer = IRpin; // RB0 state to buffer TMR1ON = 0; //disable timer TMR1IF = 0; if ((bytecount>7)&&(bytecount<14)) //grabbing command only { IRbyte <<= 1; IRbyte |= buffer; } } } }
Example of the work:
All works fine, just I don’t have the toggle bit processing so I can have some false commands without proper handling.
Pingback: Remote control for the fan | diymicro.org