Go Down

Topic: My most beloved topic - the PCF8574 with a HD44780 (Read 6726 times) previous topic - next topic


Hi! I have a modified LCDI2C4Bit that runs very well with PCF8574 and HD44780

I can post it here if you like!  ;)


that'd be just awesome, why invent the wheel a second time? ;0)


Nachtwind, I half expected to hear you say that you would prefer to try to do it yourself for the learning experience ;)
It would be good to see what angelito has done. Perhaps I can convince him to do a version for the LiquidCrystal library to save me doing it


well... i am fiddeling with that code for more than a week now.. and somehow its nothing hard at all, so i guess that i can learn more from watching how a working version was done than to keep trying to figure out what i have done wrong..
I guess t is something quite simple, my bet is on the Nibble stuff, yet i cant figure it out and so.. well, i would like to see how it is done ;0)



Hi! Here it's the code, I modified original library from http://www.arduino.cc/playground/Code/I2CPortExpanderAndLCDs to code it and added some methods to manage scroll and cursor settings.

It's only tested with 2x16 LCD and will be need to rewrite cursorTo() method for different size LCD, the original method don't runs with PCF8574, it never go to second line so I have to rewrite it completely, but I don't have different LCD to try it. You can find visible DDRAM addresses for diferent LCD in http://home.iae.nl/users/pouweha/lcd/lcd0.shtml#visible_ddram

The rest of the code is almost the same (diferences are commented to locate it easily), the wiring it's the same that you can find in the original lib example.

Hope it helps

If I got time tonight I will look your lib code

Code: [Select]

#ifndef LCDI2C4Bit_h
#define LCDI2C4Bit_h

#include <inttypes.h>

// IMPORTANT! Wire. must have a begin() before calling init()

*  Modified 21-Feb-2009 for use with PCF8574
*  Angel Sancho <angelitodeb@gmail.com>
*  Original source from:
*  http://www.arduino.cc/playground/Code/I2CPortExpanderAndLCDs

class LCDI2C4Bit {
 LCDI2C4Bit(int devI2CAddress, int num_lines, int lcdwidth);
 void commandWrite(int command);
 void init();
 void print(int value);
 void printIn(char value[]);
 void clear();
 void backLight( bool turnOn );

 // New methods to manage cursor settings and scroll with PCF8574
 void setInvisibleCursor();
 void setVisibleCursor();
 void setBlinkingCursor();
 void scrollRight();
 void scrollLeft();

 void cursorTo(int line_num, int x);
 //void leftScroll(int chars, int delay_time);
 //end of non-core--------

 //4bit only, therefore ideally private but may be needed by user
 //void commandWriteNibble(int nibble);

 //void pulseEnablePin();
 //void pushNibble(int nibble);
 //void pushByte(int value);

