;**************************************************************************** ;* - Pic Project - * ;* * ;* PROJECT RESP.: Kieran the Great * ;* NAME: IR receiver * ;* PROCESSOR: PIC12F675 * ;* CLOCK: XT - 4 MHz * ;* FILE: ir.asm * ;* WATCHDOGTIMER: no * ;* REVISION: 20.04.2010 * ;* * ;**************************************************************************** ;* GP0 = Output ;* GP1 = Output ;* GP2 = Output ;* GP3 = Input (Can only be input) ;* GP4 = Output ;* GP5 = Output ;**************************************************************************** ;* * ;* * ;* EQUATES * ;* * ;* * ;**************************************************************************** START_PULSE EQU .50 BIT_BASE_TIME EQU .237 BIT_MAX EQU .26 IDLE_TIME EQU .13 TIMER_UPDATE EQU .208 BIT_TIMER EQU 0x20 IR_STATE EQU 0x21 IR_SHIFT_LOW EQU 0x22 IR_SHIFT_HIGH EQU 0x23 INTERRUPT_W EQU 0x28 INTERRUPT_STATUS EQU 0x29 ; Debugish SIPO_DATA EQU .0 SIPO_CLOCK EQU .1 SERIAL_COUNT EQU 0x40 SERIAL_DATA EQU 0x41 BIN2BCD_BIN EQU 0x42 BIN2BCD_BCD EQU 0x43 BIN2BCD_COUNT EQU 0x44 ;**************************************************************************** ;* * ;* * ;* CONFIG * ;* * ;* * ;**************************************************************************** list p=pic12f675 #include p12f675.inc __config 0x3F91 ; Configuration ORG 0x0000 ; Reset vector GOTO INIT ORG 0x0004 ; Interrupt vector GOTO INTERRUPT ;**************************************************************************** ;* * ;* * ;* 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? XORWF 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 BIN2BCD ; Convert to BCD CALL SERIAL_SEND ; Send to displays GOTO IR_ERROR_1 ; Done ;-IR ERROR 0, WAIT FOR INPUT TO RETURN HIGH IR_ERROR_0 MOVLW .99 CALL BIN2BCD CALL SERIAL_SEND 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 ;**************************************************************************** ;* * ;* * ;* INTERRUPT SERVICE * ;* * ;* * ;**************************************************************************** INTERRUPT BCF INTCON,GIE ; Disable interrupts while in service routine MOVWF INTERRUPT_W ; Save W SWAPF STATUS,W MOVWF INTERRUPT_STATUS ; Save STATUS INTERRUPT_DONE MOVLW b'11111000' ; Clear all interrupt flags ANDWF INTCON,W ; SWAPF INTERRUPT_STATUS,W ; Restore STATUS MOVWF STATUS ; SWAPF INTERRUPT_W,F ; Restore W SWAPF INTERRUPT_W,W ; BSF INTCON,GIE ; Reenable interrupts RETFIE ;**************************************************************************** ;* * ;* * ;* 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 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 BSF GPIO,SIPO_DATA ; Set data bit GOTO SERIAL_PULSE ; Jump to SERIAL_PULSE SERIAL_ZERO BCF GPIO,SIPO_DATA ; Clear data bit SERIAL_PULSE BSF GPIO,SIPO_CLOCK ; Set clock BCF GPIO,SIPO_CLOCK ; Clear clock DECFSZ SERIAL_COUNT,F ; Decrement counter, skip if 0 GOTO SERIAL_GETBIT ; Loop MOVF SERIAL_DATA,W ; Load W from data RETURN ; Shift and add 3 binary to BCD algorithm BIN2BCD MOVWF BIN2BCD_BIN ; Save W as binary input CLRF BIN2BCD_BCD ; Clear output MOVLW .7 ; Loop 7 times MOVWF BIN2BCD_COUNT ; Move W to counter BIN2BCD_NEXT RLF BIN2BCD_BIN,F ; Shift left to move input MSB to carry RLF BIN2BCD_BCD,F ; Shift left to move carry to output LSB MOVLW b'00001111' ; ANDWF BIN2BCD_BCD,W ; Get lower BCD digit SUBLW b'00000100' ; Is it over 5? BTFSC STATUS,C ; GOTO BIN2BCD_1 ; No - jump MOVLW b'00000011' ; Yes - add 3 ADDWF BIN2BCD_BCD,F ; BIN2BCD_1 MOVLW b'11110000' ; ANDWF BIN2BCD_BCD,W ; Get upper BCD digit SUBLW b'01000000' ; Is it over 5? BTFSC STATUS,C ; GOTO BIN2BCD_2 ; No - jump MOVLW b'00110000' ; Yes - add 3 ADDWF BIN2BCD_BCD,F ; BIN2BCD_2 DECFSZ BIN2BCD_COUNT,F ; Decrement counter, skip if 0 GOTO BIN2BCD_NEXT ; Loop RLF BIN2BCD_BIN,F ; Shift left to move input MSB to carry RLF BIN2BCD_BCD,W ; Shift left to move carry to output LSB, save in W 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'00001000' ; I/O port select MOVWF TRISIO CLRF ANSEL ; Not using A/D conversion ;MOVLW b'00001000' ; Interrupt-on-change on ;MOVWF IOC ; for GP3 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 b'10001000' ; Global interrupt enable and ;MOVWF INTCON ; enable interrupt-on-change MOVLW IR_STATE_0 ; Init IR receiver state machine MOVWF IR_STATE MOVLW TIMER_UPDATE ; Get the timer started MOVWF TMR0 MOVLW .88 CALL BIN2BCD CALL SERIAL_SEND ;**************************************************************************** ;* * ;* * ;* 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