;******************************************************************* ; ; IR2RS232.ASM ; IR to RS232 to IR Program ; Version 1.0 (10/17/05) (Checksum ----) ; (C) 2005 Reymes ; Programmer: Jim Furey ; ;******************************************************************* ; ; Purpose: ; ; This program uses a PIC16F627A for RS232 communication, IR receive and IR transmit. ; Through a switch, it can be set for learn or operate to communicate with Infared signals ; from various modulated and non-modulated remote controls. Once it detects these signals, ; it stores it in EEPROM and asks the operator for a control character in ASCII to re-transmit ; the signal. ; ; Description: ; ; There are two modes of operation. One is "Learn" and the other is "Operate". This is ; changed by switch SW1. ; ; The description of "Learn" is as follows: ; ; Using the PORTB interrupt, the program waits for a "dark space" (low signal) out of the IR ; detector for more than 2mS. (There are many short pulses brought about by ambient noise ; before solid remote control IR.) ; This is the pre-amble (2 to 3 mS low). Each following "mark" high pulse (inverted condition ; out of IR detector) is followed by either a short (700uS) or long (1300us) low. A short low ; means "0" and long low means "1". This method of IR transmission/reception is called ; "space width coded" IR. ; Timer 1 determines the 0 or 1 space length by its width and saves one bit per byte into ; the RAM bytes "IRDATA". The count of how many bits is saved in "CLENGTH". The maximum ; bits that can be saved is 32. Most IR commands are between 12 and 22. ; When the IR detector outut goes high for more than 2mS, the transmission is over. ; The message "Ready to save, pick a character: " is then transmitted over the RS232 port. ; The unit waits for an ASCII character (see list of usable ASCII characters) and then searches the ; EEPROM for a match. If this character is already used, it outputs "Already used. Overwrite?" ; A "Y" will overwrite the previous bitstream saved for that character. A "N" will abandon the write. ; If that character is not already used, or "Y" was selected, the program searches for an unused ; block in the EEPROM to store the data in. If all blocks are used, it will output "No available ; space" and then end without storing. ; If a block is found, it then writes the data along with it's associated ASCII character in EEPROM ; and outputs the message "Ready". ; ;The description if "Operate" is as follows: ; ; When the SW1 switch is in the "Operate" mode, the unit will accept RS232 commands (at 9600 baud) ; and output associated IR bitstreams. When first powered up in the Operate mode, and also after ; every ASCII character in sent, the unit outputs "Ready" to the RS232 port. ; When each character is entered, (the return key is not needed) the unit goes to a look up table ; created by the user in "Learn" mode, and finds the associated match in ASCII. ; If no match is found, then the message "Error" is output to the RS232 port. ; If a match is found, then using the timer 1, it outputs a preamble 2.5mS low and then a 500uS ; pulse followed by each bit saved. This "pulse-bit-pulse-bit" is continued until all bits are sent. Then ; the last pulse stays high. This completes the IR transmission, and a "Ready" is sent again. ; ; ASCII table: ; ; 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 54 55 56 57 58 59 5A ; A B C D E F G H I J K L M N O P Q R S T U V W X Y Z ; ; 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A ; a b c d e f g h i j k l m n o p q r s t u v w x y z ; ; Notes: ; 1. For use with modulated or non-modulated, space width coded remotes with less than ; 31 characters per instruction. If there are more than 32 bits, then only the first 32 ; are captured. (Most are 12-22 bits) ; 2. RS232 operates at 9600 baud, 8 bits, 1 stop bit, no parity, ANSI emulation only ; ;******************************************************************* ; ; Revisions: ; 1.0 : Original program ; ;******************************************************************* ; Notes: ; Things left to do: ; 1. DONE ; 2. Do bits to real time IR out ; 3. Do bitstream output to IR ; 4. Logic for store, overwrite, delete of commands: ; a. Check for match, offer overwrite ; b. If full, show all used characters ; c. Entering characters while in learn mode deletes command ; d. ; ; list p=16f627a ; list directive to define processor #include ; processor specific variable definitions __CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_OFF &_EXTCLK_OSC &_LVP_OFF errorlevel -302 ; suppress message 302 from list file ;***** VARIABLE DEFINITIONS ***** ; RAM has 3 banks of usable space: | 0x20 to 0x7F (96 bytes)| 0xA0 to 0xEF (80 bytes)| 0x120 to 0x14F (48 bytes)| IRDATA equ 0x20 ; 32 bytes of data (from 0x20 to 0x3F) each representing a bit of IR irsave equ 0x40 ; Saved 32 bytes (from 0x40 to 0x5F) of IRDATA for storage to E2 AMTCH equ 0x60 ; ASCII charater to match to from incoming RS232 command asave equ 0x61 ; Saved ASCII matched character CLENGTH equ 0x62 ; Length of bits to send on outgoing comand lsave equ 0x63 ; Saved bit length count E2A equ 0x64 ; Byte for EEPROM address E2D equ 0x65 ; 6 bytes of data for E2 data to/from EEPROM (65-6A) dcnth equ 0x6B ; Delay counter high dcntl equ 0x6C ; Delay counter low pointer equ 0x6D ; ASCII Message pointer counter equ 0x6E ; ASCII byte counter wtemp equ 0x6F ; Temporary storage of W register during interrupt stemp equ 0x70 ; Temporary storage of Status register during interrupt stat1 equ 0x71 ; Status byte for flags irctrl equ 0x72 ; Counter for input capture and output strobe of IR irctrh equ 0x73 ; Counter for input capture and output strobe of IR ectr equ 0x74 ; 8 bit counter for E2 bit transfer e2bctr equ 0x75 ; Byte contains the number f bytes to transfer in/out of E2 ircnt equ 0x75 ; IR output counter xctr equ 0x77 ; Transfer counter tempb equ 0x78 ; Temp byte for black transfer RCV_REG equ 0x79 ; Receive register irlength equ 0x7A irpoint equ 0x7B ; Pointer for irplay's output ; ************** stat1 explanation: *************** ; 7 1 = Enable IR out condition stat1,7 ; 6 1 = If 1 being sent to IR LED (for 40kHz) stat1,6 ; 5 0 = space, 1 = pulse for IR out stat1,5 ; 4 1 = RS232 RCV character received stat1,4 ; 3 0/1 = history of Modulate/Non-modulate pin (PORTB,7) stat1,3 ; 2 1 = echos what's on the IROUT pin stat1,2 ; 1 1 = flag to output "Ready to save, pick a character:" stat1,1 ; 0 1 = start bit found (in IR input) stat1,0 ;PORTA: O_L equ 4 ; Used for Operate/Learn switch in MODSW equ 3 ; Used for Modulate/Non-modulate SW2 in BITSW equ 2 ; Used for ASCII/Bitstream SW3 in REDLED equ 1 ; Used for red LED error indicator out GRNLED equ 0 ; Used for green LED IR accept indicator out ;PORTB: NU1 equ 7 ; Port pin not used out NU2 equ 6 ; Port pin not used out NU3 equ 5 ; Port pin not used out IRIN equ 4 ; IR receiver input in IRNOT equ 3 ; Inverse of IROUT pin out RS232O equ 2 ; RS232 output to PC out(in) RS232I equ 1 ; RS232 input from PC in IROUT equ 0 ; IR transmitter output out org 0 ; Reset Vector goto start ; Go to Main Program org 0004 ; Interrupt Vector goto ints ; Go to Interrupt service routine org 0005h ; Start of user program ($0005h to $03FFh) (twice as much in PIC16F628A) ;**************************************************************************** ;**************************************************************************** ;******************************** Main Program ********************************* ;**************************************************************************** ;**************************************************************************** ; ;************************* INITIALIZE PIC ********************** start bcf STATUS,RP0 ; Select Bank 0 bcf STATUS,RP1 bcf STATUS,IRP movlw 0x1F ; Initialize data for PORTA movwf PORTA movlw 0xD1 ; Initialize data for PORTB movwf PORTB bsf STATUS,RP0 ; Initialize PORTA directions - Select Bank 1 movlw 0x10 ; Set porta directions (a 0 is out, a 1 is in) movwf TRISA bcf STATUS,RP0 ; De-select Bank 1 bsf STATUS,RP0 ; Initialize PORTB directions - Select Bank 1 movlw 0xD6 ; Set portb directions (a 0 is out, a 1 is in) was 1B movwf TRISB bcf STATUS,RP0 ; De-select Bank 1 movlw 0x07 ; Initialize the comparitors as off movwf CMCON bcf STATUS,IRP ; Clear all RAM locations from 0x20 to 0x7F movlw 0x20 movwf FSR rcloop clrf INDF incf FSR,f btfss FSR,7 goto rcloop ; ******* INITIALIZE RS232 PORT ******* bsf STATUS,RP0 ; Initialize RS232 TSCR - Select Bank 1 movlw 0xA0 ; WAS A2 Load Transmit Status and Control Register ((24)) movwf TXSTA ; 7)NA, 6)1=9bit, 5)1-TX EN, 4)0=Asyn/1=Sync, 3)NA, 2)Baud 0=lo/1=hi, 1)TXFLG, 0)Parity bit set bcf STATUS,RP0 ; De-select Bank 1 bsf STATUS,RP0 ; Initialize RS232 SPBRG - Select Bank 1 movlw 0x20 ; Load Baud Rate Register (Set for 9600 baud using a 20MHz Xtal) movwf SPBRG ; Entire byte for baud divisor. bcf STATUS,RP0 ; De-select Bank 1 movlw 0x90 ; Was B0 WAS A0 (Could be B0) Load Transmit Status and Control Register (B0 is enable receiver) ((90)) movwf RCSTA ; 7)RS232 EN, 6)9bitRcvEN, 5)Single Rcv En, 4)Cont. Rcv En, 3)Addr En, 2-1-0)Rest are flags ; ******** INITIALIZE OTHER PERIPHERAL INTERRUPTS ********* bsf STATUS,RP0 ; Select Bank 1 movlw 0xC0 ; Set Opt_Reg: disable pull-ups(7), rising edge int on PORTB(6), Timer0 clock source(5)prescale movwf OPTION_REG ; Timer0 source edge select(4), prescaller assignment(3), Timer0 prescaller(0-2) bcf STATUS,RP0 ; De-select Bank 1 bsf STATUS,RP0 ; Select Bank 1 movlw 0xC8 ; Set Interrupt Control Reg. Global(7), Peripheral enable(6) [for RS232, E2, TMR1&2], Timer0 OVF(5), movwf INTCON ; External Int.(4), RB Port Change(3), Flags(0-2) bcf STATUS,RP0 ; De-select Bank 1 clrf TMR1L ; Clear Timer1 values clrf TMR1H bsf STATUS,RP0 ; Select Bank 1 movlw 0x01 ; 03 Was 01 WAS 21 Set Perpherial Interrupt Control Reg. EE Int.(7), Comparitor(6), RS232RCV(5), RS232TX(4) movwf PIE1 ; Not used(3), Compare(2), Timer2 match(1), Timer1 OVF(0) bcf STATUS,RP0 ; De-select Bank 1 movlw 0x05 ; 05 Initialize Timer1 Control Register movwf T1CON bsf STATUS,RP0 ; Select Bank 1 movlw 0x3E ; Initialize Timer2 value (This will make a 40kHz signal) movwf PR2 bcf STATUS,RP0 ; De-select Bank 1 movlw 0x04 ; Initialize Timer2 pre and post scalers movwf T2CON ;TMR2 ; *********************************************************************** ; * Main routine. The main routine detects first the transmission * <<<<<<<<<<<<<<<<<<<<<< ; * time of the incoming calibration character. After that the * <<<<<<<<<<<<<<<<<<<<<< ; * routine receives and transmits incoming characters. * <<<<<<<<<<<<<<<<<<<<<< ; *********************************************************************** Main ;bsf STATUS,RP0 ; Select bank 1 +++ Clear random interrupts happening from O/L transition +++ ;main1 bcf INTCON,GIE ; Disable interrupts ; btfsc INTCON,GIE ; Test if no other interrupts happened during disable ; goto main1 ; bsf INTCON,GIE ; Re-enable interrupts ; bcf STATUS,RP0 ; Deselect bank 1 movlw 0x00 ; RS232 transmit message "Ready" 00,07 movwf pointer movlw 0x07 movwf counter call msgout ;goof goto goof loop1 btfsc PORTA,O_L ; Check if switch set for Learn(0) or Operate(1) goto oper goto learn ; <<<<<<<<<< OPERATE >>>>>>>>>>> oper bsf STATUS,RP0 ; Select Bank 1 bcf INTCON,RBIE ; Disable Interrupts on PORTB change bcf EECON1,WREN ; Disable E2 writes bcf STATUS,RP0 ; De-select Bank 1 oper1 btfss PORTA,O_L ; Check if switch still set for Operate(1) or changed to Learn(0) goto Main ; If switch changed to LEARN while in OPERATE, then restart main loop call modchk ; Check if modulate/non-modulate switch has changed and set accordingly btfsc PORTA,BITSW ; Test if E2 mode (1) or Bitstream mode (0) on SW3 goto oper2 ; If E2 mode, go to that mode continue ; Bitstream mode: ; Wait for "b" or "B" to start ; Accumulate charaters ; Wait for "e" or "E" to end, and then: ; call irplay goto oper1 ; And return ; E2 mode: oper2 btfss PIR1,RCIF ; Check if data in RS232 Receiver buffer (looking for input character) +++ WAIT FOR CHARACTER +++ goto oper1 ; Go on to next test if nothing there call rcv232 ; Get byte OR clear errors. If return with 1, then error. If return with 0, then good xorlw 0x00 ; Check if good btfss STATUS,Z ; Check if 0 which is good goto oper1 ; If it was a 1, then is was just an error, loop back again. Else: movf RCV_REG,w ; Get what's in Received byte call e2mtch ; Do match to compare E2 data with RCV_REG ASCII character C=0=no, C=1=yes btfss STATUS,C ; Test if match was found. goto opernm ; Match not found - loop back to main operate loop bcf PORTA,GRNLED ; Turn on the green LED call ee2r ; Transfer E2D 6 bytes to "IRDATA" bytes call irplay movlw 0x64 ; Then RS232 transmit message "OK" 64,06 movwf pointer movlw 0x06 movwf counter call msgout bsf PORTA,GRNLED ; Turn off the green LED goto oper1 ; Loop the main operate loop opernm bcf PORTA,REDLED ; No match found so send "Abort" - Turn on red LED +++ NO MATCH FOUND +++ movlw 0x5D ; RS232 transmit message "Abort" 5D,09 Need to be 1 back (5C rather than 5D) because sub in a sub movwf pointer movlw 0x09 movwf counter call msgout bsf PORTA,REDLED ; Turn off red LED goto oper1 ; Loop the main operate loop ; <<<<<<<<<< LEARN >>>>>>>>>>> learn bsf STATUS,RP0 ; Select Bank 1 bsf INTCON,RBIE ; Enable Interrupts on PORTB change bcf PIE1,TMR2IE ; Disable Timer2 Interrupts (40kHz timer) bcf STATUS,RP0 ; De-select Bank 1 learn1 btfsc PORTA,O_L ; Check if switch set for Learn(0) or Operate(1) goto Main ; If switch changed to OPERATE while in LEARN, then restart main loop btfsc PORTA,BITSW ; Test if E2 mode (1) or Bitstream mode (0) on SW3 goto learn2 ; If E2 mode, go to that mode continue ; Bitstream mode: btfss stat1,7 ; If in Bitstream mode, test if "send string" bit set goto learn1 ; if not set, loop back call cmdout ; If set, send out string of characters - THIS IS FOR BITSTREAM MODE ONLY bcf stat1,0 ; Clear start bit found clrf CLENGTH clrf irctrl ; Clear counters clrf irctrh bcf stat1,7 ; Clear this and any new bit set goto learn1 ; E2 mode: +++CHECK FOR ~ TO ERASE ALL E2+++ learn2 btfss PIR1,RCIF ; Check if data in RS232 Receiver buffer (looking for tilde) goto learng ; Go on to next test if nothing there call rcv232 ; Get byte OR clear errors. If return with 1, then error. If return with 0, then good xorlw 0x00 ; Check if good btfss STATUS,Z ; Check if 0 which is good goto learng ; If it was a 1, then is was just an error, loop on to next test. Else: movf RCV_REG,w ; Get what's in Received byte xorlw 0x7E ; Compare with tilde (~) btfss STATUS,Z ; Check if the same goto learng ; If not the same, go on to next test movlw 0x48 ; If it's a tilde, then RS232 transmit message "Erase all E2? Y/N? " 48,15 movwf pointer movlw 0x15 movwf counter call msgout ; +++LOOKING FOR "Y" ON TILDE +++ learna btfss PIR1,RCIF ; Check if data in RS232 Receiver buffer (looking for tilde) goto learna ; Go on to next test if nothing there call rcv232 ; Get byte OR clear errors. If return with 1, then error. If return with 0, then good xorlw 0x00 ; Check if good btfss STATUS,Z ; Check if 0 which is good goto learna ; If it was a 1, then is was just an error, loop on to next test. Else: movf RCV_REG,w ; Get what's in Received byte xorlw 0x79 ; Compare with 'y" btfsc STATUS,Z ; Check if the same goto learnec ; If the same, go to clear all E2 abort bcf PORTA,REDLED ; If not a "y", then RS232 transmit message "Abort" 5D,09 - Turn on red LED +++ NOT A "Y" ON TILDE +++ movlw 0x5D ; RS232 transmit message "Abort" 5D,09 Need to be 1 back (5C rather than 5D) because sub in a sub movwf pointer movlw 0x09 movwf counter call msgout bsf PORTA,REDLED ; Turn off red LED lsame1 movlw 0x00 ; Then RS232 transmit message "Ready" 00,07 movwf pointer movlw 0x07 movwf counter call msgout bsf PORTA,GRNLED ; Turn off the green LED bcf stat1,7 ; Clear all bits and restart bcf stat1,1 ; Clear "Send - Ready to save, pick a character:" bit bcf stat1,0 ; Clear start bit found goto learn1 learnec bcf PORTA,GRNLED ; Turn on the green LED +++ YES, A "Y" ON TILDE +++ call clre2 ; Clear all internal E2 data (except last 2 bytes) to "00" movlw 0x64 ; Then RS232 transmit message "OK" 64,06 movwf pointer movlw 0x06 movwf counter call msgout goto lsame1 learng btfss stat1,7 ; If in E2 mode, check if command found +++ CHKING FOR COMMAND END BIT +++ goto learn1 ; If not loop back btfss stat1,1 ; Test for "output "Ready to save, pick a character:" bit goto learn1 ; If status bit not set, loop back call bxfer ; Transfer data from IRDATA and CLENGTH to irsave and lsave +++ XFER FROM IRDATA TO IRSAVE +++ movlw 0x07 ; RS232 transmit message "Ready to save, pick a character:" 07,21 +++ XMIT "PICK A CHARACTER" +++ movwf pointer movlw 0x21 ; Load message count of bytes (characters) to send movwf counter call msgout bcf stat1,1 ; Clear send message bit learnk btfss PIR1,RCIF ; Check if data in RS232 Receiver buffer +++ CHKING FOR CHARACTER +++ goto learnk ; Go on to next test if nothing there call rcv232 ; Get byte OR clear errors. If return with 1, then error. If return with 0, then good xorlw 0x00 ; Check if good btfss STATUS,Z ; Check if 0 which is good goto learnk ; If it was a 1, then is was just an error, loop on to next test. Else: movf RCV_REG,w ; Get what's in Received byte +++ CHK WHAT'S IN CHARACTER +++ xorlw 0x1B ; Compare with escape key +++ CHK IF IT'S AN ESCAPE +++ btfss STATUS,Z ; Check if the same goto learnsc ; If not the same, go to save character abort2 movlw 0x0D ; Do a carriage return movwf TXREG ; Put the returned byte into the RS232 buffer call bitchk ; Check transmit flag, that byte is sent bcf stat1,7 ; Clear all bits and restart +++ IT'S AN ESCAPE, SO ABORT +++ bcf stat1,1 bcf stat1,0 ; Clear start bit found bsf PORTA,GRNLED ; Clear the LED goto abort ; +++ IT'S A CHARACTER, CHK 4 MATCH +++ learnsc call e2mtch ; Check if there's a match in internal E2 that matches ascii in RCV_REG. C=0=no, C=1=yes btfss STATUS,C ; Test if match found goto learnbl ; If no match, go to "find a blank" ; +++ MATCH FOUND WITH E2 +++ movlw 0x28 ; If already saved/a match, then RS232 message "Already used. Overwrite? Y/N? " 28,20 +++ "OVERWRITE?" +++ movwf pointer movlw 0x20 ; Load message count of bytes (characters) to send movwf counter call msgout learni btfss PIR1,RCIF ; Check if data in RS232 Receiver buffer (looking for tilde) +++ LOOKING 4 "Y" on OVERWRITE +++ goto learni ; Go on to next test if nothing there call rcv232 ; Get byte OR clear errors. If return with 1, then error. If return with 0, then good xorlw 0x00 ; Check if good btfss STATUS,Z ; Check if 0 which is good goto learni ; If it was a 1, then is was just an error, loop on to next test. Else: movf RCV_REG,w ; Get what's in Received byte xorlw 0x79 ; Compare with 'y" btfsc STATUS,Z ; Check if the same goto learn5 ; If the same, go to save in same location +++ "Y" FOUND, GOTO +++ goto abort2 ; If not a "y", then RS232 transmit message "Abort" 5D,09 - Turn on red LED and clear and start over +++ ELSE ABORT +++ learnbl call findsp ; Locate empty slot for new command +++ FIND EMPTY SLOT +++ btfsc STATUS,C ; Test if blank spot was found. C=0=no space found, C=1=space found goto learn5 ; If yes, then save it to empty space goto abort2 ; If no blank spaces, then RS232 transmit message "Abort" 5D,09 ; +++ "Y" ON OVERWRITE OR WRITE +++ learn5 call r2ee ; Convert IRDATA 32 bytes into E2D data 4 bytes, ready for writing. +++ SO CONVERT DATA TO 6 BYTES +++ call e2wr ; Write 6 bytes to internal E2 +++ AND SAVE IN E2 +++ movlw 0x64 ; RS232 transmit message "OK" 64,06 +++ XMIT "OK" +++ movwf pointer movlw 0x06 movwf counter call msgout goto lsame1 ; RS232 transmit message "Ready" 00,07, clear bits and return to main loop +++ XMIT "READY", CLR & LOOP +++ learnez bcf stat1,7 ; Clear this and any new bit set goto learn1 ; *********************************************************************** ; *********************************************************************** ; ************************** End Of Main Loop ****************************** ; *********************************************************************** ; *********************************************************************** ;************************************************************************ ;************************************************************************ ;******************************* Subroutines ****************************** ;************************************************************************ ;************************************************************************ ;************************** CHECK MODULATE SWITCH SW2 ***************** modchk btfss PORTA,MODSW goto turnon turnoff btfss stat1,3 ; Test status MODSW is high (normal) return bcf stat1,3 bsf STATUS,RP0 ; Select Bank 1 bcf PIE1,TMR2IE ; Disable TIMER2 Interrupts bcf STATUS,RP0 ; De-select Bank 1 return turnon btfsc stat1,3 ; MODSW is low (Modulate) return bsf stat1,3 bsf STATUS,RP0 ; Select Bank 1 bsf PIE1,TMR2IE ; Enable TIMER2 Interrupts bcf STATUS,RP0 ; De-select Bank 1 return btfss stat1,3 ; Check status of Modulate switch history goto mody ; History is 1 modn btfsc PORTA,MODSW ; Check if modulated switch is on (low) return ; End mod check ; Switch changed from 1 to 0 bcf stat1,3 ; Change occured to create modulate state modu bsf STATUS,RP0 ; Select Bank 1 bsf PIE1,TMR2IE ; Enable TIMER2 Interrupts bcf STATUS,RP0 ; De-select Bank 1 ;bsf T2CON,TMR2ON ; Turn on the timer return ; End mod check ; History is 0 mody btfss PORTA,MODSW ; Check if modulated switch is off (high) return ; End mod check ; Switch changed from 0 to 1 bsf stat1,3 ; Change occured to go to non-modulated state nonmod bsf STATUS,RP0 ; Select Bank 1 bcf PIE1,TMR2IE ; Disable TIMER2 Interrupts bcf STATUS,RP0 ; De-select Bank 1 ;bcf T2CON,TMR2ON ; Turn off the timer modend return ;************************** GENERAL DELAY OF 40MS ********************** cdelay movlw 0x1F ; Load small delay count goto delcom idelay movlw 0x7F ; Load large delay count (IDELAY IS 40 MS LONG) delcom movwf dcnth idly0 clrf dcntl ; Load small delay count idly1 nop ; Wait a bit nop nop decfsz dcntl, F ; Decrement small delay count and check for 0 goto idly1 ; If not 0, loop decfsz dcnth, F ; Decrement large delay count and check for 0 goto idly0 ; If not 0, loop return ;************************* RS232 MESSAGE OUT SUBROUTINE ************** msgout movlw 0x03 movwf PCLATH movf pointer,0 ; Load with beginning pointer of message call msg1 ; Get byte to load into RS232 buffer movwf TXREG ; Put the returned byte into the RS232 buffer call bitchk ; Check transmit flag, that byte is sent incf pointer,1 ; Increment the pointer to the next character address decfsz counter,1 ; Decrement counter and check for last byte goto msgout ; If not last byte, return for more return ;************************* TEST FOR RS232 TRANSMITTER BUFFER EMPTY ***** bitchk bsf STATUS,RP0 ; Initialize RS232 TSCR - Select Bank 1 bc1 btfss TXSTA,TRMT ; Test if ready for next character goto bc1 ; Loop if not bcf STATUS,RP0 ; De-select Bank 1 return ; ; Relationship of 32 "bit" data to Internal E2 data bytes ; ; AMTCH (0x40 1 byte) --> E2D (0x43 first byte) ; CLENGTH (0x21 1 byte) --> E2D+1 (0x44 second byte) ; IRDATA (0x20 32 bytes) --> E2D+2 to E2D+5 (0x45 to 0x48 4 bytes) ; ;********************** Writes 6 bytes into internal E2 ********************** ; Set up is: start address to write is already in E2A and will be transferred to EEADR. ; For saving of data, subroutine "r2ee" has already been run and IRDATA, AMTCH ; and CLENGTH is already in E2D through E2D+5. Note: 8mS write time per byte. ; e2wr movf E2A,w ; Get start address to write to bsf STATUS,RP0 ; Select bank 1 movwf EEADR ; Store it in Internal EE address byte bcf STATUS,RP0 ; Deselect bank 1 movf E2D,w ; Get ascii character to save as first byte call e2wsub ; Write byte movf E2D+1,w ; Load command length byte call e2wsub ; Write byte movf E2D+2,w ; Load command data byte 1 call e2wsub ; Write byte movf E2D+3,w ; Load command data byte 2 call e2wsub ; Write byte movf E2D+4,w ; Load command data byte 3 call e2wsub ; Write byte movf E2D+5,w ; Load command data byte 4 call e2wsub ; Write byte return e2wsub bsf STATUS,RP0 ; Write to E2 - Set to bank 1 movwf EEDATA ; Save byte to Internal EEDATA byte esub1 bcf INTCON,GIE ; Disable interrupts btfsc INTCON,GIE ; Test if no other interrupts happened during disable goto esub1 bsf EECON1,WREN ; Enable writes movlw 0x55 ; Do start sequence (55h first) movwf EECON2 movlw 0xAA ; Do start sequence (then AAh writes to E2) movwf EECON2 bsf EECON1,WR ; Set write bit to start write bcf STATUS,RP0 ; Return to bank 0 esub2 btfss PIR1,EEIF ; Check if write is complete goto esub2 ; If not, loop and test bsf STATUS,RP0 ; If write is done - Set to bank 1 incf EEADR,f ; Increment the address to write to bsf INTCON,GIE ; Re-enable interrupts bcf STATUS,RP0 ; Return to bank 0 return ;********************** Reads 6 bytes from internal E2 ********************** ; Set up is: start address to write is already in E2A and will be transferred to EEADR. ; e2rd movf E2A,w ; Get start address to write to bsf STATUS,RP0 ; Select bank 1 movwf EEADR ; Store it in Internal EE address byte bsf EECON1,RD ; Initiate a read movf EEDATA,w ; Save data into w bcf STATUS,RP0 ; Deselect bank 1 movwf E2D ; Save it to first byte call e2rsub movwf E2D+1 ; Save it to second byte byte call e2rsub movwf E2D+2 ; Save it to third byte byte call e2rsub movwf E2D+3 ; Save it to fourth byte byte call e2rsub movwf E2D+4 ; Save it to fifth byte byte call e2rsub movwf E2D+5 ; Save it to sixth byte byte return e2rsub bsf STATUS,RP0 ; Select bank 1 incf EEADR,f ; Increment to next address bsf EECON1,RD ; Initiate a read movf EEDATA,w ; Save data into w bcf STATUS,RP0 ; Deselect bank 1 return ;*** Transfers bit data in asave(AMTCH), csave(CLENGTH) and irsave(IRDATA) bytes into 8 bit bytes in E2D bytes for Internal EEPROM storage *** ; r2ee movf RCV_REG,w ; Transfer ASCII match byte movwf E2D movf lsave,w ; Transfer bit length byte movwf E2D+1 movlw 0x20 ; Load total bit counter with 32 movwf e2bctr movlw irsave ; Load pointer with IR data start movwf FSR r2e1 rrf INDF,w ; Rotate b0 of pointed IR data register into Carry rrf E2D+2,1 rrf E2D+3,1 rrf E2D+4,1 rrf E2D+5,1 ; Rotate through incf FSR,1 ; Point to next bit decfsz e2bctr,1 ; Check if last (32nd) bit goto r2e1 ; If not, go do another rotate return ; Relationship of 32 "bit" data to Internal E2 data bytes ; ; AMTCH (0x20 1 byte) --> E2D (0x50 first byte) ; CLENGTH (0x21 1 byte) --> E2D+1 (0x51 second byte) ; IRDATA (0x22 32 bytes) --> E2D+2 to E2D+5 (0x52 to 0x55 4 bytes) ;************** Transfers 8 bit bytes in E2D bytes into (active output) bit data in IRDATA, CLENGTH and IRDATA bytes *********** ; This subroutine is called in the operate mode when a match has already been found and the internal EEPROM data is already in the ; E2D bytes. It then transfers those bits/bytes to the "active" IRDATA and CLENGTH to be transmitted out. AMTCH is not necessary. ; ee2r movf E2D+1,w ; Transfer bit length byte movwf CLENGTH movlw 0x20 ; Load total bit counter with 32 movwf e2bctr ; Will transfer full 32 bits even if not all were used movlw IRDATA ; Load pointer with IR data start address (IRDATA) movwf FSR rmore rrf E2D+2,1 ; Rotate through rrf E2D+3,1 rrf E2D+4,1 rrf E2D+5,1 btfss STATUS,C ; Test if 0 or 1 goto risa0 risa1 bsf INDF,0 goto bitin risa0 bcf INDF,0 bitin incf FSR,f ; Point to next byte for bit decfsz e2bctr,1 ; Decrement the total bit counter goto rmore ; Not done with stored bits, go get another return ;******************* E2 MATCH - Check each location for 00 or ASCII match ***************** ; Addresses: 00, 06, 0C, 12, 18, 1E, 24, 2A, 30, 36, 3C, 42, 48, 4E, 54, 5A, 60, 66, 6C, 72, 78 e2mtch movlw 0x00 ; Set E2 address to the beginning movwf E2A ; Store inE2A for EEADR e2m1 call e2rd ; Reads 6 bytes from that address and puts in E2D data movf E2D,w ; Load what's in first read character byte from E2 (CHaracter location) xorwf RCV_REG,w ; Compare it with what's in RCV_REG btfsc STATUS,Z ; Test if Zero, which means a match goto mtched ; If Zero, then it matched movf E2A,w ; Check address byte for top (78) address already achieved xorlw 0x78 ; btfss STATUS,Z ; If zero, it's a match with 78 goto e2m2 ; If not zero yet, go get another block to test bcf STATUS,C ; Clear the carry bit, meaning "no match" return ; And return e2m2 movlw 0x06 ; Else get ready to add 6 to address addwf E2A,f ; Store back to E2A goto e2m1 mtched bsf STATUS,C ; Set the carry bit meaning "match found" return ; And return ;************************* Look for empty spot in Internal E2 *********************** findsp movlw 0x00 ; Set E2 address to the beginning movwf E2A ; Store in EEADR findsp1 call e2rd ; Reads 6 bytes from that address movf E2D,f ; Check if data is "00" btfss STATUS,Z ; Check if byte was a 0 goto notsp ; If not 0, then get another location bsf STATUS,C ; Return with carry bit set, meaning "here's a space" return ; And return (This will leave the open address intact in E2A) notsp movf E2A,w ; Check address byte for top (78) address already achieved xorlw 0x78 ; Compare with top address btfss STATUS,Z ; If zero, it's a match with 78 goto nextsp bcf STATUS,C ; Clear the carry bit, meaning "no match" return ; And return nextsp movlw 0x06 ; Else get ready to add 6 to address addwf E2A,f ; Store back to E2A goto findsp1 ;************************* Clear all Internal E2 ******************************* clre2 movlw 0x00 ; Set E2 address to the beginning movwf E2A ; Store in EEADR clre22 clrf E2D clrf E2D+1 clrf E2D+2 clrf E2D+3 clrf E2D+4 clrf E2D+5 call e2wr ; Write 6 blanks to byte block comf E2A,w ; Check address byte for top (78) address already achieved addlw 0x87 ; Add compliment of 78 btfsc STATUS,Z ; If zero, it's a match with 78 return movlw 0x06 ; If not, add 6 to address addwf E2A,f ; Store back to E2A goto clre22 ; And go clear another block ;******************* IR output ***************** irplay ; 2.5ms on 50 (x50uS) [12.750mS max with 0xFF] ; 0 = 550uS off / 650uS on 11 / 14 (x50uS) ; 1 = 550uS off / 1250uS on 11 / 26 (x50uS) ; 10ms on 200 (x50uS) movlw 0xFF ; Do 12.75mS dark/on time movwf ircnt bsf stat1,2 ; Show that ir is "on" bcf PORTB,IROUT ; Turn on IR LED bsf PORTB,IRNOT ; Do inverse bsf stat1,5 ; Set enable bit irplay1 btfsc stat1,5 ; Check if 12.75mS has gone by goto irplay1 ; If not, wait movlw 0x32 ; Now do start marking by turning off LED for 2.5mS movwf ircnt bcf stat1,2 ; Show that ir is "off" bsf PORTB,IROUT ; Turn off IR LED bcf PORTB,IRNOT ; Do inverse bsf stat1,5 ; Set enable bit irplay2 btfsc stat1,5 ; Check if 2.5mS has gone by goto irplay2 ; If not, wait movf CLENGTH,w ; Load with count to do movwf irlength movlw IRDATA ; Load pointer with starting bit movwf FSR irbits call iroff ; Start with a "space" irout3 btfsc stat1,5 ; Test if enable bit reset goto irout3 ; If not, keep testing rrf INDF,w ; Rotate bit into carry bit btfss STATUS,C ; Test to see if it's a 0 or 1 goto irout0 irout1 call ir1 ; Send out a long 1 goto irout2 irout0 call ir0 ; Send out a short 0 irout2 btfsc stat1,5 ; Test if enable bit reset goto irout2 ; If not, keep testing incf FSR,f ; Increment to the next bit to send decfsz irlength,f ; Check if this is the last goto irbits ; If not, go get another bit movlw 0xFF ; Do another 12.75mS of dark/on time before returning movwf ircnt bsf stat1,2 ; Show that ir is "on" bcf PORTB,IROUT ; Turn on IR LED bsf PORTB,IRNOT ; Do inverse bsf stat1,5 ; Set enable bit irplay3 btfsc stat1,5 ; Check if 12.75mS has gone by goto irplay3 ; If not, wait bcf stat1,2 ; Show that ir is "off" bsf PORTB,IROUT ; Turn off IR LED before leaving bcf PORTB,IRNOT ; Do inverse return iroff bsf stat1,2 ; Show that ir is "on" bcf PORTB,IROUT ; Turn off IR LED bsf PORTB,IRNOT ; Do inverse movlw 0x0B ; Load a count of 11 for 550uS off movwf ircnt bsf stat1,5 ; Set enable bit return ir0 bcf stat1,2 ; Show that ir is "off" bsf PORTB,IROUT ; Turn on IR LED bcf PORTB,IRNOT ; Do inverse movlw 0x0D ; Load a count of 13 for 650uS on movwf ircnt bsf stat1,5 ; Set enable bit return ir1 bcf stat1,2 ; Show that ir is "off" bsf PORTB,IROUT ; Turn on IR LED bcf PORTB,IRNOT ; Do inverse movlw 0x19 ; Load a count of 25 for 1250uS on movwf ircnt bsf stat1,5 ; Set enable bit return ;*** Transfers 34 bytes from AMTCH/CLENGTH/IRDATA to asave/lsave/irsave for saving *** bxfer ;movf AMTCH,w ; movwf asave movf CLENGTH,w movwf lsave movlw 0x20 ; Load total bit counter with 32 movwf e2bctr ; Will transfer full 32 bits even if not all were used movlw IRDATA ; Save source location address movwf ectr movlw irsave ; Save destination location address movwf xctr blkloop movf ectr,w ; Load with source address movwf FSR movf INDF,w ; Get byte at source address movwf tempb ; Save it temporarily movf xctr,w ; Load with destination address movwf FSR movf tempb,w ; Get temporary byte movwf INDF ; And save it in destination address incf ectr,f ; Increment addresses incf xctr,f decfsz e2bctr,f ; Decrement byte transfer counter goto blkloop ; If not last byte, loop back for another return ; Else return ;**************************** RS232 Receive Byte Subroutine **************************** ; Call this routine after successfully testing PIR1,RCIF flag for byte present. Will put byte in RCV_REG rcv232 btfss RCSTA,OERR ; If overrun error occurred (in bank 0) goto rcv1 bcf RCSTA,CREN ; Reset the receiver logic bsf RCSTA,CREN ; Enable reception again retlw 1 ; Return with error rcv1 btfss RCSTA,FERR ; If framing error occurred goto rcv2 movf RCREG,W ; Discard received data that has error retlw 1 ; Return with error rcv2 movf RCREG,W ; Get received data (in bank 0) movwf RCV_REG ; Save it in Receive Register ffff addlw 0xBF ; Test if less than 41(capital A) btfss STATUS,C retlw 0 ; If less than 41, then bail movf RCV_REG,w ; Get byte again addlw 0xA5 ; Test if more than 5A (capital Z) btfsc STATUS,C retlw 0 ; If more than 5A, then bail movlw 0x20 ; If it's a capital letter, add 0x20 to it addwf RCV_REG,f ; And make it a small case letter and save retlw 0 ; Return good ;************************************************************************ ;************************************************************************ ;************************** ALTERNATE SUBROUTINES *********************** ;************************************************************************ ;************************************************************************ ;******************* Alternate send command as 1's and 0's subroutine ********* ; Addresses: 00, 06, 0C, 12, 18, 1E, 24, 2A, 30, 36, 3C, 42, 48, 4E, 54, 5A, 60, 66, 6C, 72, 78 cmdout movlw 0x42 ; Send a "B" movwf TXREG ; Put the returned byte into the RS232 buffer call bitchk ; Check transmit flag, that byte is sent movf CLENGTH,w ; Save length to counter movwf ectr movlw IRDATA ; Set FSR with beginning of IR data to serve as pointer movwf FSR cmdl1 rrf INDF,0 btfss STATUS,C goto itsa0 goto itsa1 itsa0 movlw 0x30 ; Send a "0" movwf TXREG ; Put the returned byte into the RS232 buffer call bitchk ; Check transmit flag, that byte is sent goto cmd2 itsa1 movlw 0x31 ; Send a "1" movwf TXREG ; Put the returned byte into the RS232 buffer call bitchk ; Check transmit flag, that byte is sent cmd2 incf FSR,1 ; Increment the pointer decfsz ectr,1 ; Decrement the counter and test if that was the last byte to be sent goto cmdl1 ; If not the last byte, send another byte. Else if last byte, then: movlw 0x45 ; Send an "E" movwf TXREG ; Put the returned byte into the RS232 buffer call bitchk ; Check transmit flag, that byte is sent call idelay ; Delay 40mS movlw 0x20 ; Send an " " movwf TXREG ; Put the returned byte into the RS232 buffer call bitchk ; Check transmit flag, that byte is sent call idelay ; Delay 40mS movlw 0x20 ; Send an " " movwf TXREG ; Put the returned byte into the RS232 buffer call bitchk ; Check transmit flag, that byte is sent call idelay ; Delay 40mS return ;**************************************************************************** ;**************************************************************************** ;*********************************** Interrupts ******************************** ;**************************************************************************** ;**************************************************************************** ; ; *** For all interrupts, save registers *** ints movwf wtemp ; save off current W register contents movf STATUS,w ; move status register into W register movwf stemp ; save off contents of STATUS register bcf STATUS,RP0 ; STATUS saved, so now corrupt and select bank 0 no matter what ; ***** Timer 1 interrupt service routine ***** tmr1 btfss PIR1,TMR1IF ; Test if Timer 1 has Overflowed [50uS] (bit 0) goto rsrcv ; If not, go to next interrupt check movlw 0x18 ; Reload low end register for 50uS movwf TMR1L movlw 0xFF ; Reload high end register for 50uS movwf TMR1H btfss PORTA,O_L ; Check if switch set for Learn(0) or Operate(1) goto tmr1l ; If learn, go to learn section tmr1o btfss stat1,5 ; Check if bit set meaning enable count goto tmr1b ; If not set, clear and go on decfsz ircnt,f ; Decrement counter goto tmr1b ; If not 0 yet, bail bcf stat1,5 ; It's zero so clear request and bail goto tmr1b tmr1l incf irctrl,1 ; Increment the IR interval counter lower byte btfss STATUS,Z ; Test if low IR counter didn't roll over to zero goto tmr1b ; If not, just clear interrupt and return incf irctrh,1 ; If rolled over, increment the IR counter high byte btfss STATUS,Z ; Test if high byte is rolling over goto tmr1b ; If not, just clear interrupt and return movlw 0xFF ; But if rolling over, don't want to do that movwf irctrl ; So load both bytes with FF to show as high movwf irctrh ; Gets stuck high until RB interrupt clears it, so never rolls over to low (00) number tmr1b bcf PIR1,TMR1IF ; Clear Timer1 Interrupt Flag ; ***** USART Receive Interrupt service routine ***** rsrcv btfss PIR1,RCIF ; Test if USART Receive Interrupt Flag set (bit 5) goto pbint ; If not, go to next interrupt check ;movf RCREG,w ; Get byte from internal RS232 Receiver byte ;movwf RCV_REG ; And store it in ascii receiver byte ;bsf stat1,4 ; Set ascii character received bit ;bcf PORTA,REDLED ; Turn on red LED ;bcf PIR1,RCIF ; Clear USART Receive Interrupt Flag ; Not using Interrupt so skip over clearing or worrying about ; ***** PORT B Interrupt service routine ***** pbint btfss INTCON,RBIF ; Test if PORTB Transition Interrupt Flag set (bit ) goto rstx ; If not, go to next interrupt check btfsc PORTA,O_L ; Check if switch set for Learn(0) or Operate(1) goto rbO ; Was rstx ; If switch is in OPERATE, don't do a thing btfss PORTB,IRIN ; Test if transition was on falling edge goto rbO ; If falling edge, then ignore, go to save value of PORTB and clear interrupt btfsc stat1,7 ; for lock bit - Check if "LOCK" bit is set goto rbO ; If yes, ignore input and just clear and exit rbA btfsc stat1,0 ; Test if start bit set goto rbF ; If yes, go to test for 1/0/end rbB movf irctrh,f ; Test of irctrh is 00 - TEST HIGH BYTE btfss STATUS,Z ; Test if result is 0 goto rbC ; Not 0, so continue to check if 01, 02, 03 or more movlw 0x9B ; Else, high byte zero, so see what's in low byte - Load w with 9B h (inverse of 64h = 5mS) addwf irctrl,w ; Add w with value in irctrl. If higher, i.e. more than 5mS, then negative on STATUS,C = 0 btfss STATUS,C ; If number is too small, C will be 0 goto rbN ; Number was less than 5mS, Clear and bail rbC movf irctrh,f ; Check if anything in counter high byte btfss STATUS,Z ; goto rbE ; Something in high byte, so definately more than 8mS movlw 0x5F ; Now we know that high counter is 0, so let's see if more than 8mS in low byte addwf irctrl,w ; Start with 5F (inverse of A0 = 8mS) and add value btfss STATUS,C goto rbN ; If less than 8mS, then bail rbE bsf stat1,0 ; Set start bit found clrf CLENGTH ; Clear the counter byte movlw IRDATA ; 0x20 - Start with beginning of data storage area movwf FSR ; Load it into the register pointer goto rbN rbF movf irctrh,f ; Test if irctrh is 00 btfss STATUS,Z ; If loaded and not zero, to continue to check goto rbL ; But, if anything in high byte, it's more than 12.5mS so do final check movlw 0xEE ; Load w with EE (inverse of 11h) (850us) addwf irctrl,w ; Add with lower (17x50us = 850us) from current counter value in W btfss STATUS,C ; If number is too small, C will be 0 goto rbD ; If less than 850uS, too small for anything, clear start bit and restart rbG movlw 0xE3 ; Load w with E3 (inverse of 1Ch (1400us) addwf irctrl,w ; Subtract 1Ch (28d) (28x50us = 1400us) from current counter value in W btfss STATUS,C ; If number is too small, C will be 0 goto rbH ; If less than 1400uS, then it's a 0, go to store it rbI movlw 0xD7 ; Load w with D7 (inverse of 28h (2000us) addwf irctrl,w ; Subtract 28h (40d) (40x50us = 2000us = 2mS) from current counter value in W btfss STATUS,C ; If number is too small, C will be 0 goto rbJ ; If less than 2000uS, then it's a 1, go to store it rbK movf irctrh,f ; Check if more than 8 mS. Load high counter and if anything there, it's greater btfss STATUS,Z ; If loaded and NOT zero... goto rbL ; ...it's more than 10mS, so go check if it's less than 30mS movlw 0x5F ; High byte zero, so see what's in low byte - Load w with 5F h (inverse of A0h = 8mS) addwf irctrl,w ; Add w with value in irctrl. If higher, i.e. more than 8mS then negative on STATUS,C = 0 btfss STATUS,C ; If number is too small, C will be 0 goto rbD ;WAS rbM ; Number was smaller than 8mS so might be an error. Go to clear all. goto rbL ; Number was at least 8mS so consider it the end of scan. rbH ; Store a 0 movlw 0xE0 ; Check if already 32 bytes stored addwf CLENGTH,w ; Add inverse of 20h btfsc STATUS,Z ; Check if zero, meaning it's 20 already goto rbN ; Already 20 (32 bytes stored), don't store any more clrf INDF ; Store "0" in the current pointed register incf FSR,1 ; Point to next location incf CLENGTH,1 ; Increment the character pointer goto rbN rbJ ; Store a 1 movlw 0xE0 ; Check if already 32 bytes stored addwf CLENGTH,w ; Add inverse of 20h btfsc STATUS,Z ; Check if zero, meaning it's 20 already goto rbN ; Already 20 (32 bytes stored), don't store any more movlw 0x01 ; Store "1" in the current pointed location movwf INDF incf FSR,1 ; Point to next location incf CLENGTH,1 ; Increment the character pointer goto rbN rbL ; Done, store command movlw 0xFA ; Check to see if at least 5 bits were stored addwf CLENGTH,w btfss STATUS,C goto rbD ; If less than 5 bits stored, it's noise, so clear all and bail bcf stat1,0 ; ELSE GOOD/DONE! Then: Clear the start bit bsf stat1,1 ; Set send message bit bcf PORTA,GRNLED ; Turn on green LED bsf stat1,7 ; Set "output string" bit goto rbN rbD bcf stat1,0 ; Clear start bit found bsf PORTA,GRNLED ; Turn off the green LED clrf CLENGTH rbM ; Error condition here. Final measure was less than 8mS. Clear all previously stored bits, pointer, the start bit, and then: rbN clrf irctrl ; Clear counters clrf irctrh rbO movf PORTB,f ; Acts to save changed transitions on PORTB and stop double interrupts bcf INTCON,RBIF ; Clear PORTB Transition Interrupt Flag set ; ***** USART Transmit Interrupt service routine ***** rstx btfss PIR1,TXIF ; Test if USART Transmit Interrupt Flag set (bit 4) goto tmr0 ; If not, go to next interrupt check ;bcf PIR1,TXIF ; Clear the interrupt flag ; Not using Interrupt so skip over clearing or worrying about ; ***** Timer 0 interrupt service routine ***** tmr0 btfss INTCON,T0IF ; Test if Timer0 has Overflowed (bit ) goto othint ; If not, go to next interrupt check bcf INTCON,T0IF ; Clear the interrupt flag ; ***** All other Interrupts ***** othint btfsc PIR1,7 ; Test for EEPROM written Interrupt Flag bcf PIR1,7 btfsc PIR1,6 ; Test for Comparitor Interrupt Flag bcf PIR1,6 btfsc PIR1,2 ; Test for Capture 1 Interrupt FLag bcf PIR1,2 ; ***** Timer 2 interrupt service routine ***** btfss PIR1,1 ; Test for Timer 2 Match Interrupt FLag goto othint2 btfss PORTA,O_L ; Test if set for operate(1) of learn(0) goto othint2 ; If learn (0) then skip btfss stat1,3 ; PORTA,MODSW ; Test if set for modulation(0) goto tmr2a ; If not set for modulation, just clear and return btfss stat1,2 ; Check if current bit being transferred is a 1 goto tmr2a ; If not, skip and just output 0. Otherwise, is 1, then: movlw 0x09 ; Toggle IR on state @ 40kHz (39.01kHz) (on PORTB,0 and PORTB,3) xorwf PORTB,1 tmr2a bcf PIR1,TMR2IF ; Clear Timer2 Interrupt flag othint2 btfsc INTCON,T0IF ; Test for Timer0 Interrupt Flag bcf INTCON,T0IF btfsc INTCON,INTF ; Test for External Interrup Flag bcf INTCON,INTF iend movf stemp,w ; Retrieve copy of STATUS register movwf STATUS ; Restore pre-isr STATUS register contents swapf wtemp,f swapf wtemp,w ; Restore pre-isr W register contents retfie ;**************************************************************************** ;**************************************************************************** ;************************************ Tables ********************************* ;**************************************************************************** ;**************************************************************************** org 0390h msg1 addwf PCL,F ;,1 retlw 'R' ; "Ready" 00,07 retlw 'e' retlw 'a' retlw 'd' retlw 'y' msgx retlw 0x0D ; Carriage return retlw 0x0A ; Line feed msg2 retlw A'R' ; "Ready to save, pick a character: " 07,22 retlw A'e' retlw A'a' retlw A'd' retlw A'y' retlw A' ' retlw A't' retlw A'o' retlw A' ' retlw A's' retlw A'a' retlw A'v' retlw A'e' retlw A',' retlw A' ' retlw A'p' retlw A'i' retlw A'c' retlw A'k' retlw A' ' retlw A'a' retlw A' ' retlw A'c' retlw A'h' retlw A'a' retlw A'r' retlw A'a' retlw A'c' retlw A't' retlw A'e' retlw A'r' retlw A':' retlw A' ' msg3 retlw 0x0D ; Carriage return ; "Already used. Overwrite? Y/N?" 29,1C retlw 0x0A ; Line feed retlw A'A' retlw A'l' retlw A'r' retlw A'e' retlw A'a' retlw A'd' retlw A'y' retlw A' ' retlw A'u' retlw A's' retlw A'e' retlw A'd' retlw A'.' retlw A' ' retlw A'O' retlw A'v' retlw A'e' retlw A'r' retlw A'w' retlw A'r' retlw A'i' retlw A't' retlw A'e' retlw A'?' retlw A' ' retlw A'Y' retlw A'/' retlw A'N' retlw A'?' retlw A' ' msg4 retlw 0x0D ; "Erase all E2? Y/N?" 43,12 (Carriage return first) retlw 0x0A ; Line feed retlw A'E' retlw A'r' retlw A'a' retlw A's' retlw A'e' retlw A' ' retlw A'a' retlw A'l' retlw A'l' retlw A' ' retlw A'E' retlw A'2' retlw A'?' retlw A' ' retlw A'Y' retlw A'/' retlw A'N' retlw A'?' retlw A' ' msg5 retlw 0x0D ; "Abort" 5B,09 - Carriage return retlw 0x0A ; Line feed retlw A'A' retlw A'b' retlw A'o' retlw A'r' retlw A't' msg6 retlw 0x0D ; "OK" 62,06 Carriage return retlw 0x0A ; Line feed retlw A'O' retlw A'K' retlw 0x0D ; Carriage return retlw 0x0A ; Line feed ;--------------------------------------------------------------------------------------------------- END