Introduction
In previous post, I use the PCF8574AP DIP-16 chip to expand the output of dsPIC30F2010. Since this chip is an 8-bit bi-directional I/O device, it can be used to connect to any I/O peripheral devices. even an HD44780 character LCD.
![]() |
| Test Program |
A character LCD module comes with a PCF8574T is very popular and low cost. It is commonly an Arduino LCD module widely used among the students and electronic hobbyists. There are a lot of Arduino programming examples for this stuffs.
dsPIC30F2010 Simple I2C LCD using PCF8574T
Controlling an HD44780 character LCD via a PCF8574T is very easy with some additional code to process the 4-bit data transfer mode of the LCD chip controller. In this example, the I2C master micro-controller send some character to a 16x2 character LCD via a PCF8574T chip.
Schematic:
![]() |
| Schematic |
This post show a full I2C devices interfacing examples using an ATMega644P AVR chip.
MikroC Source Code:
- const char PCF8574_W=0x40;
- const char PCF8574_R=0x41;
- const char PCF8574T_LCD_W=0x4E;
- const char PCF8574T_LCD_R=0x4F;
- const char PCF8574A_W=0x70;
- const char PCF8574A_R=0x71;
- void pcf8574_write(char _data){
- I2C1_Start(); // issue I2C start signal
- I2C1_Write(PCF8574T_LCD_W); // send byte via I2C (device address + W)
- I2C1_Write(_data); // send byte (data address)
- I2C1_Stop(); // issue I2C stop signal
- }
- /*TWI LCD Driver*/
- #define RS 0
- #define RW 1
- #define EN 2
- #define BL 3
- #define i2c_lcd_cursor_off() i2c_lcd_command(0x0C)
- #define i2c_lcd_line_1() i2c_lcd_command(0x80)
- #define i2c_lcd_line_2() i2c_lcd_command(0xC0)
- char backLight=1;
- void i2c_lcd_command(char command){
- char _data;
- _data=command&0xF0;
- pcf8574_write(_data|(backLight<<BL)|(1<<EN));
- //_delay_us(10);
- pcf8574_write(_data|(backLight<<BL));
- //_delay_us(50);
- _data=command<<4;
- pcf8574_write(_data|(backLight<<BL)|(1<<EN));
- //_delay_us(10);
- pcf8574_write(_data|(backLight<<BL));
- //_delay_us(50);
- }
- void i2c_lcd__data(char command){
- char _data;
- _data=command&0xF0;
- pcf8574_write(_data|(backLight<<BL)|(1<<EN)|(1<<RS));
- //_delay_us(10);
- pcf8574_write(_data|(backLight<<BL)|(1<<RS));
- Delay_us(50);
- _data=command<<4;
- pcf8574_write(_data|(backLight<<BL)|(1<<EN)|(1<<RS));
- //Delay_us(10);
- pcf8574_write(_data|(backLight<<BL)|(1<<RS));
- //Delay_us(50);
- }
- void i2c_lcd_xy(char x, char y){
- char addr[]={0x80,0xC0};
- i2c_lcd_command(addr[y-1]+x-1);
- }
- void i2c_lcd_text(char *txt){
- while(*txt) i2c_lcd__data(*txt++);
- }
- void i2c_lcd_clear(void){
- i2c_lcd_command(0x01);
- Delay_ms(5);
- }
- void i2c_lcd_init(void){
- pcf8574_write(0);
- Delay_ms(10);
- i2c_lcd_command(0x33);
- Delay_us(10);
- i2c_lcd_command(0x32);
- Delay_us(10);
- i2c_lcd_command(0x28);
- Delay_us(10);
- i2c_lcd_command(0x0F);
- Delay_us(10);
- i2c_lcd_command(0x01);
- Delay_ms(10);
- i2c_lcd_command(0x06);
- Delay_us(10);
- }
- void main(){
- char temp = 0, i = 0;
- I2C1_Init(10000); // initialize I2C communication
- Delay_ms(10);
- i2c_lcd_init();
- Delay_ms(10);
- i2c_lcd_text("dsPIC30F2010 I2C");
- i2c_lcd_line_2();
- i2c_lcd_text("PCF8574T LCD");
- i2c_lcd_cursor_off();
- while(1){
- }
- }
I test this example on my DIY dsPIC30F2010 Prototype Board. It works fine.
![]() |
| My DIY dsPIC30F2010 Prototype Board |
dsPIC30F2010 5V DVM I2C LCD using PCF8574T
There is one on-board POT. So I made a simple 5VDC Digital Volt Meter with this I2C LCD. The schematic remains the same a above.
MikroC Source Code:
- const char PCF8574_W=0x40;
- const char PCF8574_R=0x41;
- const char PCF8574T_LCD_W=0x4E;
- const char PCF8574T_LCD_R=0x4F;
- const char PCF8574A_W=0x70;
- const char PCF8574A_R=0x71;
- void pcf8574_write(char _data){
- I2C1_Start(); // issue I2C start signal
- I2C1_Write(PCF8574T_LCD_W); // send byte via I2C (device address + W)
- I2C1_Write(_data); // send byte (data address)
- I2C1_Stop(); // issue I2C stop signal
- }
- /*TWI LCD Driver*/
- #define RS 0
- #define RW 1
- #define EN 2
- #define BL 3
- #define i2c_lcd_cursor_off() i2c_lcd_command(0x0C)
- #define i2c_lcd_line_1() i2c_lcd_command(0x80)
- #define i2c_lcd_line_2() i2c_lcd_command(0xC0)
- char backLight=1;
- void i2c_lcd_command(char command){
- char _data;
- _data=command&0xF0;
- pcf8574_write(_data|(backLight<<BL)|(1<<EN));
- //_delay_us(10);
- pcf8574_write(_data|(backLight<<BL));
- //_delay_us(50);
- _data=command<<4;
- pcf8574_write(_data|(backLight<<BL)|(1<<EN));
- //_delay_us(10);
- pcf8574_write(_data|(backLight<<BL));
- //_delay_us(50);
- }
- void i2c_lcd__data(char command){
- char _data;
- _data=command&0xF0;
- pcf8574_write(_data|(backLight<<BL)|(1<<EN)|(1<<RS));
- //_delay_us(10);
- pcf8574_write(_data|(backLight<<BL)|(1<<RS));
- Delay_us(50);
- _data=command<<4;
- pcf8574_write(_data|(backLight<<BL)|(1<<EN)|(1<<RS));
- //Delay_us(10);
- pcf8574_write(_data|(backLight<<BL)|(1<<RS));
- //Delay_us(50);
- }
- void i2c_lcd_xy(char x, char y){
- char addr[]={0x80,0xC0};
- i2c_lcd_command(addr[y-1]+x-1);
- }
- void i2c_lcd_text(char *txt){
- while(*txt) i2c_lcd__data(*txt++);
- }
- void i2c_lcd_clear(void){
- i2c_lcd_command(0x01);
- Delay_ms(10);
- }
- void i2c_lcd_init(void){
- pcf8574_write(0);
- Delay_ms(10);
- i2c_lcd_command(0x33);
- Delay_us(10);
- i2c_lcd_command(0x32);
- Delay_us(10);
- i2c_lcd_command(0x28);
- Delay_us(10);
- i2c_lcd_command(0x0F);
- Delay_us(10);
- i2c_lcd_command(0x01);
- Delay_ms(10);
- i2c_lcd_command(0x06);
- Delay_us(10);
- }
- void main(){
- unsigned int adc_rd;
- char text[16];
- long tlong;
- float voltage;
- ADPCFG = 0xFFFF; // Configure AN pins as digital
- I2C1_Init(10000); // initialize I2C communication
- Delay_ms(10);
- i2c_lcd_init();
- Delay_ms(10);
- i2c_lcd_text("dsPIC30F2010 I2C");
- i2c_lcd_line_2();
- i2c_lcd_text("ADC PCF8574T LCD");
- i2c_lcd_cursor_off();
- Delay_ms(10000);
- i2c_lcd_clear();
- while(1){
- adc_rd = ADC1_read(4); // get ADC value from 2nd channel
- voltage = 5.0*adc_rd/1023;
- i2c_lcd_line_1();
- sprintf(text,"AN4 ADC: %4d 10", adc_rd);
- i2c_lcd_text(text);
- i2c_lcd_line_2();
- sprintf(text,"Voltage: %.2f V", voltage);
- i2c_lcd_text(text);
- Delay_ms(500);
- }
- }
Using program C sprintf function is very easy to convert any data type into an array of ASCII characters. But it requires a lot of memory space. For limited ROM and RAM space, we can process the text, character, integer and floating point numbers one-by-one before sending it to UART or LCD stream. This post shows a simple number to ASCII character converting.
Archive:

ADC Read Voltage 0.00 V 
ADC Read Voltage 2.74 V
![]() |
| ADC Read Voltage 5.00 V |
See this short video on Youtube:





No comments:
Post a Comment