Driving a 20x4 LCD with I2C - what am I missing?

Hi, first post so please go easy on me :slight_smile:

I'm new to Arduino and I'm trying to drive a 20x4 LCD display with an I2C driver.

I've done quite a lot of reading and been through some excellent posts, but still have a problem and cannot determine whether something is wrong with my screen or if the screen is fine and I'm just driving it wrong.

I'll detail as much as I can hoping it will help find the cause and solution.

First step: identifying the I2C controller version. Following this topic: https://arduino-info.wikispaces.com/LCD-Blue-I2C I reckon it's a "version 3" albeit without the text.

Photo of my actual unit:

Close up of the I2C:

Now in trying to get it working, I ran the address identifier. Strangely enough, this appears to be 0x3f.

Setting 0x3f as the address in the v3 code seems to work: I do get the backlight turning on and off at the start. Any other address doesn't give any backlight control.

However, I don't get any text at all.

With the following code:

/* YourDuino.com Example Software Sketch
 20 character 4 line I2C Display
 Backpack Interface labelled "LCM1602 IIC  A0 A1 A2"
 terry@yourduino.com */

/*-----( Import needed libraries )-----*/
#include <Wire.h>  // Comes with Arduino IDE
// Get the LCD I2C Library here: 
// https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads
// Move any other LCD libraries to another folder or delete them
// See Library "Docs" folder for possible commands etc.
#include <LiquidCrystal_I2C.h>

/*-----( Declare Constants )-----*/
//none
/*-----( Declare objects )-----*/
// set the LCD address to 0x20 for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address


/*-----( Declare Variables )-----*/
//none

void setup()   /*----( SETUP: RUNS ONCE )----*/
{
  Serial.begin(9600);  // Used to type in characters

  lcd.begin(20,4);         // initialize the lcd for 20 chars 4 lines and turn on backlight

// ------- Quick 3 blinks of backlight  -------------
  for(int i = 0; i< 3; i++)
  {
    lcd.backlight();
    delay(250);
    lcd.noBacklight();
    delay(250);
  }
  lcd.backlight(); // finish with backlight on  
  
//-------- Write characters on the display ----------------
// NOTE: Cursor Position: CHAR, LINE) start at 0  
  lcd.setCursor(3,0); //Start at character 4 on line 0
  lcd.print("Hello, world!");
  delay(1000);
  lcd.setCursor(2,1);
  lcd.print("From YourDuino");
  delay(1000);  
  lcd.setCursor(0,2);
  lcd.print("20 by 4 Line Display");
  lcd.setCursor(0,3);
  delay(2000);   
  lcd.print("http://YourDuino.com");
  delay(8000);
// Wait and then tell user they can start the Serial Monitor and type in characters to
// Display. (Set Serial Monitor option to "No Line Ending")
  lcd.setCursor(0,0); //Start at character 0 on line 0
  lcd.print("Start Serial Monitor");
  lcd.setCursor(0,1);
  lcd.print("Type chars 2 display");   


}/*--(end setup )---*/


void loop()   /*----( LOOP: RUNS CONSTANTLY )----*/
{
  {
    // when characters arrive over the serial port...
    if (Serial.available()) {
      // wait a bit for the entire message to arrive
      delay(100);
      // clear the screen
      lcd.clear();
      // read all the available characters
      while (Serial.available() > 0) {
        // display each character to the LCD
        lcd.write(Serial.read());
      }
    }
  }

}/* --(end main loop )-- */


/* ( THE END ) */

I end up with this:

I did try some other code I found and that produced simlilar results, although the second and fourth lines were left completely blank:

I'll carry on researching this, but thought I'd ask here as it seems several people have similar issues with backlight blanking OK but not much more.

