The PCF8574/PCF8574A series can interface to many parallel port I/O devices such as matrix keypad or even an HD44780 character LCD. Its 8-bit port can control the HD44780-based character LCD using the controller 4-bit data transfer mode without any auxiliary chip. Even the display is a one-line, two-line or 4-line display we can set its DDRAM via LCD command.
In this introductory example I use a popular Arduino PCF8574T character LCD interface module with the ATMega644P TWI to control a 16x2 character LCD.
| A sample picture |
| Running Program on my ATMega644P Experiment Board |
The I2C default address of this module is 0x4E since the A2:A0 pins are pulled high. For the Arduino IDE its TWI address is 0x27. I draw and make my own DIY using the PCF8574AP. Its schematic is shown below.
![]() |
| Schematic Diagram |
However it works the same function except its I2C slave address. For more information about this DIY module please visit this blog.
Source Code: "main.c"
- /*
- * 10-i2c_pcf8574T_1602.c
- *
- * Created: 2/3/2026 11:05:19 AM
- * Author : Admin
- */
- #include <stdio.h>
- #include <avr/io.h>
- #include <util/delay.h>
- #define F_CPU 16000000UL
- /*TWI LCD Driver*/
- #define RS 0
- #define RW 1
- #define EN 2
- #define BL 3
- char backLight=0;
- void i2c_lcdCommand(uint8_t command){
- uint8_t data;
- data=command&0xF0;
- pcf8574Write(data|(backLight<<BL)|(1<<EN));
- //_delay_us(10);
- pcf8574Write(data|(backLight<<BL));
- //_delay_us(50);
- data=command<<4;
- pcf8574Write(data|(backLight<<BL)|(1<<EN));
- //_delay_us(10);
- pcf8574Write(data|(backLight<<BL));
- //_delay_us(50);
- }
- void i2c_lcdData(uint8_t command){
- uint8_t data;
- data=command&0xF0;
- pcf8574Write(data|(backLight<<BL)|(1<<EN)|(1<<RS));
- //_delay_us(10);
- pcf8574Write(data|(backLight<<BL)|(1<<RS));
- _delay_us(50);
- data=command<<4;
- pcf8574Write(data|(backLight<<BL)|(1<<EN)|(1<<RS));
- //_delay_us(10);
- pcf8574Write(data|(backLight<<BL)|(1<<RS));
- //_delay_us(50);
- }
- void i2c_lcdXY(int8_t x, int8_t y){
- int8_t addr[]={0x80,0xC0};
- i2c_lcdCommand(addr[y-1]+x-1);
- }
- void i2c_lcdText(int8_t *txt){
- while(*txt) i2c_lcdData(*txt++);
- }
- void i2c_lcdClear(void){
- i2c_lcdCommand(0x01);
- //_delay_ms(5);
- }
- void i2c_lcdInit(void){
- i2cInit();
- //_delay_us(10);
- pcf8574Write(0);
- //_delay_ms(10);
- i2c_lcdCommand(0x33);
- //_delay_us(10);
- i2c_lcdCommand(0x32);
- //_delay_us(10);
- i2c_lcdCommand(0x28);
- //_delay_us(10);
- i2c_lcdCommand(0x0F);
- //_delay_us(10);
- i2c_lcdCommand(0x01);
- //_delay_ms(5);
- i2c_lcdCommand(0x06);
- //_delay_us(10);
- }
- int main(void)
- {
- /* Replace with your application code */
- _delay_ms(1000);
- backLight=1;
- i2c_lcdInit();
- i2c_lcdText("ATMega644P I2C");
- i2c_lcdXY(1,2);
- i2c_lcdText(" PCF8574AP LCD");
- long counter=0;
- uint8_t msg[10];
- _delay_ms(10000);
- i2c_lcdClear();
- i2c_lcdCommand(0x0C);
- i2c_lcdText("Counter:");
- while (1)
- {
- sprintf(msg,"%u",counter);
- i2c_lcdXY(1,2);
- i2c_lcdText(msg);
- counter++;
- _delay_ms(500);
- }
- }
I putted the pcf8574.c in a a separated file that's needed to copy and add in project source folder. But it's not include in the main C source file.
The "pcf8574.c":
- /*
- * pcf8574.c
- *
- * Created: 2/3/2026 11:06:53 AM
- * Author: Admin
- */
- #include <avr/io.h>
- #include <util/delay.h>
- #define F_CPU 16000000UL
- //DIY PCF8574AP LCD Module (A2:A0=0)
- const char pcf8574_w=0x40;
- const char pcf8574_r=0x41;
- //PCF8574 (A2:A0=0)
- const char pcf8574a_w=0x70;
- const char pcf8574a_r=0x71;
- //DIY Arduino PCF8574T LCD Module
- const char pcf8574T_LCD_W=0x4E;
- const char pcf8574T_LCD_R=0x4F;
- void i2cInit(void){
- TWSR|=0x00; //Prescaler Selection Bit
- TWBR=0xF0; //Baud Rate Generator
- TWCR=(1<<TWEN); //Enable The TWI Module
- PORTC|=(1<<0);
- PORTC|=(1<<1);
- }
- void i2cStart(void){
- TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
- while((TWCR&(1<<TWINT))==0);
- }
- void i2cWrite(unsigned char data){
- TWDR=data;
- TWCR=(1<<TWINT)|(1<<TWEN);
- while((TWCR&(1<<TWINT))==0);
- }
- unsigned char i2cRead(char ACK){
- if(ACK==0)
- TWCR=(1<<TWINT)|(1<<TWEN)|(1<<TWEA);
- else
- TWCR=(1<<TWINT)|(1<<TWEN);
- while((TWCR&(1<<TWINT))==0);
- return TWDR;
- }
- void i2cStop(){
- TWCR=(1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
- _delay_us(10);
- }
- void pcf8574Write(char data){
- i2cStart();
- i2cWrite(pcf8574T_LCD_W);
- i2cWrite(data);
- i2cStop();
- }
- char pcf8574Read(void){
- i2cStart();
- i2cWrite(pcf8574T_LCD_R);
- char temp=i2cRead(1);
- i2cStop();
- return temp;
- }
Schematic:
| Schematic Diagram and Simulation |
| Simulating Program |
ATMega644 Experiment Board:
| ATMega644 Experiment Board |
| ATMega644 Experiment Board |
Now I replace with a TC1604A-01(R) I posses that is a 16x4 character LCD. It almost identical to the previous one's.
| TC1604A-01(R) MODULE OUTLINE DRAWING |
Its display data RAM address is listed below.
Source Code "main.c":
- /*
- * 10-i2c_pcf8574T_1604.c
- *
- * Created: 2/3/2026 3:01:44 PM
- * Author : Admin
- */
- #include <stdio.h>
- #include <avr/io.h>
- #include <util/delay.h>
- #define F_CPU 16000000UL
- /*TWI LCD Driver*/
- #define RS 0
- #define RW 1
- #define EN 2
- #define BL 3
- char backLight=0;
- void i2c_lcdCommand(char command){
- char data;
- data=command&0xF0;
- pcf8574Write(data|(backLight<<BL)|(1<<EN));
- //_delay_us(10);
- pcf8574Write(data|(backLight<<BL));
- //_delay_us(50);
- data=command<<4;
- pcf8574Write(data|(backLight<<BL)|(1<<EN));
- //_delay_us(10);
- pcf8574Write(data|(backLight<<BL));
- //_delay_us(50);
- }
- void i2c_lcdData(char command){
- char data;
- data=command&0xF0;
- pcf8574Write(data|(backLight<<BL)|(1<<EN)|(1<<RS));
- //_delay_us(10);
- pcf8574Write(data|(backLight<<BL)|(1<<RS));
- _delay_us(50);
- data=command<<4;
- pcf8574Write(data|(backLight<<BL)|(1<<EN)|(1<<RS));
- //_delay_us(10);
- pcf8574Write(data|(backLight<<BL)|(1<<RS));
- //_delay_us(50);
- }
- void i2c_lcdXY(int8_t x, int8_t y){
- //16x2
- //char addr[]={0x80,0xC0};
- //16x4
- char addr[]={0x80,0xC0,0x90,0xD0};
- i2c_lcdCommand(addr[y-1]+x-1);
- }
- void i2c_lcdText(int8_t *txt){
- while(*txt) i2c_lcdData(*txt++);
- }
- void i2c_lcdClear(void){
- i2c_lcdCommand(0x01);
- //_delay_ms(5);
- }
- void i2c_lcdInit(void){
- i2cInit();
- //_delay_us(10);
- pcf8574Write(0);
- //_delay_ms(10);
- i2c_lcdCommand(0x33);
- //_delay_us(10);
- i2c_lcdCommand(0x32);
- //_delay_us(10);
- i2c_lcdCommand(0x28);
- //_delay_us(10);
- i2c_lcdCommand(0x0F);
- //_delay_us(10);
- i2c_lcdCommand(0x01);
- //_delay_ms(5);
- i2c_lcdCommand(0x06);
- //_delay_us(10);
- }
- int main(void)
- {
- /* Replace with your application code */
- _delay_ms(1000);
- backLight=1;
- i2c_lcdInit();
- i2c_lcdText("ATMega644P TWI");
- i2c_lcdXY(1,2);
- i2c_lcdText("PCF8574T LCD");
- i2c_lcdXY(1,3);
- i2c_lcdText("TC1604A-01(R)");
- i2c_lcdXY(1,4);
- i2c_lcdText("16x4 Lines LCD");
- while (1)
- {
- }
- }
Schematic:
| Schematic |
ATMega644 Prototype Board:
| PCF8574T TC1604A-01(R) 16x4 LCD |

No comments:
Post a Comment