My most beloved topic - the PCF8574 with a HD44780

Hi,
After playing arround with some codes i found on the net (unfortunately non directly aimed at arduino or the wire library) i decided to put together a sketch to test arround some code and finally make some library of it.
Well.. the current state is... i can connect the LCD to the chip and i see a blinking cursor - yet i cant send any text messages onto it.. also it seemed that, no matter what i do, the cursor is always blinking, so i cannot really estimate if i am doing anything right at all...

is there someone who might help me with that code?

#define LCD_LINES                  4      /**< Enter the number of lines of your display here */
#define LCD_ROWS                  20      /**< Enter the number of rows of your display here */

#define LCD_LINE1                  0x00      /**< This should be 0x00 on all displays */
#define LCD_LINE2                  0x40      /**< Change this to the address for line 2 on your display */
#define LCD_LINE3                  0x10      /**< Change this to the address for line 3 on your display */
#define LCD_LINE4                  0x50      /**< Change this to the address for line 4 on your display */

#define LCD_D4_PIN                  0      /**< LCD-Pin D4 is connected to P0 on the PCF8574 */
#define LCD_D5_PIN                  1      /**< LCD-Pin D5 is connected to P1 on the PCF8574 */
#define LCD_D6_PIN                  2      /**< LCD-Pin D6 is connected to P2 on the PCF8574 */
#define LCD_D7_PIN                  3      /**< LCD-Pin D7 is connected to P3 on the PCF8574 */
#define LCD_RS_PIN                  4      /**< LCD-Pin RS is connected to P4 on the PCF8574 */
#define LCD_RW_PIN                  5      /**< LCD-Pin RW is connected to P5 on the PCF8574 */
#define LCD_EMPTY_PIN                  6      /**< this pin is not connected */
#define LCD_E_PIN                  7      /**< LCD-Pin E  is connected to P7 on the PCF8574 */

#define LCD_D0                        (1 << LCD_D4_PIN)      /**< bit 0 in 1st lower nibble */
#define LCD_D1                        (1 << LCD_D5_PIN)      /**< bit 1 in 1st lower nibble */
#define LCD_D2                        (1 << LCD_D6_PIN)      /**< bit 2 in 1st lower nibble */
#define LCD_D3                        (1 << LCD_D7_PIN)      /**< bit 3 in 1st lower nibble */

#define LCD_D4                        (1 << LCD_D4_PIN)      /**< bit 4 in 2nd lower nibble */
#define LCD_D5                        (1 << LCD_D5_PIN)      /**< bit 5 in 2nd lower nibble */
#define LCD_D6                        (1 << LCD_D6_PIN)      /**< bit 6 in 2nd lower nibble */
#define LCD_D7                        (1 << LCD_D7_PIN)      /**< bit 7 in 2nd lower nibble */

#define LCD_RS                        (1 << LCD_RS_PIN)      /**< RS-bit in 1st and 2nd higher nibble */
#define LCD_RW                        (1 << LCD_RW_PIN)      /**< RW-bit in 1st and 2nd higher nibble */
#define LCD_EMPTY                  (1 << LCD_EMPTY_PIN)      /**< empty-bit in 1st and 2nd higher nibble */
#define LCD_E                        (1 << LCD_E_PIN)      /**< E-bit in 1st and 2nd higher nibble */


#define LCD_ADDRESS                  0      /**< Used for reading the address-counter and busy-flag */
#define LCD_DATA                  1      /**< Used for reading data */


#define LCD_CLEAR                  0x01      /**< Clear screen */
#define LCD_HOME                  0x02      /**< Cursor move to first digit */


#define LCD_ENTRYMODE                  0x04                  /**< Set entrymode */
      #define LCD_INCREASE            LCD_ENTRYMODE | 0x02      /**<      Set cursor move direction -- Increase */
      #define LCD_DECREASE            LCD_ENTRYMODE | 0x00      /**<      Set cursor move direction -- Decrease */
      #define LCD_DISPLAYSHIFTON      LCD_ENTRYMODE | 0x01      /**<      Display is shifted */
      #define LCD_DISPLAYSHIFTOFF      LCD_ENTRYMODE | 0x00      /**<      Display is not shifted */


#define LCD_DISPLAYMODE                  0x08                  /**< Set displaymode */
      #define LCD_DISPLAYON            LCD_DISPLAYMODE | 0x04      /**<      Display on */
      #define LCD_DISPLAYOFF            LCD_DISPLAYMODE | 0x00      /**<      Display off */
      #define LCD_CURSORON            LCD_DISPLAYMODE | 0x02      /**<      Cursor on */
      #define LCD_CURSOROFF            LCD_DISPLAYMODE | 0x00      /**<      Cursor off */
      #define LCD_BLINKINGON            LCD_DISPLAYMODE | 0x01      /**<      Blinking on */
      #define LCD_BLINKINGOFF            LCD_DISPLAYMODE | 0x00      /**<      Blinking off */