Aha, update with success to a certain degree.
The display I've used in the post above is actually the second one I have after the first one I bought off ebay didn't seem to work (the backlight wouldn't turn on).
On the first (with no backlight), it came without a jumper on the LED pins. I tried it first without and nothing.
Then I added a jumper, and still nothing although something must be wrong because it pulls around 0.15A at 5V DC!

Following that, I got in touch with the seller who kindly sent out a second display (the one used in the post above). On that one, the backlight worked but I couldn't get any further.

After reading some more, I came across this neat piece of code: [SOLVED] MJKDZ brand I2C Controller working with 1602 LCD - #12 by bperrybap - Displays - Arduino Forum

I tried that and it would complain that although it found the I2C device at the odd 0x3f address, it would complain withit not being a PCF8574 chip despite having that chip on the back!

<Press <ENTER> or click [Send] to Continue>
Scanning i2c bus for devices..
i2c device found at address 0x3F
Device found: UNKNOWN
Only supports PCF8574
Scanning i2c bus for devices..
i2c device found at address 0x3F
Device found: UNKNOWN
Only supports PCF8574
Scanning i2c bus for devices..
i2c device found at address 0x3F
Device found: UNKNOWN
Only supports PCF8574

and continues looping around.

I then decided to go back to the first (with excessive current draw and non-working backlight), and then it found the device and gave me the correct manufacturer string (0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE):

Scanning i2c bus for devices..
i2c device found at address 0x27
Device found: PCF8574
<Press <ENTER> or click [Send] to start guessing>
Trying: lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE)
<Press <ENTER> or click [Send] to Continue>

So in summary, my first LCD works, but has a broken backlight. My second LCD doesn't appear to work but has a working backlight!

Just try lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE)

The PCF8574 has addresses 0x20 .. 0x27
The PCF8574A has addresses 0x38 .. 0x3F

So 0x3F is perfectly reasonable. There is an updated "guesser" sketch. I would upload this if your sketch is elderly.

I would be a lot happier with the guesser diagnosis. You can always follow the copper traces on each adapter board. Is it the same?

David.

You're right David, I hadn't noticed, but the second board I received does have the newer PCF8574A chip (and the older one has the non-A version as printed on the IC).

However, no luck with that string. I'll look for the updated guesser diagnosis sketch. Maybe it is fine after all and the parameters need to be different.

Hmm. I've found the updated sketch and now it goes through 6 variations but with no success:
lcd(0x3f, 6, 5, 4, 0, 1, 2, 3, 7, NEGATIVE)
lcd(0x3f, 6, 5, 4, 0, 1, 2, 3, 7, POSITIVE)
lcd(0x3f, 4, 5, 6, 0, 1, 2, 3, 7, NEGATIVE)
lcd(0x3f, 4, 5, 6, 0, 1, 2, 3, 7, POSITIVE)
lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, NEGATIVE)
lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE)

They all give me either full blocks on lines 1 and 3 (2nd photo above), full blocks on all four lines or full blocks on 1 and 3 / half blocks on 2 and 4 (1st photo above). Sometimes with backlight, sometimes without.

I'll carry on reading getting a grip of what the values are and maybe find the correct combination. Failing that, I don't know what else to try.

tfboy:
Hmm. I've found the updated sketch and now it goes through 6 variations but with no success:
lcd(0x3f, 6, 5, 4, 0, 1, 2, 3, 7, NEGATIVE)
lcd(0x3f, 6, 5, 4, 0, 1, 2, 3, 7, POSITIVE)
lcd(0x3f, 4, 5, 6, 0, 1, 2, 3, 7, NEGATIVE)
lcd(0x3f, 4, 5, 6, 0, 1, 2, 3, 7, POSITIVE)
lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, NEGATIVE)
lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE)

Can you tell me what issues you found in the sketch so far. I'd like to understand what the issue is so I can update the sketch.

I'd also like to work with you to get the guesser working for this backpack.
It is possible that is not wired like the 6 variations tried. I've not seen other variations out there but it is possible.
Do you have an ohm meter that we can use to ohm out the signals so figure out how it is wired up?

--- bill

I tryed your scech with my librarie on arduino nano but wit same modefications

