; (UHF receiver) ERRORLEVEL -302 ERRORLEVEL -306 list P=12F675 #include P12F675.inc ;Program Configuration Register __CONFIG _CPD_OFF & _CP_OFF & _BODEN_ON & _MCLRE_ON & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT ; bank 0 RAM W_TMP equ H'20' ; storage of w before interrupt STATUS_TMP equ H'21' ; status storage before interrupt FLAG1 equ H'23' ; interrupt flag with timer 0 TIMEOUT equ H'24' ; timeout counter SW_FLAG equ H'25' ; switch closed flag TRANS_COUNT equ H'26' ; transmission counter STORE1 equ H'27' ; delay counter STORE2 equ H'28' ; delay counter RECEIVE0 equ H'29' ; received data RECEIVE1 equ H'2A' ; received data TIMER1L_WK equ H'2B' ; timer 1 ls byte working register TIMER1H_WK equ H'2C' ; timer 1 ms byte working register TIMER1L_VAL equ H'2D' ; timer 1 ls byte working register TIMER1H_VAL equ H'2E' ; timer 1 ms byte working register TIMER1L_2 equ H'2F' ; timer 1 /2 ls byte working register TIMER1H_2 equ H'30' ; timer 1 /2 ms byte working register FLAG equ H'31' ; interrupt flag with timer 1 COUNT_BITS equ H'32' ; data count bits ENCODE equ H'33' ; encode value RECEIVEX equ H'34' ; stop bits MOM_CNT0 equ H'35' ; ms counter for momentary out period MOM_CNT1 equ H'36' ; ls counter for momentary out period TIME0_CNT equ H'3A' ; timeout of timer 0 ; ****************************************************************** ; start at memory 0 org 0 ; reset vector goto MAIN ; org 4 ; interrupt vector goto INTERRUPT MOM_LOOK ; momentary value lookup table addwf PCL,f ; add w to program counter retlw D'1' ; 0 200ms retlw D'2' ; 1 400ms retlw D'3' ; 2 600ms retlw D'4' ; 3 800ms retlw D'5' ; 4 1s retlw D'6' ; 5 1.2s retlw D'7' ; 6 1.4s retlw D'8' ; 7 1.6s retlw D'9' ; 8 1.8s retlw D'10' ; 9 2.0s retlw D'11' ; 10 2.2s retlw D'12' ; 11 2.4s retlw D'15' ; 12 3s retlw D'20' ; 13 4s retlw D'25' ; 14 5s retlw D'30' ; 15 6s retlw D'40' ; 16 8s retlw D'50' ; 17 10s retlw D'60' ; 18 12s retlw D'75' ; 19 15s retlw D'90' ; 20 18s retlw D'105' ; 21 21s retlw D'125' ; 22 25s retlw D'135' ; 23 27s retlw D'149' ; 24 30s retlw D'163' ; 25 32s retlw D'177' ; 26 35s retlw D'191' ; 27 38s retlw D'206' ; 28 41s retlw D'222' ; 29 44s retlw D'255' ; 30 50s retlw D'255' ; 31 50s retlw D'255' ; 32 50s retlw D'255' ; 33 50s ; *********************************************************************** INTERRUPT ; Interrupt ; start interrupt by saving w and status registers movwf W_TMP ; w to w_tmp storage swapf STATUS,w ; status to w movwf STATUS_TMP ; status in status_tmp ; page and banks bcf STATUS,RP0 ; select memory bank bcf STATUS,RP1 ; select memory bank 0 ; Interrupt source btfss PIR1,TMR1IF ; if timer 1 flag goto TIME_0 ; is it timer 0 ; preload timer for timer 1 interrupt rate bcf T1CON,0 ; timer 1 off movf TIMER1H_VAL,w addwf TMR1H,f movf TIMER1L_VAL,w addwf TMR1L,f btfsc STATUS,C incf TMR1H,f ; increase ms byte if ls addition has carry bsf T1CON,0 ; timer 1 on bcf PIR1,TMR1IF ; clear timer 1 overflow bsf FLAG,0 ; set flag bit to indicate an interrupt has occurred for data reception TIME_0 btfss INTCON,T0IF goto RECLAIM bcf INTCON,T0IF bsf FLAG1,0 ; set flag bit to indicate an interrupt has occurred for data reception movf TIME0_CNT,w ; decrease if not 0 btfss STATUS,Z decf TIME0_CNT,f ; momentary timeout delay movf MOM_CNT0,w ; ms counter sublw D'191' ; for 196ms btfss STATUS,C ; when negative clear goto CLEAR_MOM incf MOM_CNT0,f goto RECLAIM CLEAR_MOM clrf MOM_CNT0 movf MOM_CNT1,w btfsc STATUS,Z ; when zero do not decrease goto RECLAIM decfsz MOM_CNT1,f goto RECLAIM PROCESS btfsc GPIO,5 ; when momentary check for timeout bcf GPIO,1 ; clear output ; end of interrupt restore status and w RECLAIM swapf STATUS_TMP,w; status temp storage to w movwf STATUS ; w to status register swapf W_TMP,f ; swap upper and lower 4-bits in w_tmp swapf W_TMP,w ; swap bits and into w register retfie ; return from interrupt ;******************************************************************************************* MAIN bcf STATUS,RP0 ; select memory bank 0 ; set inputs/outputs clrf GPIO ; outputs low movlw B'00000111' ; comparators off movwf CMCON bsf STATUS,RP0 ; select memory bank 1 movlw B'00100000' ; pullups movwf WPU movlw B'00111101' ; outputs/inputs set movwf TRISIO ; port data direction register movlw B'00000001' ; settings (pullups enabled) timer0/4 movwf OPTION_REG ; calibrate internal oscillator call H'3FF' movwf OSCCAL ; analog inputs, A/D movlw B'01011001' ; AN0 & AN3 analog input movwf ANSEL bcf STATUS,RP0 ; select memory bank 0 movlw B'00001100' ; channel 3 etc movwf ADCON0 bsf ADCON0,ADON ; A/D on ; initial conditions movlw B'00000000' ; port low movwf GPIO movlw H'FB' ; preload timer 1 movwf TIMER1H_VAL movwf TMR1H movlw H'FF' movwf TIMER1L_VAL movwf TMR1L bcf T1CON,5 ; /1 prescaler bcf T1CON,4 bsf T1CON,0 ; timer 1 on call DELAYms ; add small delay ; allow interrupts ALL_INTERRUPTS bsf STATUS,RP0 ; select memory bank 1 bsf PIE1,TMR1IE ; timer 1 overflow interrupt bcf STATUS,RP0 ; select memory bank 0 bcf PIR1,TMR1IF ; timer 1 interrupt flag bsf INTCON,T0IE ; timer 0 enable bcf INTCON,T0IF ; timer 0 interrupt flag bsf INTCON,PEIE ; enable periperal interrupts bsf INTCON,GIE ; set global interrupt enable ; check for a high at RA5 INPUT_SIG btfss GPIO,2 ; when high begin to read data goto INPUT_SIG clrf TMR0 ; clear timer nop nop nop clrf FLAG1 ; movlw D'10' ; transmission counter movwf TRANS_COUNT TRANS_LOOP btfss FLAG1,0 ; count flags (set in interrupt) for a 10ms transmission from transmitter goto TRANS_LOOP btfss GPIO,2 ; check if still high goto INPUT_SIG ; not high so out decfsz TRANS_COUNT,f; count goto QUIETING_LOOP goto LOCK_START QUIETING_LOOP clrf FLAG1 goto TRANS_LOOP LOCK_START ; use start bits to lock the transmission frequency bsf STATUS,RP0 ; select memory bank 1 bcf PIE1,TMR1IE ; stop timer 1 overflow interrupt bcf STATUS,RP0 ; select memory bank 0 bcf T1CON,0 ; stop timer 1 clrf TMR1L ; clear timer 1 clrf TMR1H clrf FLAG ; interrupt occurred flag bcf PIR1,TMR1IF ; clear interrupt flag movlw D'64' movwf TIME0_CNT ; timer counter movlw D'24' movwf COUNT_BITS ; number of bits of data ; count with timer 1 for GP2 to go low, high, low corresponding to a 0,1 start bits WAIT_LOW movf TIME0_CNT,w btfsc STATUS,Z ; timer overflow if zero goto INPUT_SIG btfsc GPIO,2 ; wait till low goto WAIT_LOW WAIT_HIGH movf TIME0_CNT,w btfsc STATUS,Z ; timer overflow if zero goto INPUT_SIG btfss GPIO,2 ; wait for a high goto WAIT_HIGH ; start of 16ms reference period from transmitter bsf T1CON,0 ; timer1 on to count and check for overrange WAIT_LOW1 movf TIME0_CNT,w btfsc STATUS,Z ; timer overflow if zero goto INPUT_SIG btfsc GPIO,2 ; wait till low goto WAIT_LOW1 ; read timer 1 and divide by 16 to get the required timer 1 offset (take from FFFF to get preload value) ; if outside range then ignore. Typically should be 1024 but 2048 to 512 allowable btfsc PIR1,TMR1IF ; timer 1 overflow flag if timed out then ignore goto INPUT_SIG bcf T1CON,0 ; stop timer 1 movf TMR1L,w ; read timer 1 movwf TIMER1L_WK ; working registers movf TMR1H,w movwf TIMER1H_WK ; divide by 16 to get average count between each edge bcf STATUS,C rrf TIMER1H_WK,f rrf TIMER1L_WK,f ; /2 bcf STATUS,C rrf TIMER1H_WK,f rrf TIMER1L_WK,f ; /4 bcf STATUS,C rrf TIMER1H_WK,f rrf TIMER1L_WK,f ; /8 bcf STATUS,C rrf TIMER1H_WK,f rrf TIMER1L_WK,f ; /16 ; compare with over range/under range movf TIMER1H_WK,w ; ms byte andlw B'11111110' ; 512 and greater btfsc STATUS,Z ; if zero then value too small goto INPUT_SIG ; value off range movf TIMER1H_WK,w ; ms byte andlw B'11111000' ; 2048 and greater btfss STATUS,Z ; if not zero then value too large goto INPUT_SIG ; take from FFFF to get preset for interrupt rate movf TIMER1H_WK,w ; ms byte sublw H'FF' ; maximum movwf TIMER1H_VAL movf TIMER1L_WK,w ; ls byte sublw H'FF' ; maximum movwf TIMER1L_VAL btfss STATUS,C ; if carry reduce ms byte decf TIMER1H_VAL,f ; add compensation for preload losses movlw D'7' ; compensate for loss during preloading at interrupt addwf TIMER1L_VAL,f ; add compensation btfsc STATUS,C incf TIMER1H_VAL,f ; if overrange increase ms byte ; preload counter 1 to sync with transmission rate movf TIMER1H_VAL,w movwf TMR1H movf TIMER1L_VAL,w movwf TMR1L clrf FLAG ; clear flag bsf T1CON,0 ; timer1 on start count bsf STATUS,RP0 ; select memory bank 1 bsf PIE1,TMR1IE ; timer 1 overflow interrupt restart bcf STATUS,RP0 ; select memory bank 0 ; wait for one interrupt interval WAIT_FLG_R btfss FLAG,0 goto WAIT_FLG_R clrf FLAG ; wait for 1/2 interrupt interval to centre measurement of level on high or low transmission ; calculate 1/2 interval bcf STATUS,C ; carry cleared rrf TIMER1H_WK,w; divide by 2 movwf TIMER1H_2 ; place in secondary register rrf TIMER1L_WK,w movwf TIMER1L_2 ; take from FFFF to get shift in time to read data centred on a 1 or 0 value bcf INTCON,GIE ; stop interrupts bcf T1CON,0 ; stop timer 1 movf TIMER1H_2,w ; ms byte sublw H'FF' ; maximum movwf TMR1H movf TIMER1L_2,w ; ls byte sublw H'FF' ; maximum movwf TMR1L btfss STATUS,C ; if carry reduce ms byte decf TMR1H,f bcf PIR1,TMR1IF ; clear interrupt flag bsf T1CON,0 ; run timer 1 clrf FLAG bsf INTCON,GIE ; allow interrupts ; start of data ; shift into RECEIVE WAIT_FLG3 btfss FLAG,0 ; wait for interrupt flag change goto WAIT_FLG3 clrf FLAG ; clear interrupt flag bcf STATUS,C ; clear carry btfsc GPIO,2 ; check level bsf STATUS,C ; set carry when GPIO,2 is set rlf RECEIVEX,f ; stop bits value rlf RECEIVE0,f ; on or off signal rlf RECEIVE1,f ; encode decfsz COUNT_BITS,f goto WAIT_FLG3 ; continue loading bits ; check stop bits movf RECEIVEX,w ; check if stops bits are correct xorlw D'240' ; stop bits code btfss STATUS,Z ; if status is zero value is correct goto INPUT_SIG ; received encode must equal receiver encode ; find encode value from A/D ; set TEMP call ACQUIRE_AD movf ADRESH,w sublw D'51' ; if less than 51 then a low setting btfsc STATUS,C ; if positive then less or equal to 51 goto SET_1 movf ADRESH,w sublw D'102' ; if less than 102 then a next setting btfsc STATUS,C ; if positive then less or equal to 102 goto SET_2 movf ADRESH,w sublw D'153' ; if less than 153 then a mid setting btfsc STATUS,C ; if positive then less or equal to 153 goto SET_3 movf ADRESH,w sublw D'204' ; if less than 204 then a next setting btfsc STATUS,C ; if positive then less or equal to 204 goto SET_4 movlw D'128' ; max setting goto LD_ENCODE SET_1 movlw D'8' goto LD_ENCODE SET_2 movlw D'16' goto LD_ENCODE SET_3 movlw D'32' goto LD_ENCODE SET_4 movlw D'64' LD_ENCODE movwf ENCODE movf RECEIVE1,w ; encoder xorwf ENCODE,w btfss STATUS,Z goto INPUT_SIG ; check on/off signal movf RECEIVE0,w ; on/off xorlw D'120' ; on/off signal btfss STATUS,Z goto INPUT_SIG ; not equal so bypass ; check if toggle or momentary btfss GPIO,5 goto TOGGLE ; momentary bcf STATUS,GIE ; stop interrupt nop bsf GPIO,1 ; output on ; read momentary delay at Ch0 bcf ADCON0,2 bcf ADCON0,3 ; ch0 call DELAYms ; wait call ACQUIRE_AD clrf MOM_CNT0 ; ms momentary counter ; divide by 8 for ~156mv resolution bcf STATUS,C rrf ADRESH,f bcf STATUS,C rrf ADRESH,f bcf STATUS,C rrf ADRESH,f movlw D'2' ; take 2 away, so start changes at 312mV, ; compensates for trimpot resolution at low end subwf ADRESH,w btfss STATUS,C clrw ; clear if negative call MOM_LOOK ; momentary timeout lookup value movwf MOM_CNT1 ; momentary counter nop bsf STATUS,GIE ; channel 3 bsf ADCON0,2 bsf ADCON0,3 ; ch3 call DELAYms ; wait goto INPUT_SIG TOGGLE ; Alternate output btfss GPIO,1 goto SET1 bcf GPIO,1 ; if high set low goto END1 SET1 bsf GPIO,1 ; if low set high END1 bsf ADCON0,2 bsf ADCON0,3 ; ch3 call DELAYms ; wait goto INPUT_SIG ; *************************************************************************** ; Subroutines ; switch delay SW_DELAY movlw D'80' SW_DELAY1 movwf SW_FLAG SW_LOOP call DELAYms decfsz SW_FLAG,f ; decrease til zero goto SW_LOOP return ; delay loop DELAYms movlw D'23' ; delay value DELAYX movwf STORE1 ; STORE1 is number of loops value LOOP8 movlw H'B0' DELDSP movwf STORE2 ; STORE2 is internal loop value LOOP9 decfsz STORE2,f goto LOOP9 decfsz STORE1,f goto LOOP8 return ; subroutine to wait for A/D conversion ACQUIRE_AD bsf ADCON0,GO_DONE ; GO/DONE bit start conversion WAIT_CONV btfsc ADCON0,GO_DONE ; conversion complete when cleared ~11 cycles goto WAIT_CONV return end