; ;****************************************************************************** ; ; ME218C TREAT ; based on Wyatt Node D for Lab 10 ; author: George ; UART Receiver ; ;****************************************************************************** ; ; REQUIRED - specify processor for assembler with list list P=PIC12F752 ; HIGHLY RECOMMENDED - include file for standard definitions #include "p12F752.inc" ; RECOMMENDED - specify configuration options with _CONFIG __CONFIG (_CP_OFF & _PWRTE_ON & _WDTE_OFF & _BOREN_EN & _FOSC0_INT & _MCLRE_OFF) ; ;****************************************************************************** ; Constants/Origins ;****************************************************************************** ; W_TEMP equ 0x70 ;these need to be visible in all banks, STATUS_TEMP equ 0x71 ;so they need stored in 0x70-0x7f PCLATH_TEMP equ 0x72 ; ;variables and constants from our comm protocol: BIT_TIME equ 0x1A ;time for a bit HALF_BIT_TIME equ 0x0D ;half of the time for a bit RX_NUM_OF_BITS equ 0x09 ;1 byte+stop bit (no need to store starting bit) RX_COUNTER equ 0x73 ;tracks bit # when receiving UART byte RX_SHIFTREG equ 0x74 ;stores data while receiving UART byte RX_DATA equ 0x75 ;stores data after transmission finishes ;RX_DATA bit definitions: FAN_ON_OFF_BIT equ 0x00 ;signals whether we turn the lift fan on or off RX_STATUS equ 0x76 ;RX_STATUS bit definitions: RX_STARTING_FLAG equ 0x00 ;receiving is starting RX_FRAME_ERROR_FLAG equ 0x01 ;framing error (stop bit was 0) RX_DATA_READY_FLAG equ 0x02 ;received data ready RX_ACTIVE_FLAG equ 0x03 ;"currently receiving" flag org 0 goto MAIN ;(starts at MAIN block) org 4 goto ISR org 5 ;skip past interrupt vector ; ;****************************************************************************** ; Main Block ;****************************************************************************** ; MAIN: call INIT ;does HW init EMPTY_LOOP: ;wait for an interrupt in an endless loop NOP goto EMPTY_LOOP ; ;****************************************************************************** ; Initialization ;****************************************************************************** ; INIT: INIT_PINS: banksel ANSELA clrf ANSELA ;disable analog select for digital I/O banksel LATA bcf LATA,LATA0 ;initialize RA0 to lo,this one is for the fan bsf LATA,LATA1 ;to probe the period banksel TRISA movlw b'00001000' ;set RA3 to input; rest are LED/testing outputs movwf TRISA INIT_IOC: ;Interrupt On Change initialization banksel INTCON bsf INTCON,IOCIE ;enable IOC interrupt banksel IOCAN bsf IOCAN,IOCAN3 ;set IOC negative (falling) edge trigger for UART on RA3 INIT_HLTMR1: ;Hardware Limit Timer 1 initialization banksel HLT1CON0 movlw b'00011010' ;set prescaler to 16, postscaler to 4, keep turned off movwf HLT1CON0 banksel HLTPR1 movlw HALF_BIT_TIME ;set timer compare value as 1/2 period of a UART bit movwf HLTPR1 banksel PIE1 bsf PIE1,HLTMR1IE ;enable HLTMR1 interrupt in periph. int. enable reg. banksel INTCON bsf INTCON,PEIE ;enable peripheral interrupts (for HLTMR1) bsf INTCON,GIE ;enable interrupts globally INIT_VARIABLES: clrf RX_DATA RETURN ;initialization done; send us back to MAIN ; ;****************************************************************************** ; Interrupt Response ;****************************************************************************** ; ISR: PUSH: movwf W_TEMP ;backup W to W_TEMP swapf STATUS,W ;(swapf b/c it preserves STATUS bits) movwf STATUS_TEMP ;backup STATUS to STATUS_TEMP movf PCLATH,W movwf PCLATH_TEMP ;backup PCLATH to PCLATH_TEMP clrf PCLATH ;switch to program memory page 0 ISR_BODY: CHECK_IOC: ;Falling edge on UART pin --> transmission starting? banksel IOCAF btfsc IOCAF,IOCAF3 ;if IOC interrupt flag for pin RA3 is set: call UART_START ;then call the subroutine for UART TX start CHECK_HLTIMER: ;time to read the next UART data bit? banksel PIR1 btfsc PIR1,HLTMR1IF ;if HLTMR1 interrupt flag is set: call HLTIMER_TIMEOUT ;then call the subroutine for HLTIMER timeouts CLEAR_INT_FLAGS: banksel PIR1 bcf PIR1,HLTMR1IF ;clear HLTMR1 interrupt source/flag banksel IOCAF bcf IOCAF,IOCAF3 ;clear IOC interrupt flag for pin RA3 banksel INTCON bcf INTCON,IOCIF ;clear global IOC interrupt flag as well POP: movf PCLATH_TEMP,W movwf PCLATH ;restore PCLATH swapf STATUS_TEMP,W movwf STATUS ;restore STATUS swapf W_TEMP,F ;need to pre-swap W_TEMP before next line: swapf W_TEMP,W ;restore W (using swapf b/c movf might modify STATUS) retfie ;return from ISR, and re-enables interrupts ; ;****************************************************************************** ; Interrupt Subroutines ; UART_START: banksel HLTPR1 movlw HALF_BIT_TIME ;set timer compare value to half period of UART bit movwf HLTPR1 banksel HLT1CON0 bsf HLT1CON0,H1ON ;turn on the HLTMR1 for timing between UART bits banksel HLTMR1 clrf HLTMR1 ;clear HLTMR (necessary?) bsf RX_STATUS,RX_STARTING_FLAG ;set the "starting" flag in our status reg. movlw RX_NUM_OF_BITS movwf RX_COUNTER ;initialize the bit counter with 9, the total # bits clrf RX_SHIFTREG ;make sure shift reg and data are clear: clrf RX_DATA ;make sure data storage is clear banksel IOCAN bcf IOCAN,IOCAN3 ;disable IOC negative (falling) edge trigger for UART on RA3 banksel LATA bcf LATA,LATA4 ;set test pin low RETURN HLTIMER_TIMEOUT: movlw b'00000010' banksel LATA xorwf LATA,f ;toggles RA1 when this timer times out btfss RX_STATUS,RX_STARTING_FLAG ;if this is NOT the first UART bit: goto DATA_BITS ;then go to DATA_BITs block FIRST_BIT: ;else, this is the first bit bcf RX_STATUS,RX_STARTING_FLAG ;clear starting-bit flag banksel HLTMR1 clrf HLTMR1 ;clear HLTMR (necessary?) banksel PORTA btfsc PORTA,RA3 ;if first bit high: goto BAD_FIRST_BIT ;then first bit was bad; go to BAD_FIRST_BIT block GOOD_FIRST_BIT: ;else, first bit was valid (low) banksel HLTPR1 movlw BIT_TIME ;set timer compare value to full period of UART bit movwf HLTPR1 banksel LATA bcf LATA,LATA4 ;set test pin low goto HLTIMER_END BAD_FIRST_BIT: banksel IOCAN bsf IOCAN,IOCAN3 ;re-set IOC negative (falling) edge trigger for UART on RA3 banksel LATA bsf LATA,LATA4 ;set test pin hi goto HLTIMER_END DATA_BITS: decf RX_COUNTER,F ;decrement the bit counter btfsc STATUS,Z ;if counter has reached zero: goto TX_END ;then go to TX_END block to handle end of trans. TX_ONGOING: ;else, TX is ongoing rrf RX_SHIFTREG,F ;shift previous data in shift reg. to right banksel PORTA btfsc PORTA,RA3 ;if pin RA3 is high: goto RA3_HI ;then go to RA3_HI block RA3_LO: bcf RX_SHIFTREG,0x07 ;clear MSB in shift reg banksel LATA bcf LATA,LATA4 ;lower test output pin goto RA3_TEST_END RA3_HI: bsf RX_SHIFTREG,0x07 ;set MSB in shift reg banksel LATA bsf LATA,LATA4 ;raise test output pin RA3_TEST_END: goto HLTIMER_END TX_END: banksel LATA bsf LATA,LATA4 ;set test pin hi movf RX_SHIFTREG,W movwf RX_DATA ;store received data into RX_DATA register banksel PORTA btfsc PORTA,RA3 ;if last bit in UART TX is low (bad stop bit): bsf RX_STATUS,RX_FRAME_ERROR_FLAG bsf RX_STATUS,RX_DATA_READY_FLAG banksel HLT1CON0 bcf HLT1CON0,H1ON ;turn off the HLTMR; time to look for new packets banksel IOCAN bsf IOCAN,IOCAN3 ;re-set IOC negative (falling) edge trigger for UART on RA3 call SET_FAN ;turn on appropriate LEDs based on input data HLTIMER_END: banksel HLTMR1 clrf HLTMR1 ;clear HLTMR RETURN ; ;****************************************************************************** ; FAN INTERACTING FUNCTIONS ;****************************************************************************** ; SET_FAN: btfsc RX_DATA,FAN_ON_OFF_BIT ;if the bit goto TURN_ON_FAN TURN_OFF_FAN: banksel LATA bcf LATA,LATA0 ;use RA0 as the output to the lower circuitry goto DONE_SETTING_FAN TURN_ON_FAN: banksel LATA bsf LATA,LATA0 DONE_SETTING_FAN: RETURN END