(__________________________________________________________________________________________

/* YourDuino.com Example Software Sketch
20 character 4 line I2C Display
Backpack Interface labelled "LCM1602 IIC A0 A1 A2"
terry@yourduino.com */

/-----( Import needed libraries )-----/
#include <Wire.h> // Comes with Arduino IDE
// Get the LCD I2C Library here:
// https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads
// Move any other LCD libraries to another folder or delete them
// See Library "Docs" folder for possible commands etc.
#include <LiquidCrystal_I2C.h>

/-----( Declare Constants )-----/
//none
/-----( Declare objects )-----/
// set the LCD address to 0x20 for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
// addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x27 for a 16 chars and 2 line display

/-----( Declare Variables )-----/
//none

void setup() /----( SETUP: RUNS ONCE )----/
{
Serial.begin(9600); // Used to type in characters

lcd.begin(20,4); // initialize the lcd for 20 chars 4 lines and turn on backlight

// ------- Quick 3 blinks of backlight -------------
for(int i = 0; i< 3; i++)
{
lcd.init();
lcd.backlight();
delay(250);
lcd.noBacklight();
delay(250);
}
lcd.backlight(); // finish with backlight on

//-------- Write characters on the display ----------------
// NOTE: Cursor Position: CHAR, LINE) start at 0
lcd.setCursor(3,0); //Start at character 4 on line 0
lcd.print("Hello, world!");
delay(1000);
lcd.setCursor(2,1);
lcd.print("From YourDuino");
delay(1000);
lcd.setCursor(0,2);
lcd.print("20 by 4 Line Display");
lcd.setCursor(0,3);
delay(2000);
lcd.print("http://YourDuino.com");
delay(8000);
// Wait and then tell user they can start the Serial Monitor and type in characters to
// Display. (Set Serial Monitor option to "No Line Ending")
lcd.setCursor(0,0); //Start at character 0 on line 0
lcd.print("Start Serial Monitor");
lcd.setCursor(0,1);
lcd.print("Type chars 2 display");

}/--(end setup )---/

void loop() /----( LOOP: RUNS CONSTANTLY )----/
{
{
// when characters arrive over the serial port...
if (Serial.available()) {
// wait a bit for the entire message to arrive
delay(100);
// clear the screen
lcd.clear();
// read all the available characters
while (Serial.available() > 0) {
// display each character to the LCD
lcd.write(Serial.read());
}
}
}

}/* --(end main loop )-- */

/* ( THE END ) */

bperrybap:
Can you tell me what issues you found in the sketch so far. I'd like to understand what the issue is so I can update the sketch.

I'd also like to work with you to get the guesser working for this backpack.
It is possible that is not wired like the 6 variations tried. I've not seen other variations out there but it is possible.
Do you have an ohm meter that we can use to ohm out the signals so figure out how it is wired up?

--- bill

My questions were about the guesser sketch.
It sounds like you made modifications to it.

I'd focus on why the guesser sketch can't identify the PCF8574.
It is a very simple process. It writes to the chip output port and expects a certain response.
In this case it expects a 0x00
If it doesn't get it and the chip is a 8574 then something is wrong and needs to be corrected.

The sketch you posted above appears to use a different library than the first sketch you posted and appears to be using 0x27 as the address when it looked like the address for that module was 0x3f

I'd stick with fm's library as that is the only one that allows you to configure the 8574 to hd44780 pin mapping and is required by the guesser sketch.

Do you have a ohm meter to trace out the traces on the board, which is best way to determine how the backpack is wired. The guesser is just guessing a limited of combinations and it usually works, but tracing the wires is better and foolproof since it provides the accurate proper mapping formation.

--- bill

Hi Bill,
Not sure whether your post was directed to me or aliumas' one.
The "updated" sketch was your update taken from this thread: http://forum.arduino.cc/index.php?msg=1298575 where it correctly identifies the more recent PCF8574A version which has a default address of 0x3f. With that version, it found my LCD board's address and communicates OK (backlight toggling), but I never see the string appear on the actual LCD, just the three variations of blocks mentioned in my earlier post.

The newer LCD mainboard with the PCF8574A expander IC appears to have the same pinout as all the others:

Going through buzzing the pinout reveals:

PCB pin --Signal-- Pin on SOIC16 Pin on 4-way OK / NOK
Pin 1 Vss 8 Gnd OK
Pin 2 Vdd 16 VCC OK
Pin 3 V0 8 - Gnd Gnd OK
Pin 4 RS 4 - P0 n/c ?
Pin 5 RW 5 - P1 n/c ?
Pin 6 E 6 - P2 n/c ?
Pin 7 D0 n/c n/c ?
Pin 8 D1 n/c n/c ?
Pin 9 D2 n/c n/c ?
Pin 10 D3 n/c n/c ?
Pin 11 D4 9 - P4 n/c OK
Pin 12 D5 10 - P5 n/c OK
Pin 13 D6 11 - P6 n/c OK
Pin 14 D7 12 - P7 n/c OK
Pin 15 A 16 - VDD VCC OK
Pin 16 K OK

Of course the SDA and SCL pins on the 4-way connect to the corresponding pins on the expander IC.

Oh and on the first board with the non working backlight: there's a short between pins 15 and 16 so that'll explain why it's not working!

The rest of the pinout is the same though, so I would have thought that the code that works for my first board should work on the second just by changing the address, but it doesn't

oops sorry, tfboy, I got slightly confused by the response from aliumas147 as I mistakenly thought it was from you.

But you said you were running an "updated" version of the guesser sketch?
I think that there may be some confusion here.
The one you said was the updated sketch is actually older than the other one.
The newer sketches will print out a version number. You should see version 1.4.1
And even though it says "PCF8574" it works on all varieties since they all work the same.

based on the wiring in your table the constructor would be:

  LiquidCrystal_I2C(uint8_t lcd_Addr, uint8_t En, uint8_t Rw, uint8_t Rs, 
                     uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7,
                     uint8_t backlighPin, t_backlighPol pol);

OR

   LiquidCrystal_I2C(0x3f, 2, 1, 0,   4, 5, 6, 7,    3, POSITIVE);

I'd like to figure out why it fails to recognize the chip. The only way that can happen is that after a zero was written to the port register something other than zero was read back.
That shouldn't happen.
It would be nice if you could print out the hex value of the "data" variable in IdentifyIOexp()
just after this line:

	data = Wire.read();

That will give a clue as to what is getting read back.
Maybe there is a short on the PCB?
Or perhaps a bad transistor that is creating a short?

Also, remember that for best results, you should start from a clean power up to ensure that the hd44780 chip isn't in some funky state since there is no way to reset it other than a power cycle.

--- bill

Hi Bill,
I've checked and the two versions differ quite a bit. The one titled as v1.4.1 doesn't like my I2C and comes up with Device Found: UNKNOWN Only supports PCF 8574.

The one that appears to work is:

static char dummyvar; // dummy declaration for STUPID IDE!!!!
/*----------------------------------------------------------------------------
 * vi:ts=4
 *
 * i2cLCDguesser - guess i2c constructor for pcf8574 lcd backpack
 *
 * Created by Bill Perry 2013-04-16
 * Copyright 2013 - Under creative commons license 3.0:
 * Attribution-NonCommercial-ShareAlike 3.0 Unported (CC BY-NC-SA 3.0)
 * license page: http://creativecommons.org/licenses/by-nc-sa/3.0/
 * 
 *  This sketch attempts to locate a pcf8574 based hd44780 backpack
 *  and then tries to figure out the pin configuration for it by guessing....
 * 
 *  NOTE/WARNING: Guessing is not really a good thing since 
 *  depending on the hardware design and wiring,
 *  it could actually damage the hardware. Use with caution!!!
 *  and do not leave things with an incorrect guess for too long.
 *  i.e. advance to the next guess as soon as possible.
 * 
 *  It requires using fm's LiquidCrystal library replacement:
 *  https://bitbucket.org/fmalpartida/new-liquidcrystal/wiki/Home
 * 
 *  For each guess it will re-initialize the display and
 *  write the constructor to the serial port.
 *  It will then attempt to blink the backlight 3 times.
 *  Finally it will attempt to write the constructor used to the LCD.
 *  When the correct configuration is guessed,
 *  the LCD will display the constructor
 *  and the backlight will be on.
 * 
 *  To use:
 *  - install fm's library (it replaces the stock LiquidCrystal library)
 *  - hookup the i2c backpack and only the i2c backpack to the Arduino
 *    (make sure to use the needed pullup resistors - 
 *      i2c needs them to work correctly)
 *  - compile and upload the sketch
 *  - go to the serial monitor and set the baud rate to 9600 baud
 *  - press the reset button on the arduino to start clean
 *  - Press the <ENTER> key or [Send] button to advance to next guess
 *
 *  Created April 2013
 *  Author: Bill Perry
 * 
 * History
 * 2013.04.16 bperrybap - Original creation
 *
 * @author Bill Perry - bperrybap@opensource.billsworld.billandterrie.com
 *----------------------------------------------------------------------------*/
 
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

#define LCD_COLS 16
#define LCD_ROWS 2

char *i2cWarning = "\n\
----------------------------------------------------------------\n\
NOTE/WARNING: Guessing the i2c constructor is not really a\n\
good thing since it could damage the hardware. Use with caution!\n\
Do not leave things with an incorrect guess for too long.\n\
i.e. advance to the next guess as soon as possible.\n\
when the guess in incorrect.\n\
If the guess is correct, the constructor will show up\n\
on the LCD.\n\
----------------------------------------------------------------\n\
";




int locatedevice(void);
int guessconfig(uint8_t address);

void setup()
{
 Wire.begin();
 
 Serial.begin(9600);
 Serial.println("i2cLCDguesser - Guesses i2c constructor for i2c LCD backpack");
 Serial.println(i2cWarning);
 waitinput("<Press a Key to Continue>");
}
 

void loop()
{
int address;

 address = locatedevice(); // go look for a i2c device
 if(address >= 0)
 {
 /*
 * Got i2c address, so now go start trying configurations
 */
 if( guessconfig((uint8_t) address))
 while(1); // user found config so halt
 }
 else
 {
 delay(3000); // wait before looking again
 }
}

/*
 * Returns address of first i2c device found, or negative value if none found
 */

int locatedevice(void)
{
uint8_t error, address;
int rval = -1;
 
 Serial.println("Scanning i2c addresses for pcf8574 chip...");
 
 for(address = 0; address <= 127; address++ )
 {
 Wire.beginTransmission(address);
 error = Wire.endTransmission();
 if (error == 0)
 {
 Serial.print("i2c device found at address 0x");
 if (address<16)
 Serial.print("0");
 Serial.println(address,HEX);
 rval = address;
 break;
 
 }
 else if (error==4)
 {
 Serial.print("Unknown error at address 0x");
 if (address<16)
 Serial.print("0");
 Serial.println(address,HEX);
 }   
 }
 if (rval < 0)
 Serial.println("No I2C device found");

 return(rval);
 
}

/*
 * Identify I2C device type.
 * Currently PCF8574 or MCP23008
 */
int IdentifyDevice(uint8_t address)
{
 Wire.beginTransmission(address);
 
}


typedef struct
{
 uint8_t en;
 uint8_t rw;
 uint8_t rs;
 uint8_t d4;
 uint8_t d5;
 uint8_t d6;
 uint8_t d7;
 uint8_t bl;
 __typeof__(POSITIVE) pol; // use typeof() for backward compability since polarity type name changed
} i2cdata;



i2cdata i2cparam[] = {
// EN, RW, RS, D4, D5, D6, D7, BL, POL
  { 6,  5,  4,  0,  1,  2,  3,  7, NEGATIVE }, // I2CIO board modded for backlight
  { 6,  5,  4,  0,  1,  2,  3,  7, POSITIVE }, // I2CIO board modded for backlight
  { 4,  5,  6,  0,  1,  2,  3,  7, NEGATIVE }, // MJKDZ board
  { 4,  5,  6,  0,  1,  2,  3,  7, POSITIVE }, 
  { 2,  1,  0,  4,  5,  6,  7,  3, NEGATIVE },
  { 2,  1,  0,  4,  5,  6,  7,  3, POSITIVE },
  {0xff} // end of guess table
};


int guessconfig(uint8_t address)
{
uint8_t guess = 0;
char buf[64];

 while(i2cparam[guess].en != 0xff)
 {

 Serial.print("Trying: ");

 sprintf(buf, "lcd(0x%02x, %d, %d, %d, %d, %d, %d, %d, %d, %s)",
 address,
 i2cparam[guess].en,
 i2cparam[guess].rw,
 i2cparam[guess].rs,
 i2cparam[guess].d4,
 i2cparam[guess].d5,
 i2cparam[guess].d6,
 i2cparam[guess].d7,
 i2cparam[guess].bl, i2cparam[guess].pol == POSITIVE ? "POSITIVE" : "NEGATIVE");
 Serial.println(buf);
 
 /*
 * initialize constructor with guess
 */
 LiquidCrystal_I2C lcd = LiquidCrystal_I2C(
 address,
 i2cparam[guess].en,
 i2cparam[guess].rw,
 i2cparam[guess].rs,
 i2cparam[guess].d4,
 i2cparam[guess].d5,
 i2cparam[guess].d6,
 i2cparam[guess].d7,
 i2cparam[guess].bl,
 i2cparam[guess].pol);

 lcd.begin(LCD_ROWS, LCD_COLS);

 /*
 * Quick 3 blinks of backlight
 */
 for(int i = 0; i< 3; i++)
 {
 lcd.backlight();
 delay(250);
 lcd.noBacklight();
 delay(250);
 }
 lcd.backlight();

 lcd.clear();
 sprintf(buf, "0x%02x,%d,%d,%d,%d,",
 address,
 i2cparam[guess].en,
 i2cparam[guess].rw,
 i2cparam[guess].rs,
 i2cparam[guess].d4);
 lcd.print(buf);

 sprintf(buf, "%d,%d,%d,%d,%s",
 i2cparam[guess].d5,
 i2cparam[guess].d6,
 i2cparam[guess].d7,
 i2cparam[guess].bl, i2cparam[guess].pol == POSITIVE ? "POSITIVE" : "NEGATIVE");
 lcd.setCursor(0, 1);
 lcd.print(buf);

 waitinput("<Press a Key to Continue>");
 lcd.clear();
 guess++;
 }
 return(0);
}
void waitinput(char *prompt)
{
 while(Serial.available())
 Serial.read(); // swallow all input

 Serial.print(prompt);

 while(!Serial.available()){} // wait on serial input
 Serial.println();
}

However, the addressing you've suggested doesn't work.

I'm wondering if this newer A-version IC requires a different LCD library from FM. I'm using version 1.2.1

I've tried the more recent 1.3.3 but it's quite different and doesn't compile with the normal LCD sketches. Maybe I need to look into that. :confused:

There is NO difference between a PCF8574A and a PCF8574 except for the Address range.

I have a PCF8574A on a dev board @0x38 (together with several other I2C devices)

@tfboy,
Your guesser sketch identifies the PCF8574A @ 0x38. And suggests the correct constructor()

@Bill,
The v1.4.1 guesser finds all the I2C devices on the bus. It does not suggest a constructor()
In fact, it does not ask you to press the key when it has multiple devices on the bus.

I added a regular 0x27 display to the bus. It found the extra device on the bus.
It did not ask for key. Presumably because of multiple devices.

I removed the dev board from the bus. When there was just the single <0x27> device, it guessed correctly.

I over-rode the "multiple device" failure and forced 0x38 as my device.
IdentifyIOexp(0x38) declared it was a MCP23008 and I am not sure why. Your strategy looks correct to me. i.e. a PCF8574 will return 0 from the output latch.
Edit. IdentifyIOexp(0x38) identified a PCF8574 controller. And it suggested the correct constructor().

Anyway, an LCD connected to my dev board's PCF8574A worked absolutely fine with the constructor() suggested by tfboy's sketch.

Incidentally, I modified your v1.41 sketch to detect external pull-up resistors as an "extra diagnosis".
Yes, my dev board uses proper pull-up resistors.

David.

david_prentice:
There is NO difference between a PCF8574A and a PCF8574 except for the Address range.

Nor would you expect there to be according to the original datasheet (2002).

tfboy:
You're right David, I hadn't noticed, but the second board I received does have the newer PCF8574A chip (and the older one has the non-A version as printed on the IC).

Which is a misunderstanding - the "A" does not mean it is in any way "newer". It is merely an alternative version permitting more than eight to be used on an I2C bus.

Actually, since it has controllable address lines, you can if you want to, cascade as many as you need (within reasonable loading on the bus).

Bill, sorry, I missed your question regarding printint out the hex value of the "data" variable in IdentifyIOexp()
just after line "data = Wire.read();". If that's still relevant, I'll need some guidance, I can't quite understand how to do that.

David, I the address of my device is 0x3f, not 0x38 :slight_smile: If the "constructor()" is what you mean by the coding line "LiquidCrystal_I2C(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);" then it doesn't work (shouldn't I add the "lcd" before the parameters?).

