'**************************************************************** '* Name : IR-Chips.bas * '* Author : Bruce Reynolds http://www.rentron.com * '* Notes : Infrared decoder & encoder IC * '* : For PIC16F62x & A version using 4MHz INTRC * '* modified : Same PIC functions as IR encoder or decoder * '* version : PM assembler. Compile size = 495 words. * '**************************************************************** @ DEVICE MCLR_OFF, INTRC_OSC, WDT_OFF, LVP_OFF, BOD_OFF, PWRT_ON, PROTECT_OFF DEFINE PULSIN_MAX 3000 '// MAX wait time for pulsin DEFINE NO_CLRWDT '// Saves 17 words code space '// RA.6 = MODE select. 1 = decode function. 0 = encode function '// RA.7 = LED drive or IR receive input configured by MODE '// RA.0 = LM Latched = 1, Momentary = 0 (used only in decode mode) '// RA.1 to RA.5 = Hardware address inputs (set same on encoder as decoder) '// For PIC16F62x & A versions CMCON = 7 '// Comparators Off VRCON = 0 '// Vref Off TRISA.6 = 1 '// Set for input. 1 = Decode ; 0 = Encode '// Setup IR bit widths / carrier cycle times Header CON 96 '// Header = (96 * 25uS) = 2.4mS burst Zero CON 24 '// Zero = (24 * 25uS) = 0.6mS burst One CON 48 '// One = (48 * 25uS) = 1.2mS burst '// Define variables LM VAR PORTA.0 '// Latched or Momentary mode select for decode only Cycles VAR BYTE '// Holds number of 40KHz carrier cycles Loops VAR BYTE '// Loop counter Index VAR BYTE '// Index counter IR_PULSE VAR BYTE(13) '// 13-bytes. 8 data ; 5 address PULSE_IN VAR WORD '// Raw pulsin value DBYTE VAR BYTE '// Holds 8-bit data byte ABYTE VAR BYTE '// Holds 5-bit hardware address ABYTE1 VAR BYTE '// 2nd address byte storage for verification DBYTE1 VAR BYTE '// 2nd data byte storage for verification H_Add VAR BYTE '// Holds "Hardware" address X VAR BYTE '// Bit pointer for loop '// Test for encode or decode function & configure I/O PAUSE 10 '// Stabilize on power-up IF PORTA.6 = 1 THEN '// Is Decode MODE selected..? TRISA = $FF '// Yes. PORTA = inputs for 5-bit address & IR input PORTB = 0 '// All outputs = 0 (off) TRISB = 0 '// PORTB all outputs (8-bit data output) OPTION_REG.7 = 1 '// PORTB pull-ups off GOTO Decode '// GOTO Decode routine ENDIF '// Else encode function selected TRISB = $FF '// PORTB = 8-bit switch inputs OPTION_REG.7 = 0 '// PORTB internal pull-ups = on '// IRLED 170 PORTA.7 = 0 '// Transmitter IR LED = off RA.7 ----|>|----/\/\/\---gnd '// Note: RA.7 can drive an NPN transistor for longer range TRISA = %01111111 '// PORTA.7 = output LED drive. Rest inputs for address GOTO Encode '// Mode = Encode, jump over sub to Encode routine Pulse: '// Emits # of 40kHz bursts held in variable Cycles ASM ;// with auto delay between bursts bsf porta, 7 ;// 1uS, LED=on [need 25uS total goto $+1 ;// 3uS (2uS per goto $+1) goto $+1 ;// 5uS goto $+1 ;// 7uS goto $+1 ;// 9uS goto $+1 ;// 11uS goto $+1 ;// 13uS bcf porta, 7 ;// 14uS, LED=off goto $+1 ;// 16uS goto $+1 ;// 18uS goto $+1 ;// 20uS goto $+1 ;// 22uS decfsz _Cycles,F ;// 23uS goto _Pulse ;// 25us ENDASM PAUSEUS 500 '// 500uS delay between each data bit RETURN '// Return to Main '// Send header pulse + 13-bit data/address packet on keypress Send: Cycles = Header '// Load header pulse time CALL Pulse '// Send 2.4mS header/synch pulse '// Header sent, now send 8 data bits FOR Index = 0 TO 7 '// Loop for 8 bits data IF DBYTE.0[Index] = 0 THEN '// Get polarity of each data bit to send Cycles = Zero '// Pulse time = 0.6mS for a "0" data bit ELSE Cycles = One '// Pulse time = 1.2mS for a "1" data bit ENDIF CALL Pulse '// Send Zero or One data bit/burst NEXT Index '// Loop until 8 data-bits sent '// 8 data bits sent, now send 5-bit address '// Shift RA.0 out, RA.1,2,3,4,5=address, mask "zero" upper 3-bits ABYTE = (PORTA >> 1) & %00011111 '// ABYTE = address from RA.1 to RA.5 FOR Index = 0 TO 4 '// Loop for 5-bits to complete address code IF ABYTE.0[Index] = 0 THEN '// Get polarity of each address bit to send Cycles = Zero '// Pulse time = 0.6mS for a "0" address bit ELSE Cycles = One '// Pulse time = 1.2mS for a "1" address bit ENDIF CALL Pulse '// Send bit NEXT Index '// Loop until 5-bits sent PAUSE 25 '// 25mS delay between packets (40kHz bursts) Encode: IF PORTB != $FF THEN '// Loop until key-press DBYTE = PORTB GOTO Send ENDIF GOTO Encode Decode: '// Shift right to remove bit RA.0 H_Add = (PORTA >> 1) & %00011111 '// AND with %00011111 to mask upper 3-bits '// RA.1 to RA.5 = 5-bit hardware address Decode2: PULSIN PORTA.7,0,PULSE_IN '// Read-in start pulse IF (PULSE_IN < 200) OR (PULSE_IN = 0) THEN '// Less than Start pulse, then keep looking Loops = 0 '// Reset Loops on idle or key release IF LM = 1 THEN Decode '// If mode = latching, don't change outputs. PORTB = 0 '// Mode = momentary. Key = released or idle GOTO Decode '// so clear outputs & return. ENDIF Verify: '// Read, Decode, then verify data FOR Index = 0 TO 12 '// Setup to read-in 13 pulses PULSIN PORTA.7,0,IR_PULSE[Index] '// Read 13 low-going pulses on RA.7 NEXT Index '// Loop x times DBYTE = $FF '// Start with all 1's and find each 0 FOR Index = 0 TO 7 '// Get 8 "data" bits IF IR_PULSE[Index] < 100 THEN DBYTE.0[Index]=0 '// Less than 1mS = 0 NEXT Index ABYTE = $FF '// Start with all 1's and find each 0 in pattern X=0 '// Initialize address bit index pointer to bit 0 FOR Index = 8 TO 12 '// Get 5 address bits from IR_PULSE bits 8-12 IF IR_PULSE[Index] < 100 THEN ABYTE.0[X]=0 X = X + 1 '// Increment address bit index pointer NEXT Index ABYTE = ABYTE & %00011111 '// Mask out upper 3-bits. Result = 5-bit address. '// Loops is multi-purpose. '// If Loops = 1, store 1st data & address bytes for comparison on the next '// pass. Loops is cleared on key release or during idle periods, and is used '// in the toggle function to determine if a key was released, an idle period '// occured, or if a key is being held down. If Loops (NOT = 2) on entry to '// Latch, outputs will not be changed. Loops = Loops + 1 '// Increment loop counter IF Loops = 1 THEN '// Record data & address bytes only on 1st pass DBYTE1 = DBYTE '// Load 1st data byte into verify register ABYTE1 = ABYTE '// Load 1st address byte into verify register GOTO Decode2 '// Get 2nd readings for comparison with 1st two ENDIF IF Loops = 255 THEN Loops = 3 '// Prevent roll-overs from 255 to 0 & make sure Loops '// can never be 2 again until the key is released '// or an idle period IF ABYTE != (H_Add & ABYTE1) THEN Decode2 '// Does address match? IF LM = 1 THEN Latch '// Is latch mode selected? '// In momentary mode, any combination of key-presses are '// allowed simultaneously Momentary: PORTB = ~DBYTE '// Momentary mode set so invert & place data on PORTB GOTO Decode2 '// Latch mode requires each key to be released before it will toggle '// the port pin a 2nd time. In Latch mode, only single key-presses '// are allowed. Latch: IF Loops != 2 THEN Decode2 '// Has key been released? IF DBYTE != DBYTE1 THEN Decode2 '// Do both data bytes match? FOR Index = 0 TO 7 '// Yes. Now extract data bits IF DBYTE.0[Index] = 0 THEN PORTB.0[Index] = PORTB.0[Index] ^ 1 '// XOR port bits to toggle port pins ENDIF NEXT Index GOTO Decode2 END