; This piece of code can be used to decode RC5 signals with a pic 16f84 running at 4 MHz. It is based on ; an article from the Elrad magazine (7/96). It uses the portb-0 interrupt and the timer. This program ; is a bit different from the other RC5 decoders on the net: it is based on a state machine with 31 states ; When a RC5 frame is recieved, every 222 microsec a sample is taken from portb-0, 120 in total. ; The sample can be high or low, which triggers the statemachine to go into a different state (or not). ; I use this code for a preamplifier and for noice reduction the processor is in sleepmode until a code is ; recieved. Therefore the first RC5 frame is skipped, since the processor needs some time to wake-up and ; the frame is already 'ongoing'. ; So this is not the complete program, but just pieces to put into yours to decode RC5 !! ; Have fun with it! ; RAM locations RC5_Teller RC5_Bit_Count RC5_Command RC5_Address RC5_State S_Temp W_Temp Flags ; flags #define RC5_Toggle Flags,0 ; Togglebit #define RC5_Bit_State Flags,1 ; Status RC5 bit ; I/O port used: port B, bit 0 #define RC5_INPUT PORTB,0 ; Input from RC5 receiver ; define the RC5 reciever type you are using: ; ; x = 0 : active high output : TDA3047 ; ; x = 1 : active low output : TDA3048 / SFH505A #define ACTIVELOW x ; fill in 0 or 1 ; initialisation bsf STATUS,RP0 ; select bank 1 bcf OPTION_REG,T0CS ; source timer: internal clock movlw b'???????1' movwf TRISB ; Port B, bit 0 input bcf STATUS,RP0 ; select bank 0 bsf INTCON,GIE ; Enable Interrupts Global LOOP ; stop the processor and wait for a code bcf INTCON,INTF ; Clear flag bsf INTCON,INTE ; Enable RB0/INT sleep ; processor in sleep-mode, wake-up at new code ; >>>>> AT KEY-PRESS ON REMOTE THE INTERRUPT SERVICE ROUTINE IS DONE TO FETCH THE RC5 INFO movlw d'12' subwf RC5_Bit_Count,W btfss STATUS,Z goto LOOP ; number of bits not 12, error movlw d'xx' ; fill in your remote's address subwf RC5_Address,W btfss STATUS,Z goto LOOP ; not my address ; now you have the code and togglebit available. RC5_Command RC5_Toggle ; (i don't even use it) ; now your code here.... goto LOOP ; <<<<< INTERRUPT SERVICE ROUTINE >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> IntServ movwf W_Temp swapf STATUS,W movwf S_Temp ; push registers movlw d'120' movwf RC5_Teller ; number of samples = 120 movlw d'1' movwf RC5_State ; Set state at 1 clrf RC5_Bit_Count ; Bit counter = 0 clrf RC5_Address ; clear RC5 address clrf RC5_Command ; clear RC5 command movlw d'30' ; skip first frame because of wake-up time PIC call WAIT_MS ; use some kind of code to wait 30 miliseconds RC5_LUS movlw d'36' ; count 222 usec: load timer with (256-222) + 2 = 36 movwf TMR0 ; load timer bcf INTCON,T0IF ; clear flag #IF ACTIVELOW btfss RC5_INPUT ; skip next instruction if line is high voltage goto RC5_INPUT_HIGH ; line is low, active low, so input = 1 #ELSE btfsc RC5_INPUT ; skip next instruction if line is low voltage goto RC5_INPUT_HIGH ; line is high, active high, so input = 1 #ENDIF ; IF INPUT=0 RC5_INPUT_LOW movlw LOW STATE_TABLE_0 ; get low 8 bits of address addwf RC5_State,F ; add offset movlw HIGH STATE_TABLE_0 ; get high 5 bits of address btfsc STATUS,C addlw d'1' movwf PCLATH ; load high address in latch movf RC5_State,W ; load computed offset in W call STATE_TABLE_0 ; get new state goto CHECK_STATE ; IF INPUT=1 RC5_INPUT_HIGH movlw LOW STATE_TABLE_1 ; get low 8 bits of address addwf RC5_State,F ; add offset movlw HIGH STATE_TABLE_1 ; get high 5 bits of address btfsc STATUS,C addlw d'1' movwf PCLATH ; load high address in latch movf RC5_State,W ; load computed offset in W call STATE_TABLE_1 ; get new state ; NEW STATE OF STATEMACHINE KNOWN, CHECK FOR 0 (ERROR), 23 (ONE RECEIVED) OR 31 (ZERO RECEIVED) CHECK_STATE movwf RC5_State ; save new state movf RC5_State,F ; check if state=0 btfsc STATUS,Z ; skip goto if Z clear goto RC5_OUT ; leave state machine CHECK_FOR_23 movf RC5_State,W ; check if 1 recognised sublw d'23' ; check if state = 23 btfss STATUS,Z ; skip goto if state 23 goto CHECK_FOR_31 ; state not 23, check for 31 ; STATE 23, 1 RECOGNISED bsf RC5_Bit_State ; RC5 bit = 1 goto SET_RC5 ; ready with state 23 CHECK_FOR_31 ; check if 0 recognised movf RC5_State,W sublw d'31' ; check if state = 31 btfss STATUS,Z ; skip goto if state 31 goto END_STATE ; state not 31, ready ; STATE 31, 0 RECOGNISED bcf RC5_Bit_State ; RC5 bit = 0 ; 0 OF 1 RECOGNISED, SET TOGGLEBIT, ADRES OF COMMAND SET_RC5 incf RC5_Bit_Count,F ; Bit counter = Bit counter + 1 movf RC5_Bit_Count,W sublw d'1' ; check for first bit btfss STATUS,Z ; skip goto if bit 1 goto CHECK_FOR_SEVEN ; not bit 1 ; BITCOUNT = 1 : togglebit bcf RC5_Toggle ; Toggle = 0 btfsc RC5_Bit_State ; skip next instruction if RC5_Bit_State = 0 bsf RC5_Toggle ; Toggle = 1 goto END_STATE CHECK_FOR_SEVEN movlw d'7' subwf RC5_Bit_Count,W ; W = RC5 bit count - 7, C=0 if RC5 bit count < 7 btfsc STATUS,C goto BIT_7TO12 ; bit 7 or higher ; BITCOUNT = 2..6 : address bcf STATUS,C ; C=0 btfsc RC5_Bit_State ; skip next instruction if RC5_Bit_State = 0 bsf STATUS,C ; C=1 rlf RC5_Address,F ; Rotate C left into RC5 Address goto END_STATE ; BITCOUNT = 7..12 : command BIT_7TO12 bcf STATUS,C ; C=0 btfsc RC5_Bit_State ; skip next instruction if RC5_Bit_State = 0 bsf STATUS,C ; C=1 rlf RC5_Command,F ; Rotate C left into RC5 Command END_STATE ; check for frame sent by remote (=second frame, first one is skipped) movf RC5_State,W sublw d'1' ; check if state = 1 btfsc STATUS,Z ; skip goto if state not 1 goto RC5_LUS ; state = 1, don't wait for the timer since there is no frame yet ; check timer RC5_TIMER_LUS btfss INTCON,T0IF ; wait for timer goto RC5_TIMER_LUS ; recheck timer ; check samples decfsz RC5_Teller,F ; number of samples = number of samples - 1 goto RC5_LUS ; goto RC5_LUS if not ready with sampling ; ready with sampling RC5_OUT swapf S_Temp,W movwf STATUS ; Return STATUS swapf W_Temp,F swapf W_Temp,W ; Return W bcf INTCON,INTF ; clear flag bcf INTCON,INTE ; disable RB0/INT interrupt retfie ; Return setting GIE STATE_TABLE_0 ; next state ; state movwf PCL retlw d'1' ; 1 wait for a 1 retlw d'0' ; 2 retlw d'0' ; 3 retlw d'7' ; 4 retlw d'7' ; 5 retlw d'7' ; 6 retlw d'8' ; 7 retlw d'9' ; 8 retlw d'10' ; 9 retlw d'11' ; 10 retlw d'0' ; 11 retlw d'0' ; 12 retlw d'0' ; 13 retlw d'16' ; 14 startbit recognised retlw d'16' ; 15 retlw d'17' ; 16 retlw d'18' ; 17 retlw d'19' ; 18 retlw d'20' ; 19 retlw d'0' ; 20 retlw d'0' ; 21 retlw d'0' ; 22 retlw d'16' ; 23 1 recognised retlw d'16' ; 24 retlw d'0' ; 25 retlw d'29' ; 26 retlw d'29' ; 27 retlw d'29' ; 28 retlw d'30' ; 29 retlw d'31' ; 30 retlw d'15' ; 31 0 recognised STATE_TABLE_1 ; next state ; state movwf PCL retlw d'2' ; 1 start your engines, here we go! retlw d'3' ; 2 retlw d'4' ; 3 retlw d'5' ; 4 retlw d'6' ; 5 retlw d'0' ; 6 retlw d'0' ; 7 retlw d'0' ; 8 retlw d'12' ; 9 retlw d'12' ; 10 retlw d'12' ; 11 retlw d'13' ; 12 retlw d'14' ; 13 retlw d'15' ; 14 startbit recognised retlw d'24' ; 15 retlw d'24' ; 16 retlw d'0' ; 17 retlw d'21' ; 18 retlw d'21' ; 19 retlw d'21' ; 20 retlw d'22' ; 21 retlw d'23' ; 22 retlw d'15' ; 23 1 recognised retlw d'25' ; 24 retlw d'26' ; 25 retlw d'27' ; 26 retlw d'28' ; 27 retlw d'0' ; 28 retlw d'0' ; 29 retlw d'0' ; 30 retlw d'24' ; 31 0 recognised ; Timerloop, grabbed from the net, so if you recognise it, it could be yours: WAIT_MS movwf large_count ; x number of times 1 milisec wait Wait_Loop ; Loop x number of times call Wait_1ms decfsz large_count,1 goto Wait_Loop return Wait_1ms movlw d'100' ; 100 x 10us = 1000us = 1ms movwf small_count _10u_Loop nop ; 1 nop ; 2 nop ; 3 nop ; 4 nop ; 5 nop ; 6 nop ; 7 decfsz small_count,1 ; +1 goto _10u_Loop ; +2 = 10 cycles return