;Based on: Tutorial 5_1
; Read SIRC IR with LCD display
; Nigel Goodwin 2002
; This version using CCP1 interrupts by:
; Joe Brown 2005
; 1st version works with 4Mhz xtal and outputs 2 bytes to serial at 31250 Baud (uncomment commented code marked !!!)
; 2nd version works with 20 Mhz xtal and prescaled timer 1
LIST p=16F628A ;tell assembler what chip we are using
include "P16F628a.inc" ;include the defaults for the chip
__CONFIG _HS_OSC & _WDT_OFF & _PWRTE_OFF & _CP_OFF & _BODEN_OFF & _LVP_OFF
; vars left from orig
Bit_Cntr EQU 0x21
Cmd_Byte EQU 0x22
Dev_Byte EQU 0x23
Flags EQU 0x25
; vars new for CCP1 version
midi_byte0 EQU 0x2a
counthi EQU 0x2b
countlo EQU 0x2c
W_TMP EQU 0x2d
STATUS_TMP EQU 0x2e
FSR_TMP EQU 0x2f
timelo EQU 0x30
timehi EQU 0x31
periodlo EQU 0x32
periodhi EQU 0x33
StateFlags EQU 0x36
commandcomplete EQU 0x37
devicebyte EQU 0x38
commandbyte EQU 0x39
;delay constants
#define DELAYHI H'F3'
#define DELAYLO H'FF'
IR_In Equ 0x03 ;changed to 3 from 2 JWB ;input assignment for IR data
LED Equ 0x07 ; command rxd LED
ErrFlag Equ 0x00
StartFlag Equ 0x01 ;flags used for received bit
One Equ 0x02
Zero Equ 0x03
#define GetCommand 0
#define GetDevice 1
#define Ready 0 ; bit 0 of 'commandcomplete' flags sequence completed
org 0x0000 ; reset vector
goto Start
org 0x0004 ; IRQ vector
movwf W_TMP
swapf STATUS, W
clrf STATUS ; switch to bank 0
movwf STATUS_TMP
movf FSR, W
movwf FSR_TMP
IRQCheck
; which IRQ received?
btfsc PIR1,CCP1IF
goto CaptureIRQ
IRQEnd
movf FSR_TMP, W
movwf FSR
swapf STATUS_TMP, W
movwf STATUS
swapf W_TMP, F
swapf W_TMP, W
retfie
CaptureIRQ
; 1st clear interrupt
bcf PIR1,CCP1IF
bcf STATUS,C
movf timelo,W ; period = newtime - oldtime
subwf CCPR1L,W
movwf periodlo
movf timehi,W
subwf CCPR1H,W
movwf periodhi
; update timelo/hi
movf CCPR1L, W
movwf timelo
movf CCPR1H, W
movwf timehi
bsf STATUS,RP0 ; bank1
bcf PIE1 ^ 0x80, CCP1IE ; disable CCP interrupt whilst changing direction
bcf STATUS, RP0 ; bank 0
btfsc PORTB,3 ; test line
goto linehigh
linelow
clrf CCP1CON
movlw B'00000101' ; enable interrupts for rising edge
movwf CCP1CON
goto DoneCCP1IRQ ; only process rising edge
linehigh
clrf CCP1CON
movlw B'00000100' ; enable interrupts for falling edge
movwf CCP1CON
; test the pulse length and set flags accordingly
clrf Flags
TestError
; goto TestZero
movf periodhi,W
; !!! addlw .255 - .1 ; if periodhi <= 1, pulse is an error
addlw .255 - .1 ; if periodhi <= 1, pulse is an error
btfsc STATUS,C
goto TestZero
bsf Flags, ErrFlag
goto CalcByte
TestZero
movf periodhi,W
; !!! addlw .255 - .4 ; if periodhi <= 4, pulse is a zero
addlw .255 - .5 ; if periodhi <= 5, pulse is a zero
btfsc STATUS,C
goto TestOne
bsf Flags, Zero
goto CalcByte
TestOne
movf periodhi,W
; !!! addlw .255 - .6 ; if periodhi <= 6, pulse is a one
addlw .255 - .7 ; if periodhi <= 7, pulse is a one
btfsc STATUS,C
goto TestStart
bsf Flags, One
goto CalcByte
TestStart
movf periodhi,W
; !!! addlw .255 - .11 ; if periodhi <= 11, pulse is start pulse
addlw .255 - .13 ; if periodhi <= 13, pulse is start pulse
btfsc STATUS,C
goto IsErr
bsf Flags, StartFlag
goto CalcByte
IsErr
bsf Flags, ErrFlag
CalcByte
btfss Flags, StartFlag
goto chkerrflag
; when we arrive here a atartbit has been found
clrf Cmd_Byte ; clear accumulator for command
clrf Dev_Byte ; and for device number
clrf StateFlags ; clear old states
movlw 0x07 ; number of bits to get for command
movwf Bit_Cntr
bsf StateFlags, GetCommand ; indicate state = get cmd
goto DoneCCP1IRQ
chkerrflag
btfss Flags, ErrFlag
goto chkstatecmd
clrf StateFlags
goto DoneCCP1IRQ
chkstatecmd
btfss StateFlags, GetCommand
goto chkstatedev
bcf STATUS,C ; state = Get Command so check zero/one
btfss Flags, Zero
bsf STATUS,C
rrf Cmd_Byte,F ; rotate C into the accumulator
decfsz Bit_Cntr,F
goto DoneCCP1IRQ
rrf Cmd_Byte,F ; correct alignment of the seven bits
clrf StateFlags
bsf StateFlags, GetDevice ; move state to state = get device num
movlw 0x05 ; num of bits for device
movwf Bit_Cntr
goto DoneCCP1IRQ
chkstatedev
btfss StateFlags, GetDevice
goto IsErr
bcf STATUS,C ; state = Get Device so check zero/one
btfss Flags, Zero
bsf STATUS,C
rrf Dev_Byte,F
decfsz Bit_Cntr,F
goto DoneCCP1IRQ
rrf Dev_Byte,F ; correct alignment of the bits
rrf Dev_Byte,F ; correct alignment of the bits
rrf Dev_Byte,F ; correct alignment of the bits
movf Dev_Byte,W
movwf devicebyte ; make copy
movf Cmd_Byte,W
movwf commandbyte ; make copy
bsf commandcomplete,Ready ; flag sequence complete
bsf PORTB,7 ; switch on response LED
DoneCCP1IRQ
bsf STATUS,RP0 ; bank1
bsf PIE1 ^ 0x80,CCP1IE ; re-enable CCP1 interrupt
bcf STATUS,RP0 ; bank0
bcf PIR1,CCP1IF ; clear any spurious interrupt (see data sheet for why)
goto IRQEnd
; Main program starts here
Start
movlw 0x07
movwf CMCON ;turn comparators off (make it like a 16F84)
Initialise
clrf PORTA
clrf PORTB
clrf Flags
clrf Dev_Byte
clrf Cmd_Byte
SetPorts
bsf STATUS, RP0 ;select bank 1
movlw 0x00 ;make PortA all output
movwf TRISA ^ 0x80
movlw b'01111011' ;make IR port pin input, RB7 output to LED, RB2 serial TX, RB4 i/p for switch
movwf TRISB ^ 0x80
; init serial for 31250 Baud
movlw B'00100100' ;BEGIN SERIAL PORT INITIALIZATION, SET TXEN=1, BRGH=1
movwf TXSTA ^ 0x80
; !!! movlw 0x07 ; calc manually for 4 MHz clock using formula in data sheet
; movlw .39 ; calc manually for 20 MHz clock using formula in data sheet
movlw .129 ; 9600 Baud
movwf SPBRG ^ 0x80
bcf STATUS, RP0 ;select bank 0
; Configure Receive Status and Control Register
movlw (1 << SPEN) | (1 << CREN)
movwf RCSTA
bsf PORTB,7 ; switch on LED
call Delay
call Delay
call Delay
call Delay
bcf PORTB,7 ; switch LED Off
; init timelo/hi
movf TMR1L,W ; timelo = TMR1L
movwf timelo
movf TMR1H,W ; timehi = TMR1H
movwf timehi
clrf CCP1CON
movlw B'00000100' ; enable CCP1 interrupts for falling edge
movwf CCP1CON
bsf STATUS,RP0 ; bank1
bsf PIE1 ^ 0x80,CCP1IE ; enable CCP1 interrupt
bcf STATUS,RP0 ; bank0
clrf commandcomplete
movlw (1 << GIE) | (1 << PEIE) ; enable global and peripheral interrupts
movwf INTCON
; !!! bsf T1CON,TMR1ON ; switch on Timer 1 (No prescale)
movlw B'00100001'
movwf T1CON ; 5,4 = 10 = 1:4 prescale
movlw 0x55
movwf midi_byte0
call TxMidi ; send check byte to serial
Main
btfsc PORTB,4
goto Main ; loop till button press
bcf PORTB,7 ; switch off LED
maybe
btfss commandcomplete,Ready ; if byte rxd from IR
goto Main
; display on MIDI Monitor the 2 hex bytes for device and command
movf devicebyte,W
movwf midi_byte0
call TxMidi ; send device num to MIDI
movf commandbyte,W
movwf midi_byte0
call TxMidi ; send command num
clrf commandcomplete
goto Main
;=================
; Transmit to MIDI
;=================
TxMidi
btfss PIR1, TXIF
goto TxMidi ; poll til ready
movf midi_byte0,W
movwf TXREG
return
;======================================
; Delay loop
;======================================
Delay
MOVLW DELAYHI
MOVWF counthi
MOVLW DELAYLO
MOVWF countlo
DelayLoop
NOP ;WASTE SOME TIME
NOP
NOP
DECFSZ countlo,F
GOTO DelayLoop
DECFSZ counthi,F
GOTO Delaysetup2
GOTO Delaydone
Delaysetup2
MOVLW DELAYLO
MOVWF countlo
GOTO DelayLoop
Delaydone
RETURN
end