As far as I can tell, I have the correct address, 0x3f, as this is identified by the guesser which I could get working. This would be confirmed by the blinking backlight when starting one of those simple "hello world" sketches.

However, with the above, I only get this on the display:

So unless I need to try another coding string, then either I need a different LiquidCrystal library or something's wrong with my display.

If I'm on the wrong track, please advise.

Thanks for your help so far :slight_smile:

Yes, I realise that your device is (0x3F). I can see that from the empty A0 A1 A2 pads on your pcb. You can change this address by soldering links across these pads. There is no need to change address. (shorting all the pads would make the address 0x38)
My dev board is hard-wired as (0x38) and difficult to change.

You should try:

LiquidCrystal_I2C lcd(0x3F, 2,  1,  0,  4,  5,  6,  7,  3, POSITIVE);  // this is called a constructor()

I am sure that there is a simple solution. It is unlikely that you have two "bad" displays. A duff LED on a green display does not matter. A duff LED on a blue display makes it unreadable. A shorted track should be easy to cure. Without a backlight, the 20x4 display will only take a few mA.

David.

Thanks David.

I'll see if there's a shorted track. It does pull around 150mA so would something must have shorted or something's blown.

The constructor doesn't work. Blue backlight flashes but no text appears, just the blocks and a half :frowning:

