//////////////////////////////////////////////////////////////////////////////// // // PIC16F877 + GPIO14 + LCD03 example // Written November 2005 by Gerald Coe, using HITECH PIC16 compiler // // General Purpose I/O using same I2C bus as the LCD03 is using // Note - assumes a 20MHz crystal // // This code is Freeware - Use it for any purpose you like. // /////////////////////////////////////////////////////////////////////////////// #include #include __CONFIG(0x3b32); // configuration register - see PIC data sheet for details #define NO_OP 0x00 // does nothing #define PULLB_ON 0x01 // PORTB pull-ups #define PULLB_OFF 0x02 #define GET_AD0 0x03 // Read A/D channels #define GET_AD1 0x04 #define GET_AD2 0x05 #define GET_AD3 0x06 #define GET_AD4 0x07 #define GET_S4A 0x08 // SRF04 - Trig on RB0, Echo on RB2 #define GET_S4B 0x09 // SRF04 - Trig on RB6, Echo on RB7 #define GET_S5A 0x0A // SRF05 - Trig + Echo on RB6 #define GET_S5B 0x0B // SRF05 - Trig + Echo on RB7 #define SET_US 0x0C // sonar ranging in uS #define SET_CM 0x0D // sonar ranging in cm #define SET_IN 0x0E // sonar ranging in inches #define GPIO_ADDR 0x40 // Factory supplied default I2C address #define CMD 0 // write only - command register #define REVISION 0 // read only - firmware revision #define MASK_A 1 // write only - TRISA reg #define RESULT 1 // read only - result of A/D #define MASK_B 2 // write only - TRISB reg #define AD_CONTROL 3 // read/write - ADCON1 #define PORT_A 4 // read/write #define PORT_B 5 // read/write #define PWM 6 // read/write #define ADDR_CHANGE 7 // write only #define SET_RA0 0x10 // define bit set commands for easier use #define SET_RA1 0x11 #define SET_RA2 0x12 #define SET_RA3 0x13 #define SET_RA4 0x14 #define SET_RA5 0x15 // not available on GPIO14 (Input only) #define SET_RA6 0x16 #define SET_RA7 0x17 #define SET_RB0 0x18 #define SET_RB1 0x19 // not available on GPIO14 (SDA) #define SET_RB2 0x1a #define SET_RB3 0x1b #define SET_RB4 0x1c // not available on GPIO14 (SCL) #define SET_RB5 0x1d #define SET_RB6 0x1e #define SET_RB7 0x1f #define CLR_RA0 0x20 // define bit clear commands for easier use #define CLR_RA1 0x21 #define CLR_RA2 0x22 #define CLR_RA3 0x23 #define CLR_RA4 0x24 #define CLR_RA5 0x25 // not available on GPIO14 (Input only) #define CLR_RA6 0x26 #define CLR_RA7 0x27 #define CLR_RB0 0x28 #define CLR_RB1 0x29 // not available on GPIO14 (SDA) #define CLR_RB2 0x2a #define CLR_RB3 0x2b #define CLR_RB4 0x2c // not available on GPIO14 (SCL) #define CLR_RB5 0x2d #define CLR_RB6 0x2e #define CLR_RB7 0x2f #define TOG_RA0 0x30 // define bit toggle commands for easier use #define TOG_RA1 0x31 #define TOG_RA2 0x32 #define TOG_RA3 0x33 #define TOG_RA4 0x34 #define TOG_RA5 0x35 // not available on GPIO14 (Input only) #define TOG_RA6 0x36 #define TOG_RA7 0x37 #define TOG_RB0 0x38 #define TOG_RB1 0x39 // not available on GPIO14 (SDA) #define TOG_RB2 0x3a #define TOG_RB3 0x3b #define TOG_RB4 0x3c // not available on GPIO14 (SCL) #define TOG_RB5 0x3d #define TOG_RB6 0x3e #define TOG_RB7 0x3f void clrscn(void); // prototypes void cursor(char pos); void print(char *p); void setup(void); char read1_gpio(char reg); int read2_gpio(char reg); void write_gpio(char reg, char data); char s[21]; // buffer used to hold text to print void main(void) { int result1, result2; setup(); // sets up the PIC16F877 I2C port clrscn(); // clears the LCD03 disply cursor(5); // sets cursor to 1st row of LCD03 sprintf(s,"GPIO14 Test "); // text, printed into our buffer print(s); // send it to the LCD03 write_gpio(CMD, PULLB_ON); // turn pull-up resistors on write_gpio(AD_CONTROL, 0x80); // select right justification and all AN0-AN4 as analogue inputs write_gpio(CMD, SET_CM); // set ranging in centimeters while(1) { // loop forever write_gpio(CMD, GET_AD0); result1 = read2_gpio(RESULT); write_gpio(CMD, GET_AD1); result2 = read2_gpio(RESULT); cursor(21); // sets cursor to 2nd row of LCD03 sprintf(s,"An0 =%04d, An1 =%04d", result1, result2); // set text print(s); // send it to the LCD03 write_gpio(CMD, GET_AD2); result1 = read2_gpio(RESULT); result2 = read2_gpio(PORT_A); // reads two bytes - Ports A and B cursor(41); // sets cursor to 4th row of LCD03 sprintf(s,"An2 =%04d, AB = %04X", result1, result2); // set text print(s); // send it to the LCD03 write_gpio(CMD, GET_S5A); // now wait for the ranging to complete. This delay is a little over 100mS TMR1H = 0; // delay while the srf05 is ranging TMR1L = 0; T1CON = 0x31; // 1:4 prescale and running (0.8uS/clk) TMR1IF = 0; while(!TMR1IF); // wait for delay time TMR1ON = 0; // stop timer result1 = read2_gpio(RESULT); write_gpio(CMD, GET_S5B); // now wait for the ranging to complete. This delay is a little over 100mS TMR1H = 0; // delay while the srf05 is ranging TMR1L = 0; T1CON = 0x31; // 1:4 prescale and running (0.8uS/clk) TMR1IF = 0; while(!TMR1IF); // wait for delay time TMR1ON = 0; // stop timer result2 = read2_gpio(RESULT); cursor(61); // sets cursor to 3rd row of LCD03 sprintf(s,"SR1 =%04d, SR2 =%04d", result1, result2); // set text print(s); // send it to the LCD03 } } void write_gpio(char reg, char data) { SEN = 1; // send start bit while(SEN); // and wait for it to clear SSPIF = 0; SSPBUF = GPIO_ADDR; // GPIO I2C address while(!SSPIF); // wait for interrupt SSPIF = 0; // then clear it. SSPBUF = reg; // address of register to write to while(!SSPIF); // SSPIF = 0; // SSPBUF = data; // write the data while(!SSPIF); // SSPIF = 0; // PEN = 1; // send stop bit while(PEN); // } int read2_gpio(char reg) { int data; SEN = 1; // send start bit while(SEN); // and wait for it to clear ACKDT = 0; // acknowledge bit SSPIF = 0; SSPBUF = GPIO_ADDR; // I2C address while(!SSPIF); // wait for interrupt SSPIF = 0; // then clear it. SSPBUF = reg; // address of register to read from while(!SSPIF); // SSPIF = 0; // RSEN = 1; // send repeated start bit while(RSEN); // and wait for it to clear SSPIF = 0; // SSPBUF = GPIO_ADDR+1; // I2C address - the read bit is set this time while(!SSPIF); // wait for interrupt SSPIF = 0; // then clear it. RCEN = 1; // start receiving while(!STAT_BF); // wait for high byte data = SSPBUF<<8; // and get it ACKEN = 1; // start acknowledge sequence while(ACKEN); // wait for ack. sequence to end RCEN = 1; // start receiving while(!STAT_BF); // wait for low byte data += SSPBUF; // and get it ACKDT = 1; // not acknowledge for last byte ACKEN = 1; // start acknowledge sequence while(ACKEN); // wait for ack. sequence to end PEN = 1; // send stop bit while(PEN); // return data; } char read1_gpio(char reg) { char data; SEN = 1; // send start bit while(SEN); // and wait for it to clear ACKDT = 0; // acknowledge bit SSPIF = 0; SSPBUF = GPIO_ADDR; // I2C address while(!SSPIF); // wait for interrupt SSPIF = 0; // then clear it. SSPBUF = reg; // address of register to read from while(!SSPIF); // SSPIF = 0; // RSEN = 1; // send repeated start bit while(RSEN); // and wait for it to clear SSPIF = 0; // SSPBUF = GPIO_ADDR+1; // I2C address - the read bit is set this time while(!SSPIF); // wait for interrupt SSPIF = 0; // then clear it. RCEN = 1; // start receiving while(!STAT_BF); // wait for low byte data += SSPBUF; // and get it ACKDT = 1; // not acknowledge for last byte ACKEN = 1; // start acknowledge sequence while(ACKEN); // wait for ack. sequence to end PEN = 1; // send stop bit while(PEN); // return data; } void clrscn(void) { SEN = 1; // send start bit while(SEN); // and wait for it to clear SSPIF = 0; SSPBUF = 0xc6; // LCD02 I2C address while(!SSPIF); // wait for interrupt SSPIF = 0; // then clear it. SSPBUF = 0; // address of register to write to while(!SSPIF); // SSPIF = 0; // SSPBUF = 12; // clear screen while(!SSPIF); // SSPIF = 0; // SSPBUF = 4; // cursor off while(!SSPIF); // SSPIF = 0; // PEN = 1; // send stop bit while(PEN); // } void cursor(char pos) { SEN = 1; // send start bit while(SEN); // and wait for it to clear SSPIF = 0; SSPBUF = 0xc6; // LCD02 I2C address while(!SSPIF); // wait for interrupt SSPIF = 0; // then clear it. SSPBUF = 0; // address of register to write to while(!SSPIF); // SSPIF = 0; // SSPBUF = 2; // set cursor while(!SSPIF); // SSPIF = 0; // SSPBUF = pos; // while(!SSPIF); // SSPIF = 0; // PEN = 1; // send stop bit while(PEN); // } void print(char *p) { SEN = 1; // send start bit while(SEN); // and wait for it to clear SSPIF = 0; SSPBUF = 0xc6; // LCD02 I2C address while(!SSPIF); // wait for interrupt SSPIF = 0; // then clear it. SSPBUF = 0; // address of register to write to while(!SSPIF); // SSPIF = 0; // while(*p) { SSPBUF = *p++; // write the data while(!SSPIF); // SSPIF = 0; // } PEN = 1; // send stop bit while(PEN); // } void setup(void) { unsigned long x; PORTB = 0xfe; // RB0 (trig) is output TRISB = 0xfe; // and starts low TRISC = 0xff; PORTC = 0xff; SSPSTAT = 0x80; SSPCON = 0x38; SSPCON2 = 0x00; SSPADD = 50; // SCL = 91khz with 20Mhz Osc for(x=0; x<300000L; x++); // wait for LCD03 to initialise }