#define LCD_SHIFTMODE                  0x10                  /**< Set shiftmode */
      #define LCD_DISPLAYSHIFT      LCD_SHIFTMODE | 0x08      /**<      Display shift */
      #define LCD_CURSORMOVE            LCD_SHIFTMODE | 0x00      /**<      Cursor move */
      #define LCD_RIGHT            LCD_SHIFTMODE | 0x04      /**<      Right shift */
      #define LCD_LEFT            LCD_SHIFTMODE | 0x00      /**<      Left shift */

#define LCD_CONFIGURATION            0x20                        /**< Set function */
      #define LCD_8BIT            LCD_CONFIGURATION | 0x10      /**<      8 bits interface */
      #define LCD_4BIT            LCD_CONFIGURATION | 0x00      /**<      4 bits interface */
      #define LCD_2LINE            LCD_CONFIGURATION | 0x08      /**<      2 line display */
      #define LCD_1LINE            LCD_CONFIGURATION | 0x00      /**<      1 line display */
      #define LCD_5X10            LCD_CONFIGURATION | 0x04      /**<      5 X 10 dots */
      #define LCD_5X7                  LCD_CONFIGURATION | 0x00      /**<      5 X 7 dots */

#define PCFADDRESS                      0x38


#include <WProgram.h>
#include <Wire.h>




void setup()
{
  Serial.begin(9600);
 
  Wire.begin();
  /*Init*/
      delay(15);
      lcd_write(LCD_D5 | LCD_D4);      //-      Set interface to 8-bit
        delay(5);                  //-      Wait for more than 4.1ms
      lcd_write(LCD_D5 | LCD_D4);      //-      Set interface to 8-bit
      delay(101);            //-      Wait for more than 100us      
      lcd_write(LCD_D5 | LCD_D4);      //-      Set interface to 8-bit
      lcd_write(LCD_D5);            //-      Set interface to 4-bit
  
      //- From now on in 4-bit-Mode
      //lcd_command(LCD_4BIT | LCD_2LINE | LCD_5X7);            //-      2-Lines, 5x7-Matrix
      lcd_command(LCD_DISPLAYOFF);                        //-      Display off
      lcd_command(LCD_CLEAR);                              //-      Clear Screen
      lcd_command(LCD_INCREASE | LCD_DISPLAYSHIFTOFF);      //-      Entrymode (Display Shift: off, Increment Address Counter)
      lcd_command(LCD_DISPLAYON);                        //-      Display on  
        lcd_command(LCD_BLINKINGOFF);                           //-     Blinking off
        lcd_command(LCD_CURSORON);
  debug("DISPLAY INIT");




lcd_print("Hello world");
  debug("PRINT");
}

void loop()
{

}

void debug(char * str)
{
    Serial.println(str);
}

//-      Write data to i2c
void lcd_write_i2c(unsigned char value)
{
    Wire.beginTransmission(PCFADDRESS);
    Wire.send(value);
    Wire.endTransmission();  
}

//-      Write byte to display with toggle of enable-bit
void lcd_write(unsigned char value)
{
      lcd_write_i2c(value | LCD_E);            //-      Set enable to high
      lcd_write_i2c(value | LCD_E);            //-      Send data, keep enable high
      lcd_write_i2c(value & (!LCD_E));      //-      Set enable to low
}

//-      Issue a command to the display (use the defined commands above)
void lcd_command(unsigned char command)
{
      unsigned char lcddata;
      lcddata = command;
      lcddata >>=  4;
      lcd_write(lcddata);
      lcddata = command;
      lcddata &= 0x0F;
      lcd_write(lcddata);      
}


//-      Print string to cursor position
void lcd_print( char *string)
{
      unsigned char i = 0;
Serial.print("Debug: ");
      while(string[i] != 0x00)
      {
            lcd_putchar(string[i]);                
                Serial.print(string[i]);

            i++;
      }
debug("");
}

//-      Put char to cursor position
void lcd_putchar(unsigned char value)
{
      unsigned char lcddata;
      lcddata = value;
      lcddata >>= 4;
      lcddata |= LCD_RS;
      lcd_write(lcddata);
      lcddata = value;
      lcddata &= 0x0F;
      lcddata |= LCD_RS;
      lcd_write(lcddata);
        delay(1500);
}

Hi Nachtwind, I have a PCF8574 on order and will start playing with it when it arrives, but I was curious why you chose the code above instead of the code here: Arduino Playground - I2CPortExpanderAndLCDs