/* YourDuino.com Example Software Sketch
 20 character 4 line I2C Display
 Backpack Interface labelled "YwRobot Arduino LCM1602 IIC V1"
 Connect Vcc and Ground, SDA to A4, SCL to A5 on Arduino
 terry@yourduino.com */

/*-----( Import needed libraries )-----*/
#include <Wire.h>  // Comes with Arduino IDE
// Get the LCD I2C Library here: 
// https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads
// Move any other LCD libraries to another folder or delete them
// See Library "Docs" folder for possible commands etc.
#include <LiquidCrystal_I2C.h>

/*-----( Declare Constants )-----*/
/*-----( Declare objects )-----*/
// set the LCD address to 0x27 for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x3F, 2,  1,  0,  4,  5,  6,  7,  3, POSITIVE);  // Set the LCD I2C address


/*-----( Declare Variables )-----*/


void setup()   /*----( SETUP: RUNS ONCE )----*/
{
  Serial.begin(9600);  // Used to type in characters

  lcd.begin(20,4);         // initialize the lcd for 20 chars 4 lines, turn on backlight

// ------- Quick 3 blinks of backlight  -------------
  for(int i = 0; i< 3; i++)
  {
    lcd.backlight();
    delay(250);
    lcd.noBacklight();
    delay(250);
  }
  lcd.backlight(); // finish with backlight on  

//-------- Write characters on the display ------------------
  // NOTE: Cursor Position: Lines and Characters start at 0  
  lcd.setCursor(3,0); //Start at character 4 on line 0
  lcd.print("Hello, world!");
  delay(1000);
  lcd.setCursor(2,1);
  lcd.print("From YourDuino");
  delay(1000);  
  lcd.setCursor(0,2);
  lcd.print("20 by 4 Line Display");
  lcd.setCursor(0,3);
  delay(2000);   
  lcd.print("http://YourDuino.com");
  delay(8000);
  // Wait and then tell user they can start the Serial Monitor and type in characters to
  // Display. (Set Serial Monitor option to "No Line Ending")
  lcd.setCursor(0,0); //Start at character 0 on line 0
  lcd.print("Start Serial Monitor");
  lcd.setCursor(0,1);
  lcd.print("Type chars 2 display");  


}/*--(end setup )---*/


