;**************************************************************************** ;* - Pic Project - * ;* * ;* PROJECT RESP.: Kieran Menor * ;* NAME: IR controller * ;* PROCESSOR: PIC12F675 * ;* CLOCK: XT - 4 MHz * ;* FILE: ir.asm * ;* WATCHDOGTIMER: no * ;* REVISION: 28.04.2010 * ;* * ;**************************************************************************** ;* Pin setup ;* GP0 = I/O / Serial data ;* GP1 = I/O / Serial clock ;* GP2 = Output / Not connected ;* GP3 = Input / IR receiver ;* GP4 = Output / Not connected ;* GP5 = Output / Not connected ;**************************************************************************** ;* * ;* * ;* EQUATES * ;* * ;* * ;**************************************************************************** START_PULSE EQU .50 ; Max start pulse width BIT_BASE_TIME EQU .237 ; This value is added to BIT_TIMER after ; measuring pulse width. If BIT_TIMER ; overflows, the pulse is a logical 1 BIT_MAX EQU .26 ; Max active pulse width IDLE_TIME EQU .13 ; Max idle pulse width TIMER_UPDATE EQU .208 ; Reset value for TMR0. IR_MACHINE is called ; every time TMR0 overflows. BIT_TIMER EQU 0x20 ; Used to measure pulse width IR_STATE EQU 0x21 IR_SHIFT_LOW EQU 0x22 IR_SHIFT_HIGH EQU 0x23 SERIAL_COUNT EQU 0x24 SERIAL_DATA EQU 0x25 DELAY_COUNT EQU 0x26 WAIT_COUNT_0 EQU 0x27 WAIT_COUNT_1 EQU 0x28 ;**************************************************************************** ;* * ;* * ;* CONFIG * ;* * ;* * ;**************************************************************************** list p=pic12f675 #include p12f675.inc __config 0x3F81 ; Configuration ORG 0x0000 ; Reset vector GOTO INIT ORG 0x0004 ; Interrupt vector RETFIE ;**************************************************************************** ;* * ;* * ;* STATE MACHINE * ;* * ;* * ;**************************************************************************** IR_MACHINE MOVF IR_STATE,W ;Jump to present state MOVWF PCL ;-STATE 0, WAIT FOR START PULSE IR_STATE_0 BTFSC GPIO,3 ; Input still high? RETURN ; Yes! Nothing to do here CLRF IR_SHIFT_LOW ; Prepare shift register MOVLW b'00001000' MOVWF IR_SHIFT_HIGH CLRF BIT_TIMER ; Clear bit timer MOVLW IR_STATE_1 ; Next stop is state 1 MOVWF IR_STATE RETURN ;-STATE 1, FALLING EDGE DETECTED IR_STATE_1 INCF BIT_TIMER,F ; Increment bit timer BTFSC GPIO,3 ; Input still low? GOTO IR_STATE_1_H ; No! Pulse is over now. MOVLW START_PULSE ; See if max pulse width reached SUBWF BIT_TIMER,W BTFSS STATUS,Z RETURN ; Not yet! MOVLW IR_ERROR_0 ; Wait until pulse goes high again MOVWF IR_STATE ; before accepting new command RETURN IR_STATE_1_H CLRF BIT_TIMER ; Clear bit timer MOVLW IR_STATE_2 ; Input is now high MOVWF IR_STATE ; Next stop is state 2 RETURN ;-STATE 2, WAIT FOR PULSE TO GO LOW AGAIN IR_STATE_2 INCF BIT_TIMER,F ; Increment bit timer MOVLW IDLE_TIME ; Should we keep waiting? SUBWF BIT_TIMER,W BTFSC STATUS,Z GOTO IR_ERROR_1 ; No, time is up! BTFSC GPIO,3 RETURN ; Keep waiting while input remains high CLRF BIT_TIMER ; Clear bit timer MOVLW IR_STATE_3 ; Time to measure MOVWF IR_STATE ; RETURN ;-STATE 3, MEASURE IR_STATE_3 INCF BIT_TIMER,F ; Increment bit timer MOVLW BIT_MAX ; Should we keep waiting? SUBWF BIT_TIMER,W BTFSC STATUS,Z GOTO IR_ERROR_1 ; No, time is up! BTFSS GPIO,3 RETURN ; Keep waiting while input remains low MOVLW BIT_BASE_TIME ; ADDWF BIT_TIMER,W ; Carry is high if bit is high RRF IR_SHIFT_HIGH,F ; Save result RRF IR_SHIFT_LOW,F ; BTFSC STATUS,C ; See if we're done GOTO IR_STATE_3_DONE ; CLRF BIT_TIMER ; Not done yet MOVLW IR_STATE_2 ; Back to state 2 MOVWF IR_STATE RETURN IR_STATE_3_DONE BCF STATUS,C ; Clear carry RRF IR_SHIFT_HIGH,F ; Rotate result so that RRF IR_SHIFT_LOW,F ; IR_SHIFT_HIGH will contain RRF IR_SHIFT_HIGH,F ; the 5 bit address and RRF IR_SHIFT_LOW,F ; IR_SHIFT_LOW will contain RRF IR_SHIFT_HIGH,F ; the 7 bit command RRF IR_SHIFT_LOW,F ; RRF IR_SHIFT_LOW,F ; MOVF IR_SHIFT_LOW,W ; Load command CALL SERIAL_SEND ; Send to displays CALL WAIT GOTO IR_ERROR_1 ; Done ;-IR ERROR 0, WAIT FOR INPUT TO RETURN HIGH IR_ERROR_0 MOVLW IR_STATE_0 ; Reset state machine only if input is BTFSC GPIO,3 ; high MOVWF IR_STATE RETURN ;-IR ERROR STATE 1 IR_ERROR_1 MOVLW IR_STATE_0 ; Return to IR state 0 MOVWF IR_STATE RETURN ;**************************************************************************** ;* * ;* * ;* ROUTINES * ;* * ;* * ;**************************************************************************** SERIAL_SEND MOVWF SERIAL_DATA ; Save W to data MOVLW .8 ; Loop 8 times - 8 bits to a byte MOVWF SERIAL_COUNT ; Move W to loop counter RLF SERIAL_DATA,F ; Rotate left to move bit 7 to carry CALL DATALOW ; Pull data low CALL DELAY ; Wait CALL DELAY ; Wait CALL DELAY ; Wait CALL CLOCKLOW ; Pull clock low CALL DELAY ; Wait SERIAL_GETBIT RLF SERIAL_DATA,F ; Rotate left, moving carry to bit 0 BTFSS SERIAL_DATA,0 ; If bit 0 is 1, skip an instruction GOTO SERIAL_ZERO ; Jump to SERIAL_ZERO if bit 0 is 0 CALL DATAHIGH ; GOTO SERIAL_PULSE ; Jump to SERIAL_PULSE SERIAL_ZERO CALL DATALOW ; SERIAL_PULSE CALL DELAY ; Wait CALL CLOCKHIGH ; CALL DELAY ; Wait CALL CLOCKLOW ; DECFSZ SERIAL_COUNT,F ; Decrement counter, skip if 0 GOTO SERIAL_GETBIT ; Loop CALL DELAY CALL DATALOW CALL DELAY CALL CLOCKHIGH CALL DELAY CALL DATAHIGH MOVF SERIAL_DATA,W ; Load W from data RETURN DELAY MOVLW .6 MOVWF DELAY_COUNT DELAY_0 DECFSZ DELAY_COUNT,F GOTO DELAY_0 GOTO $+1 RETURN DATALOW BSF STATUS,RP0 ; Switch to bank 1 BCF TRISIO,0 ; Set data pin to output BCF STATUS,RP0 ; Switch to bank 0 BCF GPIO,0 ; Set data pin to low RETURN DATAHIGH BSF STATUS,RP0 ; Switch to bank 1 BSF TRISIO,0 ; Set data pin to inpu BCF STATUS,RP0 ; Switch to bank 0 RETURN CLOCKLOW BSF STATUS,RP0 ; Switch to bank 1 BCF TRISIO,1 ; Set clock pin to output BCF STATUS,RP0 ; Switch to bank 0 BCF GPIO,1 ; Set clock pin to low RETURN CLOCKHIGH BSF STATUS,RP0 ; Switch to bank 1 BSF TRISIO,1 ; Set clock pin to input BCF STATUS,RP0 ; Switch to bank 0 RETURN WAIT MOVLW .120 MOVWF WAIT_COUNT_0 WAIT_0 MOVLW .60 MOVWF WAIT_COUNT_1 WAIT_1 CALL DELAY DECFSZ WAIT_COUNT_1,F GOTO WAIT_1 DECFSZ WAIT_COUNT_0,F GOTO WAIT_0 RETURN ;**************************************************************************** INIT CLRF INTCON ; Interrupts off BSF STATUS,RP0 ; Switch to bank 1 MOVLW b'11001000' ; Option register MOVWF OPTION_REG ; See datasheet pg. 14 MOVLW b'00001011' ; I/O port select MOVWF TRISIO CLRF ANSEL ; Not using A/D conversion BCF STATUS,RP0 ; Back to bank 0 MOVLW b'00000111' ; Comparator mode MOVWF CMCON ; See datasheet pg. 37, 39 CLRF PCLATH ; All indirect jumps are on page 0! CLRF GPIO MOVLW IR_STATE_0 ; Init IR receiver state machine MOVWF IR_STATE MOVLW TIMER_UPDATE ; Get the timer started MOVWF TMR0 ;**************************************************************************** ;* * ;* * ;* MAIN * ;* * ;* * ;**************************************************************************** MAIN CALL IR_MACHINE ; Call IR routine SYNC BTFSC TMR0,7 ; Wait until bit 7 of TMR = 0 GOTO SYNC ; Not 0 yet! MOVLW TIMER_UPDATE ; Reload timer again ADDWF TMR0,F GOTO MAIN END