I have been trying on and off for a few months to simulate the ON/OFF button on a Sony Bravia TV remote, mainly as a vehicle to get up to speed with Arduino.
I finally got some success today, and now only need to bump the power through the IR LED (I think) via a transistor stage perhaps to improve the range.
I also built a PC file capture application for the Serial communication with the Arduino, allowing me to annotate the file on the run with comments etc. This is written in Delphi.
I feel that Arduino should have a supported microseconds() function, even if the fine accuracy is not perfect.
/*
* IRTinker
*
* Tinkering with a typical TV remote control to determine its key
* control sequences. My remote is a Sony RM-ED005 used with a Sony
* Bravia TV.
* The H/W uses a Dick Smith Z-1955 IR Receiver chip, wired as follows.
*
* Z-1955 .---------.----- 47 ohm ------- +Vcc
* pin 3 -------| |
* | |
* 2K2 ohm |
* | 47uF electro
* pin 1 -------. |
* | |
* 1000pF |
* | |
* pin 2 -------| |
* .---------.------------------- Gnd
*
* The IR chip output pin 1 connects to Arduino digital input pin 7
* Vcc (5V) and Gnd are obtained from the Arduino.
*
* Other receiver chips are detailed in LIRC documentation.
* See www.lirc.org/receivers.html
*
* The S/W essentially sits on the IR receiver pin, watching for
* changes in state, and recording the number of times it was detected
* in the previous state. We can then use overall time differences
* to determine actual times corresponding to each count.
*
* Raw results are written to serial output for analysis.
* Because things are happening at the 10 microsecond level, we can't
* afford to place delays or serial prints within the detection loop.
*
* Background LIRC Information
*
* Typical raw microsecond timings for this remote in the LIRC
* literature are as follows:- (TVBlue button example)
* 2304 600 1152 576 1152 576 1152 576 576 600 1152 576 1152 576
* 576 576 576 600 576 600 1152 576 576 576 576 576 576
* 576 576 576 576 20232, with 2 more repeats of this whole sequence.
* The numbers alternate ON/OFF times over a basic 38 kc/s carrier.
* The first few and the last few components of this sequence envelope
* the data for the particular button pressed.
*
* Processed Hex button LIRC formats are typically specified like
* <code name="TVChannel1" data="b5f"/>
* <code name="TVChannel2" data="80b5f"/>
* <code name="TVChannel3" data="40b5f"/>
* <code name="TVChannel4" data="c0b5f"/>
* <code name="TVChannel5" data="20b5f"/>
* <code name="TVChannel6" data="a0b5f"/>
* <code name="TVChannel7" data="60b5f"/>
* <code name="TVChannel8" data="e0b5f"/>
* <code name="TVChannel9" data="10b5f"/>
* <code name="TVChannel0" data="90b5f"/>
* <code name="TVEnter" data="b0b5f"/>
* <code name="TVUp" data="9eb5f"/>
* <code name="TVDown" data="5eb5f"/>
* <code name="TVLeft" data="deb5f"/>
* <code name="TVRight" data="3eb5f"/>
* <code name="TVPicture" data="2ab5f"/>
* <code name="TVVolumeUp" data="8cb5f"/>
* <code name="TVVolumeMute" data="4cb5f"/>
* <code name="TVChannelDown" data="1cb5f"/>
* <code name="TVChannelUp" data="c8b5f"/>
* <code name="TVVolumeDown" data="28b5f"/>
* <code name="TVChannelMode" data="48b5f"/>
*
* Results
* I experimented with the TVBlue, and Channel 1 and 2 and On/Off buttons.
* I have reformatted the results from the raw program output to the
* serial port to improve the readability.
*
* Seq TVBlue TVBlue On/Off Channel1 Channel2
* (count) (usec) (count) (count) (count)
* 0 0 0 0 0 0
* 1 -412 2801 -409 -410 -419
* 2 61 414 63 62 53
* 3 -221 0 1502 -220 0 -126 1 -227 0
* 4 65 442 67 65 60
* 5 -218 0 1482 -122 1 -124 1 -127 1
* 6 66 448 66 64 61
* 7 -216 0 1468 -216 0 -127 1 -125 1
* 8 68 462 67 61 63
* 9 -218 0 1482 -122 1 -126 1 -126 1
* 10 68 462 66 62 61
* 11 -119 1 809 -215 0 -126 1 -126 1
* 12 69 469 68 61 62
* 13 -121 1 822 -120 1 -127 1 -126 1
* 14 66 448 68 61 62
* 15 -215 0 1462 -123 1 -126 1 -125 1
* 16 68 462 64 62 63
* 17 -214 0 1455 -214 0 -214 0 -216 0
* 18 70 476 70 69 67
* 19 -212 0 1441 -118 1 -120 1 -119 1
* 20 71 482 69 68 69
* 21 -118 1 802 -120 1 -119 1 -119 1
* 22 70 476 68 69 68
* 23 -117 1 795 -120 1 -120 1 -120 1
* 24 70 476 68 67 68
* 25 -118 1 802 -120 1 -121 1 -119 1
* 26 3739 25425 3990 4267 4199
*
* Sequences repeat twice more for each button 27-52 53-78
* - indicates pin LOW
* At seq 1 a longer 'alert' pulse occurs
* At seq 26 a very long 'end of sequence' pulse occurs
* The even sequences are otherwise HIGH
* The odd sequences with counts around 120 are likely '1' bits
* The odd sequences with counts around 220 are likely '0' bits
*
* Summarising
* TVBlue 000011000111 = hex '0c7'
* On/Off 010101101111 = hex '56f'
* Ch 1 111111101111 = hex 'fef'
* Ch 2 011111101111 = hex '7ef'
*
* There is not much detailed agreement with the LIRC
* information except in the overall structure, but the
* Arduino platform turned this into a very feasible
* project.
*
* If there is not already, a time counter finer than
* 'millis()' would have been useful.
*/
/* I also experimented in the other direction, trying to actually
* turn the TV on etc. The loop function is amended to call 'decode'
* to analyze the Remote, or to call IRSender() to send an ON/OFF
* sequence to the TV.
*
* I used some code from the Forum/Playground to set up a 38400 Hz
* carrier, and turned it on off at pin 11. I am still at a loss
* as to whether the IR transmitting diode transmits natively at
* this frequency, or whether you need to supply the carrier at all.
*
* This code successfully turns the TV on/off, using pin 11 to 220
* ohmm to IR LED to ground, although the diode needs to be within
* 150 mm of the TV sensor. I will try a transistor amplification
* stage.
*
* I tuned the pulse and mark times using one Arduino running the
* detector stage, communicating with either the TV remote or a
* second Arduino running the simulated pulse sequence.
*
* I also built a Serial Capture program in Delphi which lets me
* nominate a capture file, and annotate it with running comments etc.
*/
extern volatile unsigned long timer0_millis; //timer0_millis is defined in wiring.c
#ifndef cbi // Definitions for setting and clearing register bits
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
#define SYSCLOCK 16000000 // main system clock of Arduino Board (Hz)
#define IROUT 11 // pin 11 is OC2A output from TIMER2
#define BURST_FREQUENCY 38400 //IR Burst Frequency in Hz
unsigned long time = 0;
unsigned long microseconds();
void setup_timer2(unsigned int freq);
uint8_t timer2top(unsigned int freq) ;
int ledXmt = 11; // IR transmitter diode to digital pin 3;
int ledPin = 13; // LED connected to digital pin 13
int ledIRR = 7; // IR receiver to digital pin 7
int readVal; // IR receiver read value (state)
int usec; // calibrate result (usec per digitalRead)
int Event[200]; // count of successive IR readings
int lastseen; // last state seen
void pulser(unsigned int usecsON, unsigned int usecsOFF)
{ TCNT0 = 0;
time = microseconds();
sbi(TCCR2A,COM2A0) ; // connect pulse clock
time = time + usecsON;
while(microseconds()<time){};
cbi(TCCR2A,COM2A0) ; // disconnect pulse clock
time = time + usecsOFF;
while(microseconds()<time){};
}
// return TIMER2 TOP value per given desired frequency (Hz)
uint8_t timer2top(unsigned int freq)
{ return((byte)((unsigned long)SYSCLOCK/2/freq) - 1) ;
}
void setup_timer2(unsigned int freq)
{ cbi(TCCR2A,COM2A1); // disconnect OC2A for now (COM2A0 = 0)
cbi(TCCR2A,COM2A0);
cbi(TCCR2B,WGM22); // CTC mode for TIMER2
sbi(TCCR2A,WGM21);
cbi(TCCR2A,WGM20);
TCNT2 = 0;
cbi(ASSR,AS2); // use sys