void loop()   /*----( LOOP: RUNS CONSTANTLY )----*/
{
  {
    // when characters arrive over the serial port...
    if (Serial.available()) {
      // wait a bit for the entire message to arrive
      delay(100);
      // clear the screen
      lcd.clear();
      // read all the available characters
      while (Serial.available() > 0) {
        // display each character to the LCD
        lcd.write(Serial.read());
      }
    }
  }

}/* --(end main loop )-- */


/* ( THE END ) */

I am confused. You have a Blue 20x4 and a Green 20x4 display. You have identified the same pcb traces on each I2C controller.

I presume that the Green LCD has a duff backlight. Which you can test very easily.
Does the Green LCD show text properly? And with which constructor()?
And the Blue LCD does not work with the constructor() suggested by the guesser sketch.

The soldering looks ok from your photos. Both on the adapter and the connecting header strip. Only you can check it.

Quite honestly, I have run out of ideas.

David.

I missed your question regarding printint out the hex value of the "data" variable in IdentifyIOexp()
just after line "data = Wire.read();". If that's still relevant, I'll need some guidance, I can't quite understand how to do that.

You need to add these two lines to the function and report back the printout.

Serial.print ("Byte read from device   0x"); //add this line
Serial.println(data, HEX); //add this line
/*
 * Identify I2C device type.
 * Currently PCF8574 or MCP23008
 */

