-- Sony Infrared Remote Control(aka SIRC) protocol decoder -- SIRC is widely used protocol for consumer entertainment devices -- such as TV's, VCR's, DVD players, Hi-Fi receivers, etc -- SIRC is found in 12-bit, 15-bit, 20- bit versions -- This decoder is for the 12-bit version -- -- 12-bit SIRC is comprised of a pulse-width modulated bit stream -- with 5 address bits and 7 data bits. A logical 1 is represented -- by a 1.2 mS burst of the 40 khz carrier, whereas a logical 0 -- is represented by a 0.6 mS burst of the carrier. -- -- The data stream is preceeded by a start burst 2.4 mS in duration -- of the 40 khz carrier and then the data is sent LSB first with the -- command preceeding the address. Commands are repeated every 45 mS -- (measured from start to start) as long as the button is pressed. -- For more info on this and other remote protocols see -- www.sbprojects.com/knowledge/ir.htm -- -- A short list of commands from a "universal" remote set to be a Sony TV remote -- button address command -- 1 01 00 -- 2 01 01 -- 3 01 02 -- | | | -- 0 01 09 -- note that the numbers are 1 less than face value except 0 -- vol- 01 19 -- vol+ 01 18 -- ch- 01 17 -- ch+ 01 16 -- mute 01 20 -- -- In this demo we are just displaying the address and command -- values on an LCD display, but by detecting a specific button press -- we could turn a pin on or off, thereby controlling a LED, relay, etc. -- As an example, say we wanted pin_B1 to turn on when we pressed "9" -- after the GetSIRC procedure completes in the main program simply code -- if (my_cmd == 01) & (my_add == 08) then pin_B1 = 1. -- As you see this is setup to use the internal oscillator but does work -- with an external crystal with no modification except changing the -- oscillator type. It should port to a 12F629/675 with minor -- modifications to account for pin differences and that those devices -- do not support LVP ( low voltage programming ) -- ********************************************************** -- ***** declare PIC and setup oscillator and options ***** -- ********************************************************** include 16f628 pragma target clock 4_000_000 -- 4 MHz xtal pragma target OSC INTOSC_NOCLKOUT -- internal osc pragma target MCLR external -- external MCLR pragma target WDT disabled -- no watchdog, please pragma target LVP disabled -- no low voltage programming pragma target PWRTE enabled -- ********************************************************** -- ***** declare any constants and variables used ******** -- ********************************************************** const byte LCD_ROWS = 2 -- LCD with 2 lines const byte LCD_CHARS = 16 -- and 16 characters per line var bit lcd_en is pin_B5 -- data trigger var bit lcd_rs is pin_B4 -- command/data select. var bit lcd_d4 is pin_A0 var bit lcd_d5 is pin_A1 var bit lcd_d6 is pin_A2 var bit lcd_d7 is pin_A3 var byte my_add = 0 var byte my_cmd = 0 var bit IR_pin is pin_B0 -- ****************************************** -- ***** setup input and output pins ****** -- ****************************************** pin_A0_direction = output pin_A1_direction = output pin_A2_direction = output pin_A3_direction = output pin_B0_direction = input pin_B4_direction = output pin_B5_direction = output -- ****************************************** -- ***** include needed support files ***** -- ****************************************** include delay include lcd_hd44780_4 -- LCD library with 4 data lines include print -- nice formatted output include format -- more nice formatting -- ****************************************************** -- ***** write any needed procedures or functions ***** -- ****************************************************** Procedure Get_SIRC is var byte lTime -- loop timer to detect if we have a "start burst", "1", or "0" var byte ir_add -- decoded ir device address var byte ir_cmd -- decoded ir command asm local StartLook asm StartLook: ir_add = 0 ir_cmd = 0 while(IR_pin == 1) loop lTime = 0 -- wait for it to be low and reset the counter end loop while(IR_pin == 0) loop -- while the pin is low which is our pulse count lTime = lTime + 1 -- increment every 200uS until pin is high _usec_delay (200) end loop if (lTime <= 10) then asm goto StartLook end if if (lTime >= 14) then asm goto StartLook end if -- Start too short or too long so restart lTime = 0 for 7 loop -- repeat 7 times for command ir_cmd = ir_cmd >> 1 -- if it was skipped or is done ORing then shift over the 1 while(IR_pin == 1) loop -- wait for it to be low and reset the counter lTime = 0 end loop while(IR_pin == 0) loop -- while the pin is low which is our pulse count lTime = lTime + 1 -- increment every 200uS until pin is high _usec_delay (200) -- 200uS delay end loop if (lTime >= 6) then ir_cmd = (ir_cmd | 0b01000000) end if -- If its high then OR a 1 in else skip -- if its less than 6 its a 0 so dont OR it end loop for 5 loop -- repeat 5 times for address/device ir_add = ir_add >> 1 -- if it was skipped or is done ORing then shift over the 1 while(IR_pin == 1) loop lTime = 0 -- wait for it to be low reset the counter end loop while(IR_pin == 0) loop -- while the pin is low which is our pulse count lTime = lTime + 1 -- increment every 200uS until pin is high _usec_delay (200) -- 200uS delay end loop if(lTime >= 6) then ir_add = (ir_add | 0b00010000) end if -- If its high then OR a 1 in else skip -- if its less than 6 its a 0 so dont OR it end loop my_cmd = ir_cmd my_add = ir_add end procedure -- *********************************************************** -- ******* main program begins here **************** -- *********************************************************** enable_digital_io() -- no analog pins used in this sample lcd_init() -- initialize LCD display lcd_clear_screen() -- clear screen and set cursor to line 1 column 1 forever loop if IR_pin == 0 then block Get_SIRC lcd_clear_screen() end block end if lcd_cursor_position(0,0) const byte str1[] = "addr = " print_string(lcd, str1) print_byte_dec(lcd, my_add) lcd_cursor_position(1,0) const byte str2[] = "comm = " print_string(lcd, str2) print_byte_dec(lcd, my_cmd) end loop