Using a PIC with I2C hardware, while there will still need to be some stuff done it software, is far easier than trying to bit bang I2C.
On a PIC with I2C hardware, you will need to create functions that send the start bits, ack/nack bits, and stop bits. On the I2C hardware is a control register with control bits that send these bits. If using a 16F887, this register is SSPCON2. If coding in C with the XC8 compiler, the code for sending the start bit would look something like this -
Code:
void i2cStartBit(void)
{
SSPCON2bits.SEN = 1; //send start bit
while(SSPCON2bits.SEN); //wait for start bit send to complete
PIR1bits.SSPIF = 0; //clear MSSP interrupt flag
}
You'll need to create similar functions for sending the stop bit, ack bit, nack bit, as well as sending the bytes -
Code:
void i2cStopBit(void)
{
SSPCON2bits.PEN = 1; //send stop bit
while(SSPCON2bits.PEN); //wait for stop bit send to complete
PIR1bits.SSPIF = 0; //clear MSSP interrupt flag
}
void i2cAckNackBit(void)
{
SSPCON2bits.ACKEN = 1; //send ack/nack bit
while(SSPCON2bits.ACKEN); //wait for ack/nack bit send to complete
PIR1bits.SSPIF = 0; //clear MSSP interrupt flag
}
void i2cAckBit(void)
{
SSPCON2bits.ACKDT = 0; //set up for sending ack bit
i2cAckNackBit(); //send ack bit
}
void i2cNackBit(void)
{
SSPCON2bits.ACKDT = 1; //set up for sending nack bit
i2cAckNackBit(); //send nack bit
}
void i2cSend(unsigned char a)
{
SSPBUF = a; //send byte
while(!PIR1bits.SSPIF); //wait for send to complete
PIR1bits.SSPIF = 0; //clear MSSP interrupt flag
}
unsigned char i2cReceive(void)
{
SSPCON2bits.RCEN = 1; //enable I2C receive mode
while(SSPCON2bits.RCEN); //wait for receive to complete
unsigned char a = SSPBUF; //fetch received data from MSSP buffer
PIR1bits.SSPIF = 0; //clear MSSP interrupt flag
return a; //return with received data
}
For some operations you may need to resend the start bit. Here's a function that does that -
Code:
void i2cRestartBit(void)
{
SSPCON2bits.RSEN = 1; //resend start bit
while(SSPCON2bits.RSEN); //wait for resend to complete
PIR1bits.SSPIF = 0; //clear MSSP interrupt flag
}
Then you would need to create functions that use the above functions to communicate with the LCD.
i2cSend
When using i2cSend(), you would place the byte to be sent in the parenthesis. For instance, if you wanted to send the character A, you would do -
i2cReceive
When receiving a byte from the I2C device, you would first declare a variable, then equate it to this function -
Code:
unsigned char rxdata = i2cReceive();
Then the I2C module would receive a byte, then place it in the variable rxdata.
If I knew which LCD you planned to use, I could type out some C code that would get you up and running.