int IdentifyIOexp(uint8_t address)
{
uint8_t data;
int chiptype;

 /*
 * Identify PCF8574 vs MCP23008
 * It appears that on a PCF8574 that 1 bits turn on pullups and make the pin an input.
 * and 0 bits set the output pin to 0.
 * And a read always reads the port pins.
 *
 * Strategy:
 * - Try to Write 0xff to MCP23008 IODIR register (location 0)
 *  - Point MCP23008 to IODIR register (location 0)
 * - Read 1 byte
 *
 * On a MCP23008 the read will return 0xff because it will read the IODIR we just wrote
 * On a PCF8574 we should read a 0 since we last wrote zeros to all the PORT bits
 */

 /*
 * First try to write 0xff to MCP23008 IODIR
 * On a PCF8574 this will end up writing 0 and then ff to output port
 */
 Wire.beginTransmission(address);
 Wire.write((uint8_t) 0); // try to point to MCP23008 IODR
 Wire.write((uint8_t) 0xff); // try to write to MCP23008 IODR
 Wire.endTransmission();

 /*
 * Now try to point MCP23008 to IODIR for read
 * On a PCF8574 this will end up writing a 0 to the output port
 */

 Wire.beginTransmission(address);
 Wire.write((uint8_t) 0); // try to point to MCP23008 IODR
 Wire.endTransmission();

 /*
 * Now read a byte
 * On a MCP23008 we should read the 0xff we wrote to IODIR
 * On a PCF8574 we should read 0 since the output port was set to 0
 */
 Wire.requestFrom((int)address, 1);
 data = Wire.read();

         
        Serial.print ("Byte read from device   0x"); //add this line
        Serial.println(data, HEX); //add this line

        
 if(data == 0xff)
 {
 chiptype = IICchip_MCP23008;
 }
 else if (data == 0x00)
 {
 chiptype = IICchip_PCF8574;
 }
 else
 {
 chiptype = IICchip_UNKNOWN;
 }
 return(chiptype);
}

Sorry for the confusion David.
Both of my screens are blue.
One has no working backlight, but appears to work, although as you say, is nearly unusable as text is hard to read.
On that working screen, a construcor that works is

lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE)

Thanks cattledog.
On the other screen with backlight but no success so far (apart from flashing backlight)
I get:

Scanning i2c bus for devices..
i2c device found at address 0x3F
Byte read from device   0x20
Device found: UNKNOWN
Only supports PCF8574