;************************************************************************************************** ;********************** Infrared Controller for Klaus Schmidinger's VDR *************************** ;************************************************************************************************** ; ; Author: Thomas Breuer (tb@tb-electronic.de) ; Version: 1.02 ; Date: 04 October 2003 ; ; ; History: ; V1.02 ; Self-synchronizing RC5 receive code which tolerates inaccurate RC5 timings. ; ; V1.01 ; Brown out detect deactivated. Some ATX power supplies exhibit a brown out on 5V_stby when turned ; on from standby. PIC will reset and LED will blink red instead of green ... ; ; ; Assembler source code for Microchip PIC16F628 ; Compile with Microchip MPASM ; ; Tab distance: 8 spaces ; Width: 100 chrs (for printing, courier 8pt fits on A4 portrait) ; ; instructions: lower case ; labels: lower case ; VARIABLES: UPPER CASE ; Macros: Mixed Case ; Definitions: Mixed Case ; ; ; Some notes on RC5 ; ; 14 RC5 bits: ; SSTAAAAACCCCCC ; ; S: 2 start bits, T: 1 toggle bit, A: 5 address bits, C: 6 command bits ; ; Usually both start bits are high. Extended RC5 uses the 2nd start bit for expanding ; the 6 command bits to 7 bits. After receiving a complete 14 bit word, this bit ; is inverted and added as bit 6 to the register 'RC5_CMD'. The toggle bit is ; copied to bit 7 of 'RC5_CMD'. The 5 LSBs of register 'RC5_ADR' contain the ; 5 address bits; the 3 MSBs are set to 0. ; ; Result after a valid code has been received: RC5_ADR: 000AAAAA RC5_CMD: TCCCCCCC ; ; Note that most IR receiver chips (e.g. SFH5110-xx) have an active low output, however, the ; PIC's internal comparator inverts the signal. An inverting driver transistor for the RS232 ; interface finally inverts and level shifts the signal again so that the standard LIRC ; configuration (i.e. active low) must be used. ; ;-------------------------------------------------------------------------------------------------- ; ; PIC16F628 connections ; ; PIN FUNCTION ; ; RB7 ICSP ; RB6 ICSP ; RA5 ICSP ; ; RB5 TestOut -- debug output for scope (active high) ; RB4 PWRin -- input for PC pwr switch (active low) ; RB3 RESETout -- output to drive transistor for MB reset (active high) ; RB2 PWRout -- output to drive transistor for MB ATX pwr on/off (active high) ; RB1 LEDgrn -- output for bicolor LED green anode (active high) ; RB0 LEDred -- output for bicolor LED red anode (active high) ; ; RA7 4.000 MC crystal ; RA6 4.000 MC crystal ; ; RA4 (unused) ; RA3 comparator C1 output -- transistor base drive for RS232 TX ; RA2 (internally connected to Vref = 1.25 volts) ; RA1 ATXin -- comparator C2 inverting input for sensing -5 volts of ATX power supply ; RA0 IRin -- comparator C1 inverting input for IR receiver chip ; ;--- Configuration -------------------------------------------------------------------------------- ; ; PIC16F628, Power up timer, no watchdog, HS-oscillator, *no* brown out detect, LVP off, CP off, ; MCLRE off, f = 4MHz list p=16f628 __CONFIG _pwrte_on & _wdt_off & _hs_osc & _boden_off & _lvp_off & _cp_off & _mclre_off include "p16f628.inc" ;--- Variables [all UPPER CASE] ------------------------------------------------------------------- cblock h'20' DATA_1 ; 16-bit shift register for incoming RC5 bits DATA_2 ; DATA_TMP1 ; temporary register for RC5 codes DATA_TMP2 ; temporary register for RC5 codes BITCOUNT ; counter for the RC5 bits COUNT ; universal temporary count register TMP ; universal temporary registers TMP1 ; TMP2 ; RC5_ADR ; received RC5 address after clean up: '000AAAAA' RC5_CMD ; received RC5 command after clean up: '0CCCCCCC' RC5_CMD_TMP ; temporary register for RC5 command RC5_CMD_TMP_1 ; temporary register for RC5 command KEYCOUNT ; counts the incoming RC5 pwr-key packets to set up a delay KEYCOUNT_1 ; counts the incoming RC5 0-key packets to set up a delay RC5_TX_1 ; 16-bit shift register for outgoing RC5 bits RC5_TX_2 ; EEADR_TMP ; holds the EEPROM address when calling the EEPROM write subroutine EEDATA_TMP ; holds the EEPROM data when calling the EEPROM write subroutine PWR_ON_DELAY ; 00...99 (recalled from EEPROM location h'00') PWR_KEY_ADR ; assigned RC5 pwr key address '000AAAAA' (recalled from EEPROM location h'01') PWR_KEY_CMD ; assigned RC5 pwr key command '0CCCCCCC' (recalled from EEPROM location h'02') D1 ; temporary registers for delay routines D2 ; D3 ; FLAGS ; flags, see definitions endc ;--- EEPROM default data -------------------------------------------------------------------------- org h'2100' ; adr content de d'45' ; h'00' PWR_ON_DELAY de b'00000101' ; h'01' PWR_KEY_ADR de b'00001100' ; h'02' PWR_KEY_CMD ;--- Definitions [all Mixed Case] ----------------------------------------------------------------- #define ATX_C_out cmcon,7 ; comparator 2 output #define IRin porta,0 ; input for IR receiver chip (active low) #define IRinTris trisa,0 ; tris register bit for IRin #define IR_C_out cmcon,6 ; comparator 1 output #define LEDred portb,0 ; output for bicolor LED red anode #define LEDgrn portb,1 ; output for bicolor LED green anode #define PWRout portb,2 ; output to drive transistor for MB ATX pwr on/off #define RESETout portb,3 ; output to drive transistor for MB reset #define PWRin portb,4 ; input for PC pwr switch #define TestOut portb,5 ; debug output for scope #define TurnOnDelay d'9' ; turn on delay when pressing remote pwr key to ; wake up from standby (9 makes approx. one second) #define RebootDelay d'15' ; additional reboot delay (in seconds) #define RC5_Flag FLAGS,0 ; 0: RC_5 code valid, 1: RC_5 code invalid #define Reboot_Flag FLAGS,1 ; 0: normal boot delay, 1: additional delay needed ;--- Macros [all Mixed Case] ---------------------------------------------------------------------- Bank_0 macro bcf status,5 bcf status,6 endm Bank_1 macro bsf status,5 bcf status,6 endm Test macro bsf TestOut bcf TestOut endm LED_red macro bsf LEDred bcf LEDgrn endm LED_grn macro bsf LEDgrn bcf LEDred endm LED_off macro bcf LEDred bcf LEDgrn endm ;--- Reset ---------------------------------------------------------------------------------------- org h'00' goto init ; reset -> init ;--- Interrupt ------------------------------------------------------------------------------------ org h'04' goto init ; no interrupt ;************************************************************************************************** ; Initialization ;************************************************************************************************** init ; configuration of porta and portb ---------------------------------------------------------------- Bank_0 clrf porta ; clear porta register clrf portb ; clear portb register Bank_1 movlw b'00000111' ; RA0...RA2 input, RA3...RA7 output movwf trisa movlw b'00010000' ; RB0...RB3 output, RB4 input, RB5...RB7 output movwf trisb bcf option_reg,7 ; enable portb weak pullups Bank_0 ; configuration of analog comparators ------------------------------------------------------------- movlw b'00000110' ; two common reference comparators with outputs movwf cmcon Bank_1 movlw b'11100110' ; Vref = 1.25 volts, connected to RA2 movwf vrcon Bank_0 ; timer0 ------------------------------------------------------------------------------------------ Bank_1 movlw b'01000000' ; timer0 internal clock, prescaler 1:2, enable portb weak pullups movwf option_reg ; Bank_0 ; timer1 ------------------------------------------------------------------------------------------ movlw b'00110001' ; prescaler = 8, internal clock, enabled movwf t1con ;************************************************************************************************** ; Main program ;************************************************************************************************** start clrf FLAGS ; clear all flags call copy_ee ; copy default eeprom values to RAM registers main_loop btfsc ATX_C_out ; check if ATX is standby goto green ; on --> LED green LED_red ; standby --> LED red goto pwr_sw green LED_grn pwr_sw btfss PWRin ; test PWRin (active low) goto pwr_sw_1 ; if low goto pwr_sw_1 btfss IR_C_out ; wait for high level at IR_C_out goto main_loop ; call rc5_rx ; call rc5_rx subroutine btfsc RC5_Flag ; RC5 code OK? goto main_loop ; no, goto main_loop LED_off ; turn off green LED for 50ms each time a valid code call delay_t4 ; has been received LED_grn pwr_key ; check if pwr key of remote control is pressed movfw RC5_ADR ; load RC5_ADR into w subwf PWR_KEY_ADR,w ; btfss status,z ; does PWR_KEY_ADR match? goto no_match ; - no, goto no_match ; movfw RC5_CMD ; - yes, load RC5_CMD into w andlw b'01111111' ; and clear toggle bit subwf PWR_KEY_CMD,w ; btfss status,z ; does PWR_KEY_CMD match? goto no_match ; - no, goto no_match ; movfw RC5_CMD_TMP ; - yes, toggle bit also unchanged? subwf RC5_CMD,w ; btfss status,z ; goto no_match ; - no, goto no_match ; btfsc ATX_C_out ; activate PWRout only if ATX is standby to power up PC goto vdr_pwr_down ; if on, VDR's shutdown script will turn off PC ; ATX is standby, now check if pwr key of remote control is ; pressed long enough (approx. TurnOnDelay * 114ms) incf KEYCOUNT,f ; - yes, unchanged, increment KEYCOUNT movfw KEYCOUNT ; sublw TurnOnDelay ; if reached TurnOnDelay, activate PWRout btfss status,z goto cont bsf PWRout ; activate PWRout for 250ms call delay_t6 bcf PWRout goto boot_delay ; and goto boot_delay no_match clrf KEYCOUNT ; clear KEYCOUNT cont movfw RC5_CMD ; copy RC5_CMD to temporary register movwf RC5_CMD_TMP ; for next toggle bit comparison zero_key ; check if 0 key on remote control is pressed ; at least 44 * 114ms (RC5 code repetition rate) = approx. 5s movfw RC5_CMD ; load RC5_CMD into w andlw b'01111111' ; and clear toggle bit btfss status,z ; does O key (command '0000000', any address) match? goto no_match_1 ; movfw RC5_CMD_TMP_1 ; toggle bit also unchanged? subwf RC5_CMD,w ; btfss status,z ; goto no_match_1 ; - no, has changed incf KEYCOUNT_1,f ; - yes, unchanged, increment KEYCOUNT_1 movfw KEYCOUNT_1 ; sublw d'44' ; btfss status,z ; reached 44 (approx. 5s)? goto cont_1 ; - no, loop goto pgm_or_reboot ; - yes, goto pgm_or_reboot no_match_1 clrf KEYCOUNT_1 ; clear KEYCOUNT_1 cont_1 movfw RC5_CMD ; copy RC5_CMD to temporary register movwf RC5_CMD_TMP_1 ; for next toggle bit comparison goto main_loop pgm_or_reboot btfss ATX_C_out goto pgm_mode ; PC is in standby --> enable program mode LED_red ; turn LED red to indicate that reboot has been initialized movlw h'1f' ; set address to h'1f' movwf RC5_TX_2 ; movlw h'3f' ; set command to h'3f' movwf RC5_TX_1 ; This combination is not used by the remote control. Suitable ; entries in lircd.conf and lircrc call a reboot script via irexec call rc5_tx bsf Reboot_Flag ; set Reboot_flag so that additional delay for green LED flashing goto boot_delay ; will be added and goto boot_delay ; ------------------------------------------------------------------------------------------------ pwr_sw_1 ; checks if pwr switch of PC is pressed for less or more than ; 5 seconds: if less --> power on/off, if more --> reset call delay_t4 ; 50ms delay btfsc PWRin ; still low after 50ms? goto main_loop ; if not, assume spike and goto main_loop btfss ATX_C_out ; ATX on or standby? goto turn_on ; standby, a reset would be quite useless, so turn on VDR clrf tmr1h ; clear timer1 registers clrf tmr1l ; movlw d'19' ; set COUNT to d'19', this makes approx. 19 * 262ms = 5 seconds movwf COUNT ; chk_low btfsc PWRin ; still low? goto vdr_pwr_down ; if not, pwr key was pressed < 5s --> turn off VDR btfsc tmr1h,7 ; check timer1 h register bit 7 (set after 262ms) goto dec_cnt1 goto chk_low dec_cnt1 clrf tmr1h ; clear timer1 registers clrf tmr1l decfsz COUNT,f goto chk_low ; not yet 5s, loop goto reset ; power key pressed > 5s turn_on bsf PWRout ; activate PWRout for 250ms call delay_t6 ; bcf PWRout ; goto boot_delay ; and goto boot_delay reset bsf RESETout ; activate RESETout for 250ms call delay_t6 bcf RESETout boot_delay ; variable delay from 0 to 127 s while LED is flashing green movfw PWR_ON_DELAY ; and no command is accepted, delay derived from user preset (0..99) btfsc Reboot_Flag ; add additional time (defined in RebootDelay) if Reboot_Flag is set addlw RebootDelay ; movwf COUNT bcf status,c rlf COUNT ; multiply COUNT by two as the g_flash routine takes only 0.5s sublw d'0' ; if COUNT=0 stop immediately btfss status,z goto g_flash bcf Reboot_Flag ; clear Reboot_Flag goto main_loop g_flash LED_grn call delay_t6 LED_off call delay_t6 decfsz COUNT,f goto g_flash goto main_loop vdr_pwr_down LED_red ; turn LED red movlw h'1f' ; set RC5 address to h'1f' and command to h'3e' and send the code movwf RC5_TX_2 ; This combination is not used by the remote control and will movlw h'3e' ; be send to LIRC instead of the remote's normal pwr key code. movwf RC5_TX_1 ; This way exactly *one* command can be sent instead of multiple ; (autorepeat of RC5 codes) -- VDR would start and immediately ; abort the shutdown if the pwr key is pressed a bit too long ... ; A corresponding entry must be added to lircd.conf and the ; original pwr key code must be removed. call rc5_tx ; ; Flash red LED while checking if a key on the remote control is ; pressed (which stops VDR from executing the shutdown script). ; If so, the programm returns to the main loop and the LED ; turns green again. Otherwise flash LED until ATX is in standby ; and finally turn LED red. Note: The remote's pwr key will be ; ignored (also to avoid problem with RC5/repeat and VDR). movlw d'57' ; set COUNT to d'57' for timeout couter movwf COUNT ; timeout is approx. 2 * 262ms * 57 = 30 seconds r_flash LED_red ; turn on red LED call tim_sub ; call timer subroutine and check if any remote key is pressed LED_off ; turn off LED call tim_sub ; call timer subroutine and check if any remote key is pressed decfsz COUNT,f goto r_flash ; and loop goto main_loop ; timeout after approx. 30 seconds (if shutdown fails) tim_sub ; clrf tmr1h ; clear timer1 registers clrf tmr1l ; ir_chk btfss IR_C_out ; high level at IR? goto tim_chk ; - no, check timer1 call rc5_rx ; - yes, call rc5_rx subroutine btfsc RC5_Flag ; RC5 code OK? goto tim_chk ; - no, check timer1 movfw RC5_CMD ; copy RC5_CMD to w and andlw b'01111111' ; clear toggle bit bcf status,c ; clear carry bit subwf PWR_KEY_CMD,w ; check if command is pwr key; this will be ignored btfss status,z ; goto main_loop ; key pressed, abort shutdown and goto main_loop tim_chk ; btfss tmr1h,7 ; check timer1 h register bit 7 (set after 262ms) goto ir_chk ; loop if not yet set atx_chk btfsc ATX_C_out ; wait until ATX is standby return ; still on, continue flashing goto main_loop ; now standby, goto main_loop ;************************************************************************************************** ; Program mode ;************************************************************************************************** pgm_mode movlw d'4' movwf COUNT rg_flash LED_red ; flash bicolor LED alternately green/red call delay_t6 ; (either for 250 ms) 4 times to indicate LED_grn ; that the program mode has been entered call delay_t6 decfsz COUNT goto rg_flash LED_off ; now ready to learn codes (LED off) learn_1 call ir_chk1 ; wait for high level at IR_C_out, timeout if idle for > 5s call rc5_rx ; call rc5_rx subroutinee btfsc RC5_Flag ; RC5 code OK? goto learn_1 ; no, try again movfw RC5_CMD ; copy RC5_CMD to w and andlw b'01111111' ; clear toggle bit movwf TMP1 ; copy to TMP1 and TMP2 movwf TMP2 ; bsf status,c ; check if command is 0...9 sublw d'9' btfss status,c goto learn_1 ; no, try again LED_grn ; turn on green LED for 250ms if a call delay_t6 ; valid code has been received LED_off movfw RC5_CMD ; copy RC5_CMD to temporary register movwf RC5_CMD_TMP ; for the next toggle bit comparison bcf status,c ; multiply TMP1 by 10 rlf TMP1,f ; for 10's of PWR_ON_DELAY rlf TMP1,f rlf TMP1,f movfw TMP2 addwf TMP1,f addwf TMP1,f learn_2 call ir_chk1 ; wait for high level at IR_C_out, timeout if idle for > 5s call rc5_rx ; call rc5_rx subroutine btfsc RC5_Flag ; RC5 code OK? goto learn_2 ; no, try again movfw RC5_CMD ; check if toggle bit has changed subwf RC5_CMD_TMP,w ; btfsc status,z ; goto learn_2 ; no, try again movfw RC5_CMD ; copy RC5_CMD to w and andlw b'01111111' ; clear toggle bit movwf TMP2 ; copy to TMP2 bsf status,c ; check if command is 0...9 sublw d'9' ; btfss status,c ; goto learn_2 ; no, try again movfw TMP1 ; add 10's and 1's addwf TMP2,w ; movwf EEDATA_TMP ; copy to EEDATA_TMP movlw h'00' ; set EEADR_TMP to h'00' movwf EEADR_TMP ; call write_ee ; and write to EEPROM LED_grn ; turn on green LED for 250ms if a call delay_t6 ; valid code has been received LED_off movfw RC5_CMD ; copy RC5_CMD to temporary register movwf RC5_CMD_TMP ; for the next toggle bit comparison learn_3 call ir_chk1 ; wait for high level at IR_C_out, timeout if idle for > 5s call rc5_rx ; call rc5_rx subroutine btfsc RC5_Flag ; RC5 code OK? goto learn_3 ; no, try again movfw RC5_CMD ; check if toggle bit has changed subwf RC5_CMD_TMP,w ; btfsc status,z ; goto learn_3 ; no, try again movfw RC5_CMD ; copy RC5_CMD to w and andlw b'01111111' ; clear toggle bit bcf status,c ; check if command is 0...9 sublw d'9' ; which can not be assigned btfsc status,c ; as pwr_key goto learn_3 ; yes, try again movfw RC5_ADR movwf EEDATA_TMP ; copy to EEDATA_TMP movlw h'01' ; set EEADR_TMP to h'01' movwf EEADR_TMP ; call write_ee ; and write to EEPROM movfw RC5_CMD ; copy RC5_CMD to w and andlw b'01111111' ; clear toggle bit movwf EEDATA_TMP ; copy to EEDATA_TMP movlw h'02' ; set EEADR_TMP to h'02' movwf EEADR_TMP ; call write_ee ; and write to EEPROM call copy_ee ; copy new values to RAM LED_grn ; turn on green LED for 250ms to indicate call delay_t6 ; that a valid code has been received LED_off clrf KEYCOUNT_1 ; clear KEYCOUNT_1 to reset zero key detection delay goto main_loop ir_chk1 ; wait for high level at IR_C_out, timeout if idle for > 5s clrf tmr1h ; clear timer1 registers clrf tmr1l movlw d'19' ; set COUNT to d'19', this makes 19 x 262ms = approx. 5 seconds movwf COUNT ir_chk2 btfsc IR_C_out ; wait for high level at IR_C_out return ; and return btfsc tmr1h,7 ; check timer1 h register bit 7 (set after 262ms) goto dec_cnt goto ir_chk2 dec_cnt clrf tmr1h ; clear timer1 registers clrf tmr1l decfsz COUNT,f goto ir_chk2 ; not yet 5s, loop clrf KEYCOUNT_1 ; clear KEYCOUNT_1 to reset zero key detection delay goto main_loop ; timeout after approx. 5s ;************************************************************************************************** ; RC5 transmit subroutine ;************************************************************************************************** rc5_tx ; we have: RC5 address '000AAAAA' and command '0CCCCCCC' bsf RC5_TX_2,7 ; set 1st start bit btfss RC5_TX_1,6 ; check command bit #6 and bsf RC5_TX_2,6 ; set 2nd start bit if necessary bcf status,c ; clear carry bit rlf RC5_TX_1 ; left shift RC5_TX_1 twice to bring command MSB to bcf status,c ; left-most position rlf RC5_TX_1 ; now the 16-bit shift register is ready for ; shifting out: RC5_TX_2 1S0AAAAA RC5_TX_1 CCCCCC00 bsf IRin ; set port register bit IRin high before setting to output Bank_1 ; to avoid a 1µs spike bcf IRinTris ; set IRin as output Bank_0 ; call delay_t6 ; 250ms delay for time decoupling (LIRC might still be busy with ; processing IR codes from the receiver and would not react to the ; the code generated below) movlw d'14' ; set BITCOUNT to 14 movwf BITCOUNT ; bit_test btfss RC5_TX_2,7 ; test all bits goto out_low_high ; remember that we have to invert them out_high_low bsf IRin ; output a high-low sequence at IRin call delay_t5 ; either state is 889µs bcf IRin ; call delay_t5 ; goto next_bit ; goto next_bit out_low_high bcf IRin ; output a low-high sequence at IRin call delay_t5 ; either state is 889µs bsf IRin ; call delay_t5 ; next_bit rlf RC5_TX_1 ; left shift the 16-bit register rlf RC5_TX_2 ; decfsz BITCOUNT ; until all 14 bits are out goto bit_test ; btfss IRin ; if the last bit was a high-low sequence, immediately set IRin bsf IRin ; high to terminate the RC5 code after the correct time call delay_t6 ; 250ms delay for time decoupling (IR codes from the receiver chip ; occuring directly after the code generated above would destroy ; the integrity of this code) Bank_1 bsf IRinTris ; set IRin to input again Bank_0 return ;************************************************************************************************** ; RC5 receive routine ;************************************************************************************************** ; ; in: 14 bit data from IRin resp. DTRin ; ; out: RC5_ADR (8 bit, 000AAAAA) ; RC5_CMD (8 bit, TCCCCCCC) ; RC5_Flag (1 bit) 0: RC5 code valid, 1: RC5 code invalid ; ; Self-synchronizing code which tolerates inaccurate RC5 timings. ; Tolerance is achieved by polling +/- approx. 250µs around each expected level change. To mark the ; received code as valid, the level before and after the edges must be opposite, no timer0 overflow ; (512µs) occurred, and two samples taken at 1200µs and 1500µs after each edge must be equal. rc5_rx clrf DATA_1 ; clear input shift register clrf DATA_2 ; movlw d'13' ; set BITCOUNT to 13 movwf BITCOUNT ; test ; 1µs mark call delay_t1a ; 1520µs delay until approx. 256 µs before next expected slope call delay_t1b pre_slope test ; 1µs mark clrf tmr0 ; clear timer0 register bcf intcon,t0if ; clear timer0 interrupt flag btfss IR_C_out ; IR_C_out high? goto poll_lo_hi ; poll_hi_lo btfsc intcon,t0if ; check for timer0 overflow (after 512µs) goto set_flag ; and set 'invalid' flag btfsc IR_C_out goto poll_hi_lo goto next_bit1 poll_lo_hi bsf DATA_1,0 ; set lsb in DATA_1 btfsc intcon,t0if ; check for timer0 overflow (after 512µs) goto set_flag ; and set 'invalid' flag btfss IR_C_out goto poll_lo_hi next_bit1 decfsz BITCOUNT,1 ; if 0: all 14 bits received (1st was used for goto shift ; trigger and has not been recorded); do not goto cleanup ; shift any further and go on with cleanup shift bcf status,c ; clear carry bit rlf DATA_1,1 ; left shift the 16-bit register DATA_2/DATA_1 rlf DATA_2,1 ; call delay_t1a ; aquire sample #1 clrf DATA_TMP1 ; clear temporary register btfss IR_C_out ; IR_C_out low? bsf DATA_TMP1,0 ; then set lsb in DATA_TMP1 call delay_t1b ; aquire sample #2 clrf DATA_TMP2 ; clear temporary register btfss IR_C_out ; IR_C_out low? bsf DATA_TMP2,0 ; then set lsb in DATA_TMP2 check ; check if samples are equal movfw DATA_TMP1 ; copy DATA_1 to w, andlw b'00000001' ; keep only lsb in w, xorwf DATA_TMP2,0 ; xor LSBs of DATA_TMP2 and w, btfss status,z ; if not equal discard data and goto set_flag ; goto set_flag -- no valid code has been received goto pre_slope ; and loop cleanup ; collected so far: DATA_2 000STAAA DATA_1 AACCCCCC movfw DATA_1 ; copy DATA_1 to w andlw b'00111111' ; clear bits 6 and 7 movwf RC5_CMD ; copy w to RC5_CMD btfsc DATA_2,3 ; toggle bit is 0? bsf RC5_CMD,7 ; if not, set bit 7 of RC5_CMD btfss DATA_2,4 ; 2nd start bit is 1? bsf RC5_CMD,6 ; if not, set bit 6 of RC5_CMD (extended RC5) rlf DATA_2 ; left shift two times rlf DATA_2 ; movfw DATA_2 ; copy DATA_2 to w andlw b'00011100' ; clear 3 MSB and 2 LSB movwf RC5_ADR ; and copy to RC5_ADR btfsc DATA_1,6 ; address bit 0 is 0? bsf RC5_ADR,0 ; if not, set bit 0 of RC5_ADR btfsc DATA_1,7 ; address bit 1 is 0? bsf RC5_ADR,1 ; if not, set bit 1 of RC5_ADR ; now we have: RC5_ADR 000AAAAA RC5_CMD TCCCCCCC bcf RC5_Flag ; clear RC5_Flag -- valid code has been received return set_flag bsf RC5_Flag ; set RC5_Flag -- no valid code has been received return ;************************************************************************************************** ; EEPROM read/write subroutines ;************************************************************************************************** write_ee Bank_0 movfw EEADR_TMP ; copy EEADR_TMP to eeadr Bank_1 movwf eeadr Bank_0 movfw EEDATA_TMP ; copy EEDATA_TMP to eedata Bank_1 movwf eedata bsf eecon1,wren ; enable write movlw h'55' ; eeprom write unlock sequence movwf eecon2 ; movlw h'aa' ; movwf eecon2 ; bsf eecon1,wr ; write w_ready btfsc eecon1,wr ; write completed? goto w_ready ; Bank_0 return ;-------------------------------------------------------------------------------------------------- copy_ee ; reads address and command for assigned remote power key ; and turn on delay value from EEPROM and copies them to ; the RAM registers PWR_KEY_ADR, PWR_KEY_CMD, and PWR_ON_DELAY Bank_1 movlw h'00' movwf eeadr bsf eecon1, rd movfw eedata Bank_0 movwf PWR_ON_DELAY Bank_1 movlw h'01' movwf eeadr bsf eecon1, rd movfw eedata Bank_0 movwf PWR_KEY_ADR Bank_1 movlw h'02' movwf eeadr bsf eecon1, rd movfw eedata Bank_0 movwf PWR_KEY_CMD return ;************************************************************************************************** ; Delay routines (1 cycle equals 1µs @ 4MC oscillator frequency) ;************************************************************************************************** delay_t1a ; total: 1200 cycles movlw 0xEE ; 1193 cycles movwf d1 movlw 0x01 movwf d2 delay_t1a_0 decfsz d1, f goto $+2 decfsz d2, f goto delay_t1a_0 goto $+1 ; 3 cycles nop return ; 4 cycles (including call) ;---------------------------------------------------------- delay_t1b ; total: 320 cycles movlw 0x69 ; 316 cycles movwf d1 delay_t1b_0 decfsz d1, f goto delay_t1b_0 return ; 4 cycles (including call) ;---------------------------------------------------------- delay_t2 ; total: 500 cycles movlw h'A5' ; 496 cycles movwf D1 delay_5 decfsz D1,f goto delay_5 return ; 4 cycles (including call) ;---------------------------------------------------------- delay_t3 ; total: 1255 cycles movlw h'F9' ; 1248 cycles movwf D1 movlw h'01' movwf D2 delay_6 decfsz D1,f goto $+2 decfsz D2,f goto delay_6 goto $+1 ; 3 cycles nop return ; 4 cycles (including call) ;---------------------------------------------------------- delay_t4 ; total: 50000 cycles ; 49993 cycles movlw h'0E' movwf D1 movlw h'28' movwf D2 delay_7 decfsz D1,f goto $+2 decfsz D2,f goto delay_7 goto $+1 ; 3 cycles nop return ; 4 cycles (including call) ;---------------------------------------------------------- delay_t5 ; total: 886 cycles movlw h'AF' ; 878 cycles movwf D1 movlw h'01' movwf D2 delay_8 decfsz D1,f goto $+2 decfsz D2, f goto delay_8 goto $+1 ; 4 cycles goto $+1 return ; 4 cycles (including call) ;---------------------------------------------------------- delay_t6 ; total: 250000 cycles movlw h'4E' ; 249993 cycles movwf D1 movlw h'C4' movwf D2 delay_9 decfsz D1,f goto $+2 decfsz D2, f goto delay_9 goto $+1 ; 3 cycles nop return ; 4 cycles (including call) ;---------------------------------------------------------- end