list p=pic16F84 include "p16f84.inc" __FUSES _XT_OSC & _PWRTE_ON & _WDT_OFF & _CP_OFF RAMbase equ 12 cblock RAMbase flags W_Temp S_Temp Prev_TMR0 RC5_Timer_Ovfl Delay RC5_Bit_Count RTC_H RTC_L RTC_32 RC5_3 RC5_2 RC5_1 RC5_0 endc ; ***** Definitions ***** #define TH1 d'18' ; threshold below which we count 1 bit #define TH2 d'18' ; threshold below which we count 2 bits #define Prev_RC5_Val flags,0 ; Last RC5 bit received #define Reading_RC5 flags,7 ; RC5 data reading in process #define SEL_BANK_0 bcf STATUS,RP0 ; Select Bank 0 #define SEL_BANK_1 bsf STATUS,RP0 ; Select Bank 1 #define IR_Input PORTB,4 ; Infrared module input #define CARRY STATUS,C #define ZERO STATUS,Z ; ***** RESET ***** org 0000h Reset_Vector goto Main_Start nop nop nop ; ; ***** Interrupt Vector ***** ; Interrupt_Vector if (Interrupt_Vector != 0x004 ) ERROR "Warning Interrupts must start at address 0x004" endif Push movwf W_Temp ; Save W swapf STATUS,W movwf S_Temp ; Save STATUS SEL_BANK_0 Disable_Int bcf INTCON,GIE ; Disable all Interrupts btfsc INTCON,GIE ; Are Interrupts disabled ? goto Disable_Int ; NO, try again btfsc INTCON,RBIF ; Skip PORTB4's Interrupt? goto RB4_Int ; NO, goto RB0 btfsc INTCON,T0IF ; Skip TMR0 overflow interrupt? goto TMR0_Int ; NO, goto TMR0 Pop swapf S_Temp,W movwf STATUS ; Return STATUS swapf W_Temp,F swapf W_Temp,W ; Return W retfie ; Return setting GIE ; ;***** Manage RB4 Int ***** ; RB4_Int bcf Prev_RC5_Val ; Set the previous RC5 value to 0 btfss IR_Input ; Current Input level is 1? bsf Prev_RC5_Val ; NO: Previous RC5 value was 1 bcf INTCON,RBIF ; Clear interrupt flag ; Now we have the value. ; Let's see how many bits we got (1 or 2) movf TMR0,W movwf Delay ; Delay = TMR0 movf Prev_TMR0,W subwf Delay,F ; Delay = TMR0 - Prev_TMR0 ; Delay = delay since last interruption btfss CARRY ; Is the result positive? (CARRY == 1) decf RC5_Timer_Ovfl,F ; NO: TMR0 overflew at least once, decrement RC5_Timer_Ovfl movf RC5_Timer_Ovfl,F ; YES: Check if RC5_Timer_Ovfl == 0 btfss ZERO ; Is it? (Z == 1) goto RC5_Long_Delay ; NO: there was a long delay, more than 1 overflow) movlw TH1 ; YES: let's check now how many bits we got subwf Delay,F ; Let's check if delay > TH1 (delay - TH1 > 0) ; Delay = delay - TH1 btfss CARRY ; Is it? (CARRY == 1) goto RC5_1_bit ; NO: We got 1 bit movlw TH2 ; YES: Let's then check if we got 2 bits subwf Delay,F ; Check if delay > TH2 (delay - TH2 > 0) ; Delay = delay - TH1 - TH2 btfss CARRY ; Is it? (CARRY == 1) goto RC5_2_bits ; NO: We got 2 bits goto RC5_Long_Delay ; YES: Long delay RC5_1_bit call Add_1_bit_to_RC5 goto End_RB4_Int RC5_2_bits call Add_2_bits_to_RC5 goto End_RB4_Int RC5_Long_Delay ; A long delay occured btfss Reading_RC5 ; RC5 data reading bit clear ? goto RC5_First_bit ; NO: end of RC5 frame goto RC5_Last_bit ; YES: beginning of RC5 frame RC5_First_bit call Clear_RC5 ; Clear all RC5-related registers (incl. flags) bsf Reading_RC5 ; start reading now goto RC5_Long_Delay_End RC5_Last_bit bcf Reading_RC5 ; stop reading now ;goto RC5_Long_Delay_End RC5_Long_Delay_End call Add_1_bit_to_RC5 ; Add first/last bit End_RB4_Int movlw d'28' subwf RC5_Bit_Count,W ; How many bits have we got? 28? btfsc ZERO ; bcf Reading_RC5 ; YES: stop reading now clrf RC5_Timer_Ovfl ; Reset TMR0 overflow counter for RC5 timing movf TMR0,W ; Save the current timer value movwf Prev_TMR0 goto Pop ; ;***** Manage TMR0 int ***** ; TMR0_Int bcf INTCON,T0IF ; Clear TMR0 interrupt flag ; Counting TMR0 overflows for RC5 timing movf RC5_Timer_Ovfl,W sublw 0xFF ; Is RC5_TMR0_Ovfl == 0xFF? btfss ZERO goto TMR0_Inc_RC5_Timer_Ovfl ; NO: then increment goto TMR0_RC5_End_of_Frame ; YES: See if it is the end of an RC5 frame TMR0_Inc_RC5_Timer_Ovfl incf RC5_Timer_Ovfl,F goto TMR0_Next TMR0_RC5_End_of_Frame btfsc Reading_RC5 ; Are we reading an RC5 frame? call End_RC5_Reading ; YES: put an end to it TMR0_Next ; Real Time Clock (32 TMR0 overflows for 1 second) decfsz RTC_32,F ; Count 1/32th of a second. 32th round? goto TMR0_Int_End ; NO, nothing happens movlw d'32' ; YES, Reinitialize counter to 32 (31 ?) movwf RTC_32 incfsz RTC_L,F ; Count 1 second. 256th round? goto TMR0_Int_End ; NO, nothing more happens incf RTC_H,F ; Yes, Count 1 in RTC_H TMR0_Int_End goto Pop ; End of Interrup Vector ; ;***** RC5 register routines ***** ; Clear_RC5 ; ** SUBROUTINE ** clrf RC5_0 ; clear RC5 registers (all 4) clrf RC5_1 clrf RC5_2 clrf RC5_3 clrf RC5_Bit_Count clrf flags return ; return from subroutine Shift_RC5 ; ** SUBROUTINE ** rlf RC5_0,F ; left shift RC5_0. MSb in carry rlf RC5_1,F ; left shift RC5_1. Carry to LSb, MSb in carry rlf RC5_2,F ; left shift RC5_2. Carry to LSb, MSb in carry rlf RC5_3,F ; left shift RC5_3. Carry to LSb, MSb in carry return ; return from subroutine Add_1_to_RC5 ; ** SUBROUTINE ** call Shift_RC5 ; Shift the RC5 registr by 1 bit bsf RC5_0,0 ; Set LSb to 1 return ; return from subroutine Add_0_to_RC5 ; ** SUBROUTINE ** call Shift_RC5 ; Shift the RC5 registr by 1 bit bcf RC5_0,0 ; Set LSb to 1 return ; return from subroutine Add_1_bit_to_RC5 incf RC5_Bit_Count,F btfss Prev_RC5_Val ; Previous RC5 value == 1? goto Add_one_0_bit_to_RC5 ; NO: Add one '0' bit goto Add_one_1_bit_to_RC5 ; YES: Add one '1' bit Add_one_1_bit_to_RC5 call Add_1_to_RC5 return Add_one_0_bit_to_RC5 call Add_0_to_RC5 return Add_2_bits_to_RC5 incf RC5_Bit_Count,F incf RC5_Bit_Count,F btfss Prev_RC5_Val ; Previous RC5 value == 1? goto Add_two_0_bit_to_RC5 ; NO: Add two '0' bits goto Add_two_1_bit_to_RC5 ; YES: Add two '1' bits Add_two_1_bit_to_RC5 call Add_1_to_RC5 call Add_1_to_RC5 return Add_two_0_bit_to_RC5 call Add_0_to_RC5 call Add_0_to_RC5 return ; ;***** RC5 End of Frame handling ***** ; End_RC5_Reading ;call Add_1_bit_to_RC5 ; This would add the opposite of the current bit call Add_0_to_RC5 ; Add 0 as last bit (only possible choice) bcf Reading_RC5 ; stop reading now return ; ;***** Main Program ***** ; Main_Start SEL_BANK_1 bcf OPTION_REG,T0CS ; Select internal timer mode for TMR0 bcf OPTION_REG,PSA ; Prescaler assigned to TMR0 bcf OPTION_REG,PS0 ; Set prescaler to 1:128 (b'110') bsf OPTION_REG,PS1 ; TMR0 increment = 0.128 ms bsf OPTION_REG,PS2 ; TMR0 overflow = 32.768 ms SEL_BANK_0 ;btfss STATUS,NOT_TO ; Reset from WDT? ;goto Main_Loop ; YES, don't reset the RTC ; ; NO, power-up initializations movlw d'32' ; Initialize RTC_32 counter to 32 (31 ?) movwf RTC_32 clrf RTC_L ; Clear RTC registers (Low and High) clrf RTC_H call Clear_RC5 ; Clear RC_5 registers movlw 0xFF movwf RC5_Timer_Ovfl ; Initialize RC5_Timer_Ovfl to FF: first int is a long delay clrf PORTB ; Initialize port B SEL_BANK_1 movlw 0x10 ; Set RB4 to input movwf TRISB SEL_BANK_0 bsf INTCON,T0IE ; Enable TMR0 Interrupt bsf INTCON,RBIE ; Enable RB4 Interrupt on change bsf INTCON,GIE ; Enable all Interrupts Main_Loop goto Main_Loop END