Using an existing Arduino supported LCD class makes the code easier to integrate with existing arduino lcd applications. I would think that the LiquidCrystal class would be the best choice although there are lots of apps still using the LCD4bit library.

I didnt use this class as it is aimed at a different port expander (to be honest - i havent tried to use it.. should do that).
In the end i wanted to make the library look muhc like the 4bit lkibrary (same interface) so it could be used as the original one as much as possible, but beforehad i wanted to write a small sketch in order to get it working.

If you want to get it going with the lcd4bit library, I would think it would be easier to start with the playground library I linked. My guess is that you would not need to do much more than change the function void SendToLCD( ) .

Perhaps have a look at the datasheets and see how much difference there is between the tow chips

i was doing this after i read your post.. strangely enough its almost the same chip yet the code doesnt work out of the box.. unfortunately i dont see any big differences.. gonna spent some more time on this..

My guess is that its most likely an addressing issue – double check to make sure you are getting that right. You may want to run some simple tests driving some LEDs before trying to get the LCD displaying text.

With LEDs attached it looks kind of right...

Its always RS and E activated when the 4Bit Data is set.. and if i recall right this is the way to go?

Not sure which 'it' you are referring to, I presume you are testing the code in the playground. One way you can test is to connect LEDs to the 8 extender outputs and send some bit patterns to see if the expected LEDs light up.

You can send test patterns using some simple wire command sequences:

byte deviceAddr = devI2CAddress; // set this to your devices I2C address

Wire.beginTransmission(deviceAddr);
Wire.send(0x0);  // all LEDs off
Wire.endTransmission();
delay(1000);
Wire.beginTransmission(deviceAddr);
Wire.send(0xFF);  // all LEDs on
Wire.endTransmission();
delay(1000);
for(int i=0; i < 256;i++){
   Wire.beginTransmission(deviceAddr);
   Wire.send((byte)i);  // sequence through all binary patterns
   Wire.endTransmission();
   delay(10); 
}

with 'it' i refered to the LEDs flashing structure.. it looked somewhat right to me... this whole thing is driving me nuts!
Also using your code it seems there is no problem...
grumbling this is really frustrating ><

Don't wory, you will get it to work. In der Schule, mein Deutsch Lehrer hat mich gelehrt, dass alle Anfang ist schwer

The problem will be some small thing that you will find if you take it in small steps.

Am I correct in thinking that you are now using the playground code instead of the code posted in the start of this thread?

Also, if you send wire commands to the extender , you can get the correct LEDS to light?

With the LCD connected, you have checked the wiring from the extender to the LCD and its wired exactly as it should be?

The LCD still works if you wire it directly to the Arduino?

your teacher is absolutely right ;0)

Also no.. i am actually using the code used in the first post as it seems to give me the right LED sequence yet it is still not working exactly as supposed. When wired directly to the Arduino the LCD perfectly works - so its not a problem of the LCD...
well, in the end it seems i have to keep trying..

Good luck!

If you get stuck, think about trying to get the playground code to work.

I guess that could be the way to go.. but after reading into the code in the playground i have to admit that i simply dont understand it as good as the one i have here (see post one)... in the end its not that optimised i think - so i can try this first ;0)

I do understand the benefit of first working with the easier to understand code. But bear in mind that the code in post one is an alternative for the Liquid Crystal library and after you have it going, you will need to decide if you want to continue to use this non-standard LCD interface or get something working that has an interface similar to the ones in popular use. The advantage of the playground code is that once you have it going you can ignore the fact that its connected via I2C and use exactly the same sketch code as if it was directly connected.

The playground code is a library so it's a little harder to understand at first. But in essence that code contains each of the functions of the normal LCD4Bit code and replaces calls to digitalWrites with code that calls I2C. So you will see functions like :

void LCDI2C4Bit::init( void );
void print(int value);
void printIn(char value[]);
void clear();

These are the same functions as in the LCD4bit library used for direct connections, but the code calls a SendToLCD function that sends the appropriate data sequence to I2C

You may want to read the library tutorial here : http://www.arduino.cc/en/Hacking/LibraryTutorial. This shows the relationship between normal C functions and the form used in a library that may help.

But there is no wrong way to approach this so take whatever path you feel most comfortable with.

but that is exactly what i have in mind ^^

I just wanted to tackle the whole thing with some easier code and if/when it works i wanted to put the whole stuff into a nice library that has the functions:

void LCDI2C4Bit::init( void );
void print(int value);
void printIn(char value[]);
void clear();

as well as some few others, but basically that you can just swap the #include statements and add somewhere the address for the pcf8574 ;0)

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

I can post it here if you like! :wink:

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 :wink:
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)

I agree, I was just teasing :wink: