I2C 1602 LCD Displays only blocks.

Hi,

i’ve attached a 1602 I2C LCD display to an Uno, ran the I2CScanner program and found that the address is 0x3F.

I then run this code :

// I2C LCD Hello World

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

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

void setup()

{
  lcd.begin(16,2);
  lcd.clear();
  lcd.print("hello world");
}

void loop () {}

The LCD only displays a line of blocks.

I’ve turned the contrast up and down and still only blocks.

Since the scanner program fetched an address the wiring must be correct? I’ve quadruple-checked it, it’s simple wiring and no mistakes there.

I’m wondering if my instance of an lcd has the right parameter values but the module i bought has no info or even brand name (unless it’s under the I2C module that piggybacks onto the LCD!), so all i’ve changed is the address.

I’m using this library for the I2C LCD :

https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads/

I can make the backlight flash but printing text just results in blocks.

Any help greatly appreciated, i’ve been tinkering with this for nearly 8 hours :confused:

Thanks, Gary.

Does the example in the library work?

larryd:
Does the example in the library work?

Thanks larryd, the example blinks the backlight but doesn't display text, just blocks.

Rather than:
LiquidCrystal_I2C lcd(0x3F,2,1,0,4,5,6,7,3,POSITIVE);

Try this:
LiquidCrystal_I2C lcd(0x3F,16,2);

   #include <Wire.h> 
#include <LiquidCrystal_I2C.h>

// Set the LCD address to 0x27 for a 16 chars and 2 line display
LiquidCrystal_I2C lcd(0x3F, 16, 2);

void setup()
{
	// initialize the LCD
	lcd.begin();

	// Turn on the blacklight and print a message.
	lcd.backlight();
	lcd.print("Hello, world!");
}

void loop()
{	
// Do nothing here...
}

Try searching this forum for I2C and Blocks and stand back as you are inundated with responses.

Don

For an I2C LCD display to work, the I2C address and the I2C backpack to LCD pin mapping must be correct. If the library default settings for either or both are not correct the LCD will not work. You can try to figure out the right pin mapping and use an I2C scanner to find the address, but if you install and use the hd44780 library that is done automatically by the library.

Install the hd44780 library. The hd44780 library is the best available for I2C LCDs. The library is available in the Library Manager. Go to Library Manager (in the IDE menus, Sketch, Include Libraries, Manage Libraries) and in the Topics dropdown choose Display and in the Filter your search box enter hd44780. Select and install the hd44780 library by Bill Perry.

The class that you want to use is the hd44780_I2Cexp class. There are examples to show how to use the library. The nice thing about the hd44780 library is that it will autodetect the I2C address and the I2C backpack to LCD pin mapping.

In the examples, there is a diagnostic sketch that will help us to help you if you still have trouble with the display. Run the diagnostic sketch and post the results.

I have bought several 1602 and 2004 from AliExpess. Some of the 2004 has had the same problem. I complained and got refund. Ordered new which worked.

I suspect that it is the I2C board attached to the LCD display that is bad. Some of them was bent and had contact with the LCD. Other I2C boards had bad soldering and has not been cleaned after production.

OK, the thing is, you are using the older code.

You need to run not the I2Cscanner code, but the i2cLCDguesser:
First half:

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.
 *
 * Since the guesser uses a limited number of known permutations,
 * it is possible that it will not be able to guess the needed
 * wiring.
 * 
 *  To use:
 *  1. install fm's library (it replaces the stock LiquidCrystal library)
 *  2. 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)
 *  3. compile and upload the sketch
 *  4. go to the serial monitor in the IDE and set the baud rate to 9600 baud
 *  5. press the reset button on the arduino to start clean
 *  6. Press the <ENTER> key or [Send] button to advance to next guess
 *     NOTE: Make sure to select a newline as the line ending and
 *           if using the <ENTER> key you must first click on the text box
 *           to give it focus.
 *
 * Also note:
 * With respect to the the jumper on certain baords:
 * On the boards Ive seen so far, it controls the backlight control.
 * Depending on the board, it can
 * - force the backlight on
 * - force the backlight off
 * - allow backlight control by PCF8574
 *
 * So you may have to experiment with the jumper in/out to be able
 * to see anything on the display if you have a display that uses
 * light pixels on a dark background.
 *
 * Known Issue:
 * On chipkit platforms, with MPIDE mpide-0023-linux32-201311118-test
 * and earlier you must modify the twi.c file in
 * {installdir}/pic32/libraries/wire/utility/twic.
 * in the function twi_init()
 * Somthing in the clock stretching initalization causes the i2c module
 * to enter an infinite clock stretch and hang. A work around is to
 * change this:
 *----------------------------------------------------------------------
 *  ptwi->ixCon.reg = (1 << _I2CCON_ON) | (1 << _I2CCON_STREN);
 *----------------------------------------------------------------------
 * to this:
 *----------------------------------------------------------------------
 *  ptwi->ixCon.reg = 0; // disable then renable i2c module
 *  ptwi->ixCon.reg = (1 << _I2CCON_ON) | (1 << _I2CCON_STREN);
 *----------------------------------------------------------------------
 *  Created April 2013
 *  Author: Bill Perry
 * 
 * History
 * 2014-01-09 bperrybap - changed i2c bus scan to avoid reserved space
 * 2013.11.26 bperrybap - added a version number
 * 2013.11.24 bperrybap - added multiple device detection (not allowed)
 * 2013.08.01 bperrybap - added chip type detection
 * 2013.04.16 bperrybap - Original creation
 *
 * @author Bill Perry - bperrybap@opensource.billsworld.billandterrie.com
 *----------------------------------------------------------------------------*/

#define VERSION 141 // major.minor.point 120 is 1.2.0
 
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// Try to detect if fm's library is being used
// and bomb out with an error if missing known defines
// or if using defines that fm's library is known not to use
// #if !defined(BACKLIGHT_OFF) || !defined(BACKLIGHT_ON) || !defined(FOUR_BITS) || defined(En) || defined(Rw) || defined(Rs)
// #error i2dLCDguesser requires using fmalpartida LiquidCrystal replacement library
// #endif

#define LCD_COLS 16
#define LCD_ROWS 2

// hide STUPID ugly 1.x Wire API change nonsense
#if ARDUINO < 100
#define write(_data) send(_data)
#define read() receive()
#endif

#define   IICchip_UNKNOWN 0
#define   IICchip_PCF8574 1
#define   IICchip_MCP23008 2

#define DEFPROMPT ((const char *) 0)


const char *i2cWarning = \
"----------------------------------------------------------------\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);
int IdentifyIOexp(uint8_t address);
const char *iicType2Name(int type);

void setup()
{
  Wire.begin();
 
#if ARDUINO >= 100
  while(!Serial); // wait for native USB devices to enumerate/attach
#endif

  Serial.begin(9600);
  Serial.print("i2cLCDguesser v");
  Serial.print(VERSION/100);
  Serial.print('.');
  Serial.print((VERSION%100)/10);
  Serial.print('.');
  Serial.println((VERSION%100)%10);

  Serial.println(" - Guess constructor for i2c LCD backpack");
  Serial.println(i2cWarning);
  waitinput(DEFPROMPT);
}
 
void loop()
{
int address;
int chiptype;

  address = locatedevice(); // go look for a i2c device
  if(address >= 0)
  {
    chiptype = IdentifyIOexp((uint8_t)address);

    Serial.print("Device found: ");
    Serial.println(iicType2Name(chiptype));
    
    /*
     * Check for PCF8574 chip
     */
    if(chiptype != IICchip_PCF8574)
    {
      Serial.println("Only supports PCF8574");
    }
    else
    {
      waitinput("<Press <ENTER> or click [Send] to start guessing>");
      /*
       * Got i2c address, and PCF8574 so now go start trying configurations
       */

      if( guessconfig((uint8_t) address))
        while(1); // user found config so halt
    }
  }
  delay(3000); // wait before looking again
}

Second half:

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

int locatedevice(void)
{
uint8_t error, address;
int rval = -1;
int devcount = 0;
 
  Serial.println("Scanning i2c bus for devices..");
 
  /*
   * Note: 
   *  Addresses below 8 are reserved for special use
   *  Addresses above 0x77 are reserved for special use
   */
  for(address = 8; address <= 0x77; address++ )
  {
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
    if (error == 0)
    {
      devcount++;
      Serial.print("i2c device found at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.println(address,HEX);
      rval = address;
    }
    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");

  if (devcount > 1)
  {
    Serial.println("Warning: More than 1 device found");
    rval = -1; // for now we don't allow multiple devices on the bus
  }

  return(rval);
}

/*
 * 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();

  if(data == 0xff)
  {
    chiptype = IICchip_MCP23008;
  }
  else if (data == 0x00)
  {
    chiptype = IICchip_PCF8574;
  }
  else
  {
    chiptype = IICchip_UNKNOWN;
  }
  return(chiptype);
}
const char *iicType2Name(int type)
{
const char *name;
  switch(type)
  {
    case IICchip_PCF8574:
      name = "PCF8574";
      break;
    case IICchip_MCP23008:
      name = "MCP23008";
      break;
    default:
      name = "UNKNOWN";
      break;
  }
  return(name);
}

/*
 * Bit positions on i2c expander output port for LCD pins 
 */
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
} IICexpdata;



IICexpdata i2cparam[] = {
// EN, RW, RS, D4, D5, D6, D7, BL, POL
  { 2,  1,  0,  4,  5,  6,  7,  3, POSITIVE }, // YwRobot/DFRobot/SainSmart
  { 2,  1,  0,  4,  5,  6,  7,  3, NEGATIVE }, // Robot Arduino LCM1602/2004
  { 4,  5,  6,  0,  1,  2,  3,  7, NEGATIVE }, // MJKDZ board
  { 6,  5,  4,  0,  1,  2,  3,  7, NEGATIVE }, // I2CIO board modded for backlight (pnp transistor)
  { 6,  5,  4,  0,  1,  2,  3,  7, POSITIVE }, // I2CIO board modded for backlight (npn transistor)
  { 4,  5,  6,  0,  1,  2,  3,  7, POSITIVE }, // (extra combination of MJKDZ just in case...)
  {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(DEFPROMPT);
    lcd.clear();
    guess++;
  }
  return(0);
}
#undef read // ugly but removes Wire libary function mapping done above
void waitinput(const char *prompt)
{
  if(prompt)
    Serial.print(prompt);
  else
    Serial.print("<Press <ENTER> or click [Send] to Continue>");

  while(Serial.available())
    Serial.read(); // swallow all input

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

  Serial.println();
}

This will give you the configuration to insert in this line:

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

However a better approach is to install from the IDE Library Manager, Bill Perry’s “HD44780” library and use the test program and examples from that instead of the older LiquidCrystal_I2C.

Thanks very much for all the help.

Thanks larryd, i tried that but same result.

Thanks Don, yes i did search and read quite a few posts on the topic but had no luck after following steps of a few solutions.

Thanks thehardwareman, i bought 7 of these units and the three i’ve tested are showing only blocks, but you’re right most of them have bent pins but the soldering on mine is fine.

Thanks groundFungus, i installed the library and ran the example hello world but no joy, no errors or anything but still just blocks.

Thanks PaulB, when i run that code i get warnings about multiple libraries, which doesn’t happen when i use other code :

C:\Users\Gary\Documents\Arduino\libraries\LiquidCrystal\I2CIO.cpp:35:10: fatal error: …/Wire/Wire.h: No such file or directory

Multiple libraries were found for “Wire.h”
#include <…/Wire/Wire.h>

Used: F:\Program
^~~~~~~~~~~~~~~~

Multiple libraries were found for “LiquidCrystal_I2C.h”
compilation terminated.

Used: C:\Users\Gary\Documents\Arduino\libraries\LiquidCrystal
exit status 1
Error compiling for board Arduino/Genuino Uno.

I’m going to read through more of the forum posts on the same topic.

Thanks again for helping, Gary.

I'm confused now!

I don't have a Wires folder in my library yet it says there are multiple libraries for Wire.h.

I also only have one LCD-related library in the libraries folder at a time when testing them and it's detecting multiple ones and stopping compilation.

I can't think where it would be seeing other libraries.

I ran the LCDLibTest code from the hd44780 library and still only blocks.

I ordered 3 more I2C 1602A LCD modules which arrive today, they are from a different seller and look slightly different.

Thanks again for help, Gary.

The hd44780 library has an example called I2CexpDiag. Load and run that sketch. Then post the serial monitor output here. That has helped others to find problems.

I've turned the contrast up and down and still only blocks.

If you turn the pot to one end, "blocks" on all lines will show up (all pixels); at the other end, all pixels will be off, somewhere in between is the appropriate contrast setting.

I ran the LCDLibTest code from the hd44780 library and still only blocks.

LCDLibTest is not a hardware diagnostic test. It test various capabilities of the library on the selected i/o class device.

When using the hd44780 library and the hd44780_I2Cexp i/o class for the very first time or with a LCD module and backpack for the very first time, the first thing that should be run is the included diagnostic sketch, I2CexpDiag
This will test the i2c signals, that the library can communicate with the backpack, and test the LCD display RAM/memory.
This is mentioned in the included documentation and the wiki.

--- bill

bperrybap:
If you turn the pot to one end, "blocks" on all lines will show up (all pixels); at the other end, all pixels will be off, somewhere in between is the appropriate contrast setting.

Note however that "somewhere in between", the "appropriate" contrast setting is very near to the end where the "blocks" show, most of the range of the potentiometer is wasted. A good setting to start with is when the blocks are faint.

If you can disconnect the end of the potentiometer which is erroneously connected to 5 V (but there may be more than one track to it, connecting to other things as well) it will increase the range of useful contrast setting.

Thanks Bill i'll run that tomorrow.

Thanks Paul, yes i've adjusted it with care and there aren't even faint signs of text.

Let's see what the diags tell me, should have time tomorrow or possibly this evening.

Cheers, Gary.

What is the part number on the integrated circuit on the I2C PCB?

Thanks very much Bill, your diagnostic code gave me the correct address as 0x27 so all working now with your library :slight_smile:

Thanks Larry, on one brand of LCD the chip is a PCF8574T, on the other one i bought it's a PCF8574AT.

Thanks all for helping, now i can finally see what's going on with my sensors. When i power the Uno via USB to the PC the sensor values go crazy so i have to run it all from a battery and a power distribution board to get the right values.

Thanks again, Gary.