; IR REMOTE CONTROL ; for Toshiba CATV Home Terminal model TCJ552B ; Version 3.1 ; Copyright 2001 Tickets, All rights reserved ; ; * Use 3.58MHz resonator for proper operation ; ; NOTE: This code is written in Parallax SPASM assembler ; device pic16f84,hs_osc,wdt_off,protect_off,pwrt_on ID 'IRRC' ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; DEFINITIONS ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; Version ver_major = '3' ; Major version ver_minor = '1' ; Minor Version ; IR LED led_out = PortA.4 ; LED output/Active Low time_h = 22 ; Cycles of H bit for 0.56msec time_0 = 120 ; L duration for data 0 time_1 = 250 ; L duration for data 1 time_start = 95 ; Cycles of Leader (+255) delay_repeat = 90 ; Adjust for 108msec interval delay_gap = 40 ; Gap for first repeat code bit_cnt = 8 ; Bit count ; Key scan code_system = 49h ; Toshiba key_shift = 1ch ; Key scan code of SHIFT key_chup = 0ch ; Channel Up key_chdn = 10h ; Channel Down key_vrup = 14h ; Volume Up key_vrdn = 18h ; Volume Down data_shift = 32 ; Add to key code in shift mode col0 = PortB.4 ; COLUMN scan ports (Input) col1 = PortB.5 col2 = PortB.6 col3 = PortB.7 no_key = 0ffh ; Key matrix code for no key ; Port Settings porta_dir = 11100000b portb_dir = 11110000b porta_ini = 00010000b portb_ini = 00000000b portb_pullup = OPTION.7 ; 0 to enable PortB pull-up ; Control registers settings mask_int = 00000000b ; INTCON register mask_opt = 01111111b ; OPTION register ; Interrupt int_rbif = INTCON.0 ; PortB interrupt flag int_toif = INTCON.2 ; WDT int_rbie = INTCON.3 ; PortB interrupt enable int_gie = INTCON.7 ; General interrupt enable ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ org 0ch ; Top of available RAM time_cntr ds 1 ; Cycle counter delay_cntr ds 1 ; Delay counter cntr_1msec ds 1 ; Counter for 1msec wait cntr_15msec ds 1 ; Counter for 16msec wait cntr_100msec ds 1 ; Counter for 100msec wait cntr_1sec ds 1 ; Counter for 1sec wait cntr_nmsec ds 1 ; Counter for N msec wait (N in W) tx_data_buff ds 1 ; Store code to be transmitted code_buff ds 1 ; Store result data code from key_scan bit_cntr ds 1 ; Bit counter to send byte key_row ds 1 ; Row for keyscan key_column ds 1 ; Column for keyscan key_matrix ds 1 ; Result key matrix code (0-63) cntr_row ds 1 ; Counter for row scan cntr_col ds 1 ; Counter for column scan cntr_nokey ds 1 ; Counts key scan cycles to sense no-key shift_32 ds 1 ; Contains 00100000b in shift mode flag_row ds 1 ; NZ if row scan get key press flag_col ds 1 ; NZ if column scan get key press flag_nokey ds 1 ; NZ if no key is pressed for a while flag_continue ds 1 ; NZ if key press is continued flag_error ds 1 ; 0:No error NZ:Error ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ org 0 ; Top of program jmp start interrupt_routine org 04h ; Interrupt vector/NOT USED reti ; End of interrupt ; Version number retw 'Ver.',ver_major,'.',ver_minor ;------------------------- start call init ;------------------------- ; MAIN LOOP ;------------------------- main mov PortA,#10h ; Set scan port output to L mov PortB,#0h mov w,PortB ; Clear PortB input mismatch clrb int_rbif ; Clear RBIF for sure setb int_rbie ; Enable PortB mismatch int sleep ; Sleep untill interrupt occurs ; Process next instruction on interrupt ; No interrupt vector (04h) called ; since GIE is disabled clrb int_rbie ; Disable PortB interrupt clrb int_rbif ; Clear PortB interrupt flag call delay_1msec ; Remove key bounces call process_key ; Main Process goto main ; Wait for next key ;-------------------------------------------- ; KEY SCAN TABLE ; This should be placed within first 256 byte ;-------------------------------------------- key_table jmp pc+w ; W contains matrix code ; Returns data code in W ; 55h should be ignored retw 12h,11h,0fh,15h,16h,1ch,55h,1dh retw 17h,00h,19h,14h,1bh,03h,02h,01h retw 1fh,06h,05h,04h,1ah,09h,08h,07h retw 1eh,18h,0bh,0ah,55h,10h,13h,0eh retw 0ffh,55h,43h,55h,55h,5dh,44h,4eh retw 55h,55h,45h,55h,55h,55h,5bh,55h retw 55h,55h,5ch,55h,42h,55h,5eh,55h retw 55h,55h,5fh,41h,55h,55h,0feh,40h ;------------------------- ; POWER ON INITIALIZE ;------------------------- init mov INTCON,#mask_int mov OPTION,#mask_opt clrb int_gie ; Disable GIE ; Ports Direction mov !ra,#porta_dir ; All PortA for output mov !rb,#portb_dir ; RB0-3 for output, RB4-7 for output mov PortA,#porta_ini ; row4-7 to L,led_out to H mov PortB,#portb_ini ; row0-3 to L clr shift_32 ; Clear shift data (32) ret ;------------------------- ; Process Key Input ;------------------------- process_key clr flag_continue ; Prepare for new key input :loop call key_scan ; Scan keys cje key_matrix,#no_key,:finish ; No key, do nothing cje flag_continue,#0,:skip0 ; Skip0 if not continue cje key_matrix,#key_chup,:skip3 ; Repeat Channel Up cje key_matrix,#key_chdn,:skip3 ; Repeat Channel Down cje key_matrix,#key_vrup,:skip3 ; Repeat Volume Up cje key_matrix,#key_vrdn,:skip3 ; Repeat Volume Down call delay_15msec ; Eliminate key bounce goto :skip2 ; Don't process :skip3 ; Send Repeat code call tx_leader ; 9.0msec leader call delay_2msec ; 2.25msec gap call tx_bit ; 0.56msec 1 mov w,#delay_repeat ; 108msec interval call delay_nmsec goto :skip2 :skip0 cjne key_matrix,#key_shift,:skip ; Skip if not shift :wait_release call key_scan ; Wait till SHIFT key is released cje key_matrix,#key_shift,:wait_release mov shift_32,#data_shift goto :finish ; Shift data is set :skip ; Normal transmission process mov w,key_matrix ; Set key matrix code call key_table ; Get Remote Control code mov code_buff,w ; Set in transmit buffer call tx_data ; Send IR clr shift_32 ; Reset shift mode mov w,#delay_gap call delay_nmsec ; Adjust gap before repeat code :skip2 mov flag_continue,#1 ; Set continue flag goto :loop :finish clr flag_continue ; Key released call delay_15msec ; Eliminate key bounce ret ;------------------------- ; KEY SCAN ;------------------------- key_scan clr key_matrix ; Initialize scan matrix :loop1 clr key_column ; Prepare for new scan mov PortA,#1fh ; Clear PortA mov PortB,#0feh ; Set RB0 to low mov cntr_col,#4 ; Test four times :loop2 call row_scan or flag_row,#00h ; Test flag jnz :finish ; Yes, key is pressed setb c ; rl PortB ; Next row inc key_column ; Increment Key Matrix code djnz cntr_col,:loop2 :loop3 mov PortA,#1eh ; Set RA0 to low mov PortB,#0fh ; Clear PortB mov cntr_col,#4 ; Test four times :loop4 call row_scan or flag_row,#00h ; Test flag jnz :finish ; Yes, key press is sensed dec cntr_col jz :skip ; Avoid RA4(LED) to be Low setb c ; Column scan rl PortA inc key_column goto :loop4 :skip mov key_matrix,#no_key goto :no_key ; No key is pressed :finish mov key_matrix,key_row and key_column,#0000111b ; Use last 3 bits clrb c rl key_column ; Move to upward rl key_column add key_matrix,key_column add key_matrix,shift_32 ; Add 32 in shift mode :no_key ret ;--------------- row_scan clr flag_row clr key_row jnb col0,:finish inc key_row jnb col1,:finish inc key_row jnb col2,:finish inc key_row jnb col3,:finish inc key_row :exit ret :finish inc flag_row goto :exit ;------------------------- ; TRANSMIT DATA ;------------------------- tx_data call tx_leader ; 9.0msec leader burst call tx_bit1 ; 4.5msec space (gap) call tx_bit1 call tx_bit1 mov tx_data_buff,#code_system ; Send system code call tx_byte mov tx_data_buff,#code_system xor tx_data_buff,#0ffh ; Invert system code call tx_byte mov tx_data_buff,code_buff ; Send Data code call tx_byte mov tx_data_buff,code_buff xor tx_data_buff,#0ffh ; Invert data code call tx_byte call tx_bit ; End bit ;-------------------------- ; TRANSMIT LEADER ;-------------------------- tx_leader ; Send 0 for 9.0msec mov time_cntr,#0ffh ; Count 1 call :loop mov time_cntr,#time_start ; Additional count call :loop ret :loop clrb led_out ; Turn on LED nop nop nop nop nop nop setb led_out ; Turn off LED nop nop nop nop nop nop nop nop nop nop nop dec time_cntr ; Count cycles jnz :loop ret ;-------------------------- ; TRANSMIT BYTE ;-------------------------- tx_byte ; TX data in tx_data mov bit_cntr,#bit_cnt ; 8bits clc :loop call tx_bit ; Transmit LED pulse rr tx_data_buff ; Adjust duration jnc :skip0 ; Skip if 0 call tx_bit1 ; Bit 1 jmp :finish :skip0 call tx_bit0 ; Bit 0 :finish dec bit_cntr jnz :loop ret ;------------------------- ; BIT 0 DURATION ;------------------------- tx_bit0 mov time_cntr,#time_0 :loop dec time_cntr jnz :loop ret ;------------------------- ; BIT 1 DURATION ;------------------------- tx_bit1 mov time_cntr,#time_1 :loop dec time_cntr nop nop jnz :loop ret ;-------------------------- ; TRANSMIT LED PULSE ;-------------------------- tx_bit mov time_cntr,#time_h :loop clrb led_out ; Turn on LED nop nop nop nop nop nop setb led_out ; Turn off LED nop nop nop nop nop nop nop nop nop nop nop dec time_cntr ; Count cycles jnz :loop ret ;-------------------------- ; DELAY ROUTINES ; (Multi entry Multi exit) ;-------------------------- delay_1sec mov cntr_1sec,#10 :loop call delay_100msec djnz cntr_1sec,:loop ret ;------------ delay_nmsec mov cntr_nmsec,w ; Delay W msec :loop call delay_1msec djnz cntr_nmsec,:loop ret ;------------ delay_100msec mov cntr_100msec,#100 :loop call delay_1msec djnz cntr_100msec,:loop ret ;------------ delay_15msec mov cntr_15msec,#15 :loop call delay_1msec djnz cntr_15msec,:loop ret ;------------ delay_2msec call delay_1msec ;------------ delay_1msec mov cntr_1msec,#80h ; 1msec delay for 3.58MHz :loop nop nop nop nop djnz cntr_1msec,:loop ret