/* irlink.c */ /* Originally intended for an IR link, this was modified for a 433.9 mhz RF link instead. It doesn't work as well as it should and I intend to completely redo it. This code creates one or two pulses for each transmitted data bit. A single pulse at the start of a Bit interval indicates a ZERO while 2 pulses indicate a ONE bit. This is compatible with the way IR remote control receivers work but wastes lots of bandwidth when used with an RF transmitter. Dale Heatherington Aug. 1999 */ #define p16c71 #define FOSC 8000000 #pragma CLOCK_FREQ 8000000 //For 1200 baud //#define TMR0DIV 256-(FOSC/(4800*16)) Compiler will not do this math //#define TMR0DIV 157 //#define SYNCPOINT TMR0DIV + ((255 - TMR0DIV) / 2) //#define SYNCPOINT 204 //for 2400 baud #define TMR0DIV 210 #ifdef p16c71 char ADCON0@0x08; char ADCON1@0x88; char ADRES@0x09; char GPIO@0x06; char OPTION@0x81; //INTCON bits #define ADIE 6 #define T0IE 5 #define INTE 4 #define RBIE 3 #define T0IF 2 #define INTF 1 #define RBIF 0 #endif #ifdef p12c671 /* Special registors for 16C671 chip */ char GPIO@0x05; char PIR1@0x0c; char PIE1@0x8c; char ADRES@0x1e; char ADCON0@0x1f; char OPTION@0x81; char TRIS@0x85; char ADCON1@0x9f; char PCON@0x8e; char OSCCAL@0x8f; #define PEIE 6 #define T0IE 5 #define INTE 4 #define GPIE 3 #define T0IF 2 #define INTF 1 #define GPIF 0 #endif char work; //char biphase; /* 600 hz manchester data + clock */ char tx_data; char tx_sample; char bits; /* count bits in async char frame */ char tx_clk, rx_clk; char rx_data; char rxtmr; #define DI 3 /* 600 baud RS232 data input on GP3*/ #define IR_IN 2 /* IR input pulses */ #define IR_OUTB 1 /* out to IR LED */ #define IR_OUTA 0 /* out to IR LED (Tie A and B in parallel) */ #define DO 4 /* 600 Baud RS232 data out on GP4 */ //-------------------------------------------------------------- /* Emit 15 cycles of 40khz IR pulse on PORTA bit 1. An external transistor should be used to drive the IR LED at up to 500 MA. PORTA bit 0 goes high to key an AM RF transmitter */ void ir_pulse() { char pcount,work; pcount = 15; work = GPIO; L40KHZ: //Make 15 cycles of 40 KHZ on PORTA bit 1 asm{bsf _work_ir_pulse,0 ; //Raise bit 0 for until were are done bsf _work_ir_pulse,1 ; //Pulse bit 1 at 40 khz movf _work_ir_pulse,w ; movwf _GPIO ; //Pin goes high nop ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; bcf _work_ir_pulse,1 ; nop ; movf _work_ir_pulse,w ; movwf _GPIO ; // pin goes low nop ; nop ; nop ; nop ; nop ; nop ; decfsz _pcount_ir_pulse,f ; goto _L40KHZ bcf _GPIO,0 ;Lower bit 0 (RF off) } return; } //--------------------------------------------------------- /* Timer 0 generates 2400 interrupts/sec */ void interrupt() { char pcount; clear_bit(STATUS,RP0); //BANK 0 if(INTCON & (1 << T0IF)){ //Make sure it's a TMR0 interrupt TMR0 = TMR0DIV; //Restart timer0 clear_bit(INTCON,T0IF); //Reset interrupt flag rx_clk++; switch(rx_clk){ //PORTA,3 high during window for second pulse case 1: // for debuging . case 2: set_bit(PORTA,3); break; case 3: case 4: case 5:clear_bit(PORTA,3); break; } if(rx_clk == 3) { if(rx_data) set_bit(GPIO,DO); else clear_bit(GPIO,DO);//output the rx data bit } if(rx_clk >= 5){ rx_clk = 5; set_bit(GPIO,DO); //Force RX mark (1) if no IR pulses } tx_clk++; tx_clk = tx_clk & 3; //tx_clk rolls over after 4 ticks if(tx_clk & 2) set_bit(PORTB,5); else clear_bit(PORTB,5); if((bits < 10) || (~tx_data & (1 << DI))){ //Only do IR pulses if bit count is 0..10 //or sending zeros switch(tx_clk){ case 2: clear_bit(GPIO,0); tx_data = GPIO; //Sample the tx data bit break; case 1: //ir_pulse(); //Always pulse here set_bit(GPIO,0); break; case 0: clear_bit(GPIO,0); //tx_sample = GPIO; break; case 3: if(tx_data & (1 << DI)) //ir_pulse(); //another pulse if bit = 1 set_bit(GPIO,0); break; } } else clear_bit(GPIO,0); //Finished a 10 bit frame if((tx_clk == 3) && (bits < 11)) bits++; //Count data bits } } //------------------------------------------------------------- main() { char lastbuf,buf; STATUS = 0; INTCON = 0; GPIO = 0; #ifdef p16c71 PORTA = 0; PORTB = 0; #endif TMR0 = 0; set_bit(STATUS,RP0); //BANK 1 #ifdef p12c671 TRIS = 0x0c; //GP2 and GP3 inputs. Others outputs #endif #ifdef p16c71 TRISB = 0x0c; TRISA = 0; #endif OPTION = 0x81; //prescaler to Timer 0 clear_bit(STATUS,RP0); //BANK 0 bits = 11; //Transmiter dormant TMR0 = TMR0DIV; //Start timer 0 clear_bit(INTCON,T0IF); set_bit(INTCON,T0IE); //Enable timer 0 interrupts set_bit(INTCON,GIE); //Enable global interrupts while(1){ set_bit(PORTB,6); buf = GPIO; if(~buf & (1 << DI)){ // DI is space (zero) if(bits >= 9){ clear_bit(INTCON,T0IE); //Disable timer interrupts if((buf ^ lastbuf) & (1 << DI)){ //mark to space transition (1->0) set_bit(PORTB,7); TMR0 = TMR0DIV; //Set up for start of a 10 bit async frame tx_clk = 3; if(bits == 11) tx_data = 0; bits = 0; clear_bit(INTCON,T0IF); clear_bit(PORTB,7); set_bit(INTCON,T0IF); //force an interrupt now } set_bit(INTCON,T0IE); //enable timer interrupts } } if(bits == 11){ // In receive mode //if(~buf & (1<< IR_IN)){ // IR pulse in progress (low true) if(buf & (1<< IR_IN)){ // RF pulse in progress (High true) disable_interrupt(T0IE); if((buf ^ lastbuf) & (1 << IR_IN)) { //OFF to ON IR transition //set_bit(PORTA,3); switch(rx_clk){ //Discover when it happened relative to our clock case 0: break; case 3: case 4: case 5: clear_bit(PORTA,3); rx_clk = 0; TMR0 = TMR0DIV; //Reset prescaler clear_bit(INTCON,T0IF);//make sure tmr int flag is clear if(rx_data) set_bit(PORTA,2); else clear_bit(PORTA,2); rx_data = 0; //assume bit will be zero break; case 1: case 2: set_bit(PORTA,3); rx_data = 0xFF; //Data 1 bit detected break; } //clear_bit(PORTA,3); } enable_interrupt(T0IE); } } lastbuf = buf; //Update difference buffer clear_bit(PORTB,6); nop(); nop(); } } //------------------------------------------------------------ /* End of code */