// file: irda.c // vers: 1.1 // // This is a program for the PIC16F84 running on an iRX board -- // see http://www.media.mit.edu/~r/projects/picsem/ for info // on the iRX board in general. // // The program looks for IrDA data recieved over the infrared // port and prints it out as serial data. Similarly, it looks // for serial data received on the RS232 port and transmits it // as IR data. Communication rates are set at 9600 baud. // // NOTE 1: A stock iRX board requires some modifications before // this program can be run. Refer to the section on "Modifying // the iRX board" below for the required modifications. // // NOTE 2: This program is "half duplex": attempts to receive // data on one port (IR or RS232) while transmitting on another // will result in dropped characters. // // REVISION HISTORY // // 1999 Nov 03 - Vers 1.1 - Robert Poor // Eliminated interrupt routine, use INTCON.INTF instead as // the pulse catcher. Added documentation on how to perform // the required modifications to a stock iRX board. // // PROGRAM STRUCTURE // // In main(), the program loops, looking for a start bit either // from the serial input or from the IrDA receiver. If an IrDA // start bit is detected, the program starts reading in IrDA bytes // and storing them in a global buffer, stopping only when the // buffer is full or when the IrDA data stops coming in (as detected // by the absence of a start bit). The accumulated contents of the // global buffer is "printed" to the RS232 serial output. // // The situation is similar if an RS232 start bit is detected: // the program starts reading RS232 bytes over the serial port // and storing the bytes in a buffer, stopping only when the // buffer is full or when the RS232 data stops coming in (as // detected by the absense of a start bit). The accumulated // contents of the global buffer is then transmitted over the // IrDA emitter using "IrDA style" signalling. // // CATCHING AN IR PULSE // // The iRX board receives IR data through a Sharp IS1U20 IRDA // receiver. When the IRDA receiver detects IR, it emits a short // (negative going) pulse, approximately 2 uSec long. It's not // practical to have the PIC monitoring the IR input line continually // looking for such a short pulse, so we use a simple trick to // latch the pulse. But the iRX board must be modified for this // trick: // // IR pulses arrive on RB0, the "external interrupt" pin of the PIC. // (See below for board modifications required to make this so.) // The call to ext_int_edge() in main() configures RB0 so that the // external interrupt flag, INTCON.INTF, will be set whenever an IR // pulse is detected. Thereafter, it's sufficient simply to look at // INTCON.INTF to see if a pulse has been received. However, it's // the responsibility of the code to reset INTON.INTF to zero before // any subsequent pulses are received. // // MODIFYING AN IRX BOARD // // Two modifications are requires to make a "stock" iRX board // run this program. // // 1: Feed the IS1U20 into RB0: you must jumper the PIC RB4 to // PIC RB0. The easiest way is to take a short piece of // wire and connect directly between U3 pin 6 and U3 pin 10. // 2: Add more decoupling for the IR1U20. The IR receiver // is very sensitive to noise on the power supply, so additional // decoupling is needed to prevent false triggers. Immediately // "inboard" of the IR receiver (U4) is a row of V+ and a row // of GND connection points. Solder a 22 uF capacitor *and* a // .1 uF capacitor between V+ and GND right there. (Note to // self: next rev should have a small RC filter in line with the // V+ lead going to the IS1U20.) // #include <16F84.H> #fuses HS,NOWDT,NOPROTECT,PUT #use DELAY(clock=10000000) #use fast_io(A) #use fast_io(B) // Standard definitions for the irx2_1 board // #define RS232_XMIT PIN_B1 // (output) RS232 serial transmit #define RED_LED PIN_B2 // (output) Red LED (low true) #define IR_LED PIN_B3 // (output) Infrared LED (low true) #define IR_SENSOR PIN_B4 // (input) IR sensor (Sharp IS1U30) #define RS232_RCV PIN_B5 // (input) RS232 serial receive // Macros to simplify I/O operations // #define RED_LED_ON output_low(RED_LED) #define RED_LED_OFF output_high(RED_LED) #define IR_LED_ON output_low(IR_LED) #define IR_LED_OFF output_high(IR_LED) #define IR_RECEIVED (!input(IR_SENSOR)) // Default TRIS bits: RS232_RCV and IR_SENSOR are inputs, all // others are outputs // #define IRX_B_TRIS 0b00110000 // =================================================================== // General definitions // struct { short int RBIF; short int INTF; short int T0IF; short int RBIE; short int INTE; short int T0IE; short int PEIE; short int GIE; } INTCON; #byte INTCON = 0x0B // general I/O buffer // #define BUF_SIZE 32 char gBuf[BUF_SIZE]; // =================================================================== // IRDA constants // // Port B0 is also an input (jumpered from IR_RECEIVE port) #define IRDA_TRIS (IRX_B_TRIS | 0b00000001) // Minimum IRDA pulse is 1.63 uSec. With 400 nSec instruction // cycle time (10MHz clock), this requires 4+ cycles, ergo 5. // #define IRDA_PULSE_CYCLES 5 // The following assume an RTCC prescaler of 4:1, or 1600 nSec tics // #define IRDA_BIT_TICS 65 // 1/9600 baud #define IRDA_STARTBIT_TICS 98 // 1.5 * 1/9600 baud #define IRDA_TIMEOUT_TICS 255 // =================================================================== // IR Output // // Wait until the *previous* bit period has expired, then // write a single bit using IrDA 1.0 protocol: a 1.63 uSec // pulse for a zero bit, no pulse for a one bit. // // Reads low order bit in b // void putIRDABit(int b) { do {} while (!INTCON.T0IF); // wait for TMR0 to expire set_rtcc(256-IRDA_BIT_TICS); // reset for next bit period INTCON.T0IF = 0; output_high(PIN_A2); // for 'scope testing if (!(b&1)) { // pulse for 0 bit, no pulse for 1 IR_LED_ON; delay_cycles(IRDA_PULSE_CYCLES-1); IR_LED_OFF; } output_low(PIN_A2); // for 'scope testing } // write a start bit, 8 bits of b (LSB first), and a stop // bit using IrDA 1.0 protocol. // void putIRDAByte(char b) { output_high(PIN_A1); putIRDABit(0); // start bit putIRDABit(b); // b0: lsb first b >>= 1; putIRDABit(b); // b1 b >>= 1; putIRDABit(b); // b2 b >>= 1; putIRDABit(b); // b3 b >>= 1; putIRDABit(b); // b4 b >>= 1; putIRDABit(b); // b5 b >>= 1; putIRDABit(b); // b6 b >>= 1; putIRDABit(b); // b7: msb putIRDABit(1); // stop bit output_low(PIN_A1); } // Send all the chars in Buf[] via IrDA // void putIRDABuf(int count) { int i; INTCON.T0IF = 1; // makes putIRBit() start immediately for (i=0; i