Well, here's one old project of mine that I brushed up a bit ...
Licence: Do whatch ya want with it just don't bug me about it, if you credit me for work, great, if you don't want to that's not a problem also, if you get rich from it send me a beer :D
What: it is a 16F690 pic driving a 2x16 LCD .. nothing too smart .. it acts like i2c slave with address 0xB0 but you can select any other address in the source. You talk to it using standard i2c by reading and writing to its registers. Registers 0-15 represent 16 characters in the first row, registers 16-31 represent characters in the second row. Other registers (up to 72 iirc) are not used attm.
Why: I hate how many pins the lcd takes, especially when I'm using powerful mcu's with low pin count .. that's why while back I decided to whenever possible use i2c bus for all the io (lcd, buttons, leds etc etc)
Improvements: There's bunch of unused ram on the pic so bunch of unused registers that you can use for temporary storage or you can add some code to the 16F690 to use unused pins as inputs or outputs so you can set/read data from those pins via unused registers. The pic also have hardware uart that could be also used as interface to display data and there's also the SPI there...
Example:
this is the sample code that runs on the master mcu sending data to this controller:
void i2c_putc(unsigned char c){
unsigned char static position = 0;
if (c == 'f'){ // f will clear screen
I2C_Start();
I2C_Wr(0xB0);
I2C_Wr(32);
I2C_Wr('x');
I2C_Stop();
position=0;
} else if (c=='n'){ //move position to beginning of the second line
position=16;
} else {
I2C_Start();
I2C_Wr(0xB0);
I2C_Wr(position++);
I2C_Wr(c);
I2C_Stop();
if (position > 31) position=0;
}
}
void i2c_print(char *c){
unsigned char i;
i=0;
while (c[i]){
i2c_putc(c[i]);
i++;
}
}
char x[] = "fHello World!nsecond line";
void main(){
Delay_ms(200); //wait for the i2c slaves to come online
I2C_Init(100000); //"fast" i2c initialisation
i2c_print(x);
}