 int myNumLines;
 int myWidth;
 int myAddress;


Code: [Select]

*  Modified 21-Feb-2009 for use with PCF8574
*  Angel Sancho <angelitodeb@gmail.com>
*  Original source from:
*  http://www.arduino.cc/playground/Code/I2CPortExpanderAndLCDs

#include "LCDI2C4Bit.h"
#include <Wire.h>

extern "C" {
 #include <stdio.h>  //not needed yet
 #include <string.h> //needed for strlen()
 #include <inttypes.h>
 #include "WConstants.h"  //all things wiring / arduino

//command bytes for LCD
#define CMD_CLR 0x01
#define CMD_RIGHT 0x1C
#define CMD_LEFT 0x18
#define CMD_HOME 0x02
#define CMD_CURSOR_RIGHT 0x14

//stuff the library user might call---------------------------------

//constructor.  num_lines must be 1 or 2, currently.

byte dataPlusMask = 0; // TODO!!!

LCDI2C4Bit::LCDI2C4Bit( int devI2CAddress, int num_lines, int lcdwidth) {
 myNumLines = num_lines;
 myWidth = lcdwidth;
 myAddress = devI2CAddress;

void SetMCPReg( byte deviceAddr, byte reg, byte val ) {
 //Wire.send(reg);  // not need this for PCF8574

void SendToLCD( byte deviceAddr, byte data ) {
 data |= dataPlusMask;
 data ^= 0x80; // E
 data ^= 0x80; // E


void WriteLCDByte( byte deviceAddr, byte bdata ) {
 SendToLCD(deviceAddr,bdata >> 4);
 SendToLCD(deviceAddr,bdata & 0x0F);

void LCDI2C4Bit::init( void ) {
 dataPlusMask = 0; // initial: 0
 //SetMCPReg(myAddress,0x05,0x0C); // set CONFREG (0x05) to 0   // not need this for PCF8574
 //SetMCPReg(myAddress,0x00,0x00); // set IOREG (0x00) to 0   // not need this for PCF8574
 //delay(50);      // not need this for PCF8574
 WriteLCDByte(myAddress,0x0C); // turn on, cursor off, no blinking
 WriteLCDByte(myAddress,0x01); // clear display

void LCDI2C4Bit::backLight( bool turnOn ) {
 dataPlusMask |= 0x40; // Lights mask
 if (!turnOn) dataPlusMask ^= 0x40;

void LCDI2C4Bit::print( int value ) {
 dataPlusMask |= 0x10; // RS
 dataPlusMask ^= 0x10; // RS

void LCDI2C4Bit::printIn( char value[] ) {
 for ( char *p = value; *p != 0; p++ )

void LCDI2C4Bit::clear() {

//  Completely modified for PCF8574
//  Original method not runs correctly with this IC and was impossible to put
//  cursor on second line. With this new method you can put it anywhere and
//  quickly than the other, because it only write once to PCF8574. Although it
//  is only tested with 2x16 LCD and will be need to change it for different
//  size LCD. Here you can find visible DDRAMM addresses for different LCD:
//  http://home.iae.nl/users/pouweha/lcd/lcd0.shtml#visible_ddram
void LCDI2C4Bit::cursorTo(int line_num, int x) {
 int targetPos;

 targetPos = x + ((line_num-1) * (myWidth-1));

 if(targetPos > (myWidth-1)) {
    commandWrite( 0xC0 + (targetPos-myWidth) );  // 0xC0 = start of second line in 2x16 LCD
 } else {
    commandWrite( 0x80 + targetPos );  // 0x80 = start of first line in 2x16 LCD

void LCDI2C4Bit::commandWrite( int command ) {
 // RS - leave low

//  ++
//  New methods to manage cursor settings and scroll for PCF8574
void LCDI2C4Bit::setInvisibleCursor() {

void LCDI2C4Bit::setVisibleCursor() {

void LCDI2C4Bit::setBlinkingCursor() {

void LCDI2C4Bit::scrollRight() {

void LCDI2C4Bit::scrollLeft() {
//  --


Thank you for that code, it looks much like what i had in mind with mine, especially the part in it that works - that was one of my main goals in imy design ;0)
Anyway, would you mind if i try to change it a bit to add 4x20 support to it and repost it in here?


Feb 26, 2009, 12:05 am Last Edit: Feb 26, 2009, 12:07 am by angelito Reason: 1
Feel free to change it what you want! I modified it from original LCDI2C4bit and this one came from LCD4bit.. and I think it is GPL (I hope it  ::)) and improving libraries is good for all of us that use arduino


mem, I didn't look on LiquidCrystal library until I read it on your post. I used LCD4bit some months ago and the past week I need it again and directly search for an I2C interface for it and found LCDI2C4bit

I have been viewing LiquidCrystal and definetely it is much "finished" than the others, thanks a lot!


*unintended push*

Hm, is there any documentation about connecting the HD44780 to the I2C expander somewhere? I tried following the original libraries wiki entry, but to no success... i know that lib works, but i seem unable to reproduce this ><


thanks for the code Angelito,
only one question: the pin assignments for pcf8574 is equal to the original (MCP23008)?

;Connect the following pins from MCP23008 to LCD
;P0 - D4
;P1 - D5
;P2 - D6
;P3 - D7
;P4 - RS
;P5 - RW (not used, set to 0 to ground for write)
;P6 - Bl (backlight switch)
;P7 - E


Mar 23, 2010, 11:08 pm Last Edit: Mar 23, 2010, 11:08 pm by Mario_H Reason: 1

Perhaps this can be of help.




thanks Mario

I use your lib, works fine with my lcd modules



has anyone found that the philips (nxp) and TI versions are NOT compatible??  I cannot get the -a version from both places to work.

the NXP works fine.  uses the -a style addressing (0111xxx).  but the TI chip will not work!  others have reported this but I have not found any answers ;(



replying to my own post ;)

I found the problem.  see this:


THAT solved it.

next time anyone runs into this, try the pullup trick.

Go Up