; ; ctrlir.asm ; TITLE "IR Remote Receiver" ; include "reg84.h" ; ; To Do ; Reject notches by accumulating very small counts ; ; ; Equates ; DbgIr equ 01H ; ; Port B bits(Bits 6 & 7 are used by serial comms.) InpBit equ 00H ; if DbgIr != 0 DbgBit equ 01H DbgByte equ 02H DbgMain equ 03H DbgIsr equ 04H endif ; ; Flag bits in StatByte PrevBit equ 00H ; State of previous bit sample RcvBusy equ 01H ; In the process of receiving RcvReady equ 02H ; Code completely received BitReady equ 03h ; Bit ready for assembly XmitCod1 equ 04h ; LSB of code ready for xmit XmitCod2 equ 05h ; MSB of code ready for xmit CodeOrun equ 06h ; Code overrun ; ; Rate of interrupt. Set at 9600/sec. Rest of this arrived at by ; trial and error(mostly error). The calculation is as follows. ; Required rate = 1/9600 = 104us ; No. of instruction cycles = 104*3.58/4 ; = 93(with a crystal of 3.58 MHz) ; RtccCount = 0 - 93 = A3h ; With an overhead(12d?) it is afh ; RtccCount equ 0afh ; ; Timing constants HdrTic equ 19h ; 2500us-2700us MarkTic equ 0bh ; 1100us-1300us SpacTic equ 05h ; 500us-700us EndCode equ 14h ; Gap indicating end of code(2ms) ; ; Data ORG 0CH ; Data Origin ; SaveWReg RES 1 ; Save W during ISR SaveStat RES 1 ; Save Status during ISR IntDiv RES 1 ; Divider for periodic interrupt ; CurrTime RES 1 ; The current ticks MarkTime RES 1 ; Ticks the mark lasted SpacTime RES 1 ; Ticks the space lasted StatByte RES 1 ; A whole bunch of flags CodeByt1 RES 1 ; LSB of the received byte CodeByt2 RES 1 ; MSB of the received byte CodeCnt RES 1 ; Bits received so far SendCod1 RES 1 ; Hold before transmit SendCod2 RES 1 ; include "ctrlcomm.h" ; ; Macros ; ; ; ChkRng : If value in register ChkReg is not between ChkVal ; and ChkVal + 2 go to ErrLbl ChkRng MACRO ChkReg,ErrLbl,ChkVal movf ChkReg,0 sublw ChkVal+2 JMPC ErrLbl ; Value more than ChkVal + 2 sublw 3 JMPC ErrLbl ; Value less than ChkVal ENDM ; ; Program ; ORG 0 ; Reset vector ; goto main ; ; ORG 4 ; Interrupt vector ; goto isr ; ; ORG 8 ; Program starts here ; main call InitIr call InitPort if DbgIr != 0 bcf RegPortb,DbgBit bcf RegPortb,DbgByte endif loop1 btfss StatByte,BitReady goto DoneIr ; Nothing on IR port if DbgIr != 0 bcf RegPortb,DbgBit endif bcf StatByte,BitReady movf CodeCnt,0 JMPNZ NotHdr ; Not expecting header ; Header has m=21-23, space=5-7 ChkRng MarkTime,IrErr,15h ChkRng SpacTime,IrErr,5 ; Expecting header & this ain't it incf CodeCnt,1 clrf CodeByt1 clrf CodeByt2 goto DoneIr NotHdr bcf RegStatus,BitCarry ; It's not the header rlf CodeByt1,1 rlf CodeByt2,1 ChkRng MarkTime,NotOne,0bh ; Is it a 1? goto Maybe1 NotOne ChkRng MarkTime,IrErr,5 ; Is it a 0? goto ChkSpac Maybe1 bsf CodeByt1,0 ChkSpac ChkRng SpacTime,IsItEnd,5 incf CodeCnt,1 goto DoneIr IsItEnd movf SpacTime,0 sublw EndCode JMPNZ IrErr clrf CodeCnt movf StatByte andlw (1<<XmitCod1)|(1<<XmitCod2) JMPZ NoOrun bsf StatByte,CodeOrun goto DoneIr NoOrun movf CodeByt1,0 movwf SendCod1 movf CodeByt2,0 movwf SendCod2 bsf StatByte,XmitCod1 bsf StatByte,XmitCod2 goto DoneIr IrErr clrf CodeCnt bcf StatByte,RcvBusy if DbgIr != 0 bcf RegPortb,DbgByte endif goto DoneIr DoneIr btfss StatByte,XmitCod1 goto TryCod2 btfss P1Stat,TxRdy goto SkipXmt movf SendCod1,0 bsf RegPortb,DbgMain call P1PutC bcf RegPortb,DbgMain bcf StatByte,XmitCod1 goto SkipXmt TryCod2 btfss StatByte,XmitCod2 goto SkipXmt btfss P1Stat,TxRdy goto SkipXmt movf SendCod2,0 bsf RegPortb,DbgMain call P1PutC bcf RegPortb,DbgMain bcf StatByte,XmitCod2 goto SkipXmt SkipXmt goto loop1 ; Play it again, Sam. ; InitIr bsf RegStatus,BitRp0 movlw 0 movwf RegTrisa ; Set Port A to all outputs movlw 1 movwf RegTrisb ; Set Port B Bit 0 to input bcf RegOption,BitRts ; Enable RTCC timer bcf RegStatus,BitRp0 movlw 0 movwf RegRtcc movlw 0 movwf IntDiv movwf CurrTime movwf CodeByt1 movwf CodeByt2 movwf CodeCnt movwf StatByte return ; isr btfss RegIntcon,BitRtif retfie movwf SaveWReg swapf RegStatus,w movwf SaveStat movlw RtccCount movwf RegRtcc bcf RegStatus,BitRp0 bsf RegPorta,0 ; The real work starts here ; The IR detector output is inverted. Thus, all tests of ; InpBit are inverted. btfsc RegPortb,InpBit goto IsSpace btfsc StatByte,RcvBusy goto Rcving ; In the middle of receiving bsf StatByte,RcvBusy ; Now I'm busy if DbgIr != 0 bsf RegPortb,DbgByte endif clrf CurrTime ; Start count goto OneDone ; Rcving btfss StatByte,PrevBit goto WasZero incf CurrTime goto OneDone ; WasZero movf CurrTime,0 movwf SpacTime clrf CurrTime bsf StatByte, BitReady if DbgIr != 0 bsf RegPortb,DbgBit endif goto OneDone ; IsSpace btfss StatByte,RcvBusy goto Done ; All quiet btfsc StatByte,PrevBit ; Current input is space goto WasOne incf CurrTime movlw EndCode subwf CurrTime,0 JMPNZ Done movf CurrTime,0 ; Received end of code movwf SpacTime bcf StatByte,RcvBusy if DbgIr != 0 bcf RegPortb,DbgByte endif bsf StatByte,BitReady if DbgIr != 0 bsf RegPortb,DbgBit endif goto Done ; WasOne movf CurrTime,0 ; Just changed from 1 to 0 movwf MarkTime ; Store MarkTime clrf CurrTime bcf StatByte,PrevBit goto Done ; OneDone bsf StatByte,PrevBit Done incf IntDiv,1 movf IntDiv,0 sublw 2 JMPNZ SkipSer ; Call the serial ISR every two tics clrf IntDiv call SerIsr SkipSer bcf RegPorta,0 swapf SaveStat,w movwf RegStatus swapf SaveWReg swapf SaveWReg,w bcf RegIntcon,BitRtif retfie ; include "ctrlcomm.asm" ; end
InitPort in ctrlcomm.asm ChkSpac P1PutC in ctrlcomm.asm SerIsr in ctrlcomm.asm