[SOLVED] I2C LCD - Setup instructions for 16x2

Like many on this discussion group, I bought an I2C LCD device for my Arduino only to find that the documentation is either non-existent or, if it does exist, just wrong.

Having spent the last few nights trying out all the options I could find, I thought I’d pull together the steps I used to get my LCD going.

This is an amalgamation of a number of threads and I’ll acknowledge as I go along.

Firstly, the LCD panel I have is an I2C from sainsmart. It’s a 16x2 LCD based on the 1602 panel with a small back-panel to convert it to I2C. It’s shown here http://farm9.staticflickr.com/8046/8115486011_a99d721319_b.jpg for clarity.

Step 1 – collect your tools.

There’s a new LCD library that F Malpartida has created at https://bitbucket.org/fmalpartida/new-liquidcrystal

This tutorial is based on version LiquidCrystal_V1.2.1.zip

This library REPLACES the standard one in Arduino V1.0. So

  • rename the existing LCD library directory
  • unzip the new library
  • place the folder LiquidCrystal into the library folder.
  • Start up the Arduino IDE

Step – 2 Wire up the I2C LCD panel to the Arduino.
Reviewing the photo at http://farm9.staticflickr.com/8046/8115486011_a99d721319_b.jpg you can see the four wires attached to the top of the device. The connections, from left to right, are GND, VCC, SDA and SCL. These latter two are the I2C leads.

My Arduino is an Uno, so the I2C connections are on SDA=A4 and SCL=A5. So go ahead and wire these up, along with the two power leads to the 5V and GND terminals.

**Step 3 - Power up your devices. **

You should see the LCD light up. Depending on how the device was constructed, you might want to turn down the contrast of the LCD; you can do this by inserting a screwdriver into the potentiometer at the back. I suggest you turn it half-way so that there’s still a little contrast.

Step 4 – find the I2C address
Each device has an I2C address that it uses to accept commands or send messages. Unfortunately this is one of the areas where the documentation falls down. So let’s go and look for the one on your device.

Load the sketch over at http://arduino.cc/playground/Main/I2cScanner and follow the instructions to use it. By opening up the monitor window after you upload the sketch, Arduino will scan the address range looking for a reply. Even though the documentation said it was 0x27, this scanner detected it at 0x3F… so I was never going to find it based on the documentation!

Write down the Address that you have found, you’ll need it in the next step.

Step 5 – Fire up the LCD
OK, so now you know that you have a device that works and is responding on the I2C bus. Now we’ll light this up.

The next bit of code is based on Edward Comer’s project over at

Load this up into your IDE, but before you upload it to the Arduino, check two things

The #define I2C_ADDR on line 21 should be set to the value you got on Step 4 above (0x3F in my case).

Line 37 should be reviewed for for the size of lcd.begin (20,4);

For completeness, here’s his sketch modified for my 16x2 LCD

** Example Arduino sketch for SainSmart I2C LCD Screen 16x2
** based on https://bitbucket.org/celem/sainsmart-i2c-lcd/src/3adf8e0d2443/sainlcdtest.ino
** by
** Edward Comer
** LICENSE: GNU General Public License, version 3 (GPL-3.0)

** This example uses F Malpartida's NewLiquidCrystal library. Obtain from:
** https://bitbucket.org/fmalpartida/new-liquidcrystal 

** Modified – Ian Brennan ianbren at hotmail.com 23-10-2012 to support Tutorial posted to Arduino.cc

** Written for and tested with Arduino 1.0
** NOTE: Tested on Arduino Uno whose I2C pins are A4==SDA, A5==SCL

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

#define I2C_ADDR    0x3F // <<----- Add your address here.  Find it from I2C Scanner
#define BACKLIGHT_PIN     3
#define En_pin  2
#define Rw_pin  1
#define Rs_pin  0
#define D4_pin  4
#define D5_pin  5
#define D6_pin  6
#define D7_pin  7

int n = 1;

LiquidCrystal_I2C	lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin);

void setup()
  lcd.begin (16,2); //  <<----- My LCD was 16x2

// Switch on the backlight
lcd.home (); // go home


void loop()
  // Backlight on/off every 3 seconds
  lcd.setCursor (0,1);        // go to start of 2nd line
  lcd.setBacklight(LOW);      // Backlight off
  lcd.setBacklight(HIGH);     // Backlight on

Now compile and you’re away!

1 Like

Very, VERY grateful for this. I have been banging my head for hours trying to get a noname ebay LCD working and it turned out to be the i2c address issue you pointed out. THANK YOU!

I created an account just so i could log in and say to you THANKYOU for this. it helped me so much and saved me so much time. I now have my 16x2 LCD working nicely.

The only issue i need to solve now is when displaying a value, which is for example being read from an analogue pin, and that value is for example 1234 and then the value drops down to say 99 there seems to be some retention of the previous chars. e.g. in this case i will see 9934 on the display. i need to figure out why the chars arent cleared. oh the fun.

but thanks so much again. your my favourite person at the moment. :)

blackscience, have a look at this topic http://arduino.cc/forum/index.php/topic,94633.msg710615.html#msg710615%20%28http://arduino.cc/forum/index.php/topic,94633.msg710615.html#msg710615. May help you.

Pavilion1984. Thanks alot mate, i managed to solve the issue yesterday evening using the exact same method :slight_smile: nice to know my solution wasnt a bad idea as i am new to all of this. I thought i was going to have to modify some of the libraries which looked rather daunting.

 threshold = analogRead (pinA0Value);   // read value of A0

  if (threshold<=999 && threshold>=100) { 
      lcd.setCursor (3,1);        // go to start of the second line - 4th char
      lcd.print("    ");           // clear out the thousands char as it is no longer needed
  }else if (threshold<=99 && threshold>=10) {
      lcd.setCursor (2,1);        // go to start of the second line - 3rd char
      lcd.print("     ");         // clear out the hundreds char as it is no longer needed

  }else if (threshold<=9 && threshold >=0) {
      lcd.setCursor (1,1);        // go to start of the second line - 2nd char
      lcd.print("      ");        // clear out the tens char as it is no longer needed
  lcd.setCursor (0,1);        // go to start of 2nd line
  lcd.print(threshold, DEC);  // print the threshold value

blackscience. No problem, happy to help.

Thanks for these clear instructions, I am sure they will help, but I afraid that I have got stuck on the first step "Rename the existing library" (or words to that effect).

After years using a PC I am sure that I could do it there, but not on my newish iMac!

If I rename the folders there, the IDE still picks up the old library. Any ideas anyone?

Thanks in advance


OK, it is done, if anyone out there is trying to help with my MAC query, thanks but somehow I've stumbled on a solution. The LCD now works fine.

And thanks for the original post, could not be more clear.

I'm glad you all found it useful - I also spent evenings banging my head against a wall trying to solve this. :)

@ianbren - nice post there, here is a bit of karma for you!

I am glad that you like the library and find it useful.

Awesome stuff. Great help.

Many thanks to ianbren. I was stuck with some lcds due to wrong i2c address. Your instructions are clear and comprehensive. Good job.

That was extremely helpful, thanks ianbren !

Just a few pointers for newbies like me (please feel free to correct me) :

  • My LCD setup had PCF8574T chip as the 8-bit I/O expander for I2C bus. (Address 0x27).
  • 8 pins from PCF8574T connect to the LCD display as follows (in this model of the board) :
    LCD <------> pcf8574T CHIP
    RS(pin4) - P0 (pin4)
    RW(pin5) - P1 (pin5)
    EN(pin6) - P2 (pin6)
    BL(pin3) - P3 (pin7)
    D4(pin11) - P4 (pin9)
    D5(pin12) - P5 (pin10)
    D6(pin13) - P6 (pin11)
    D7(pin14) - P7 (pin12)

So, for example, in the code:
#define En_pin 2
means EN signal of LCD is being addressed by P2 of the 8 bit (P0-P7) address bus (parallel).

  • The PCF8574T details are here - http://www.nxp.com/products/interface_and_connectivity/i2c/i2c_general_purpose_i_o/PCF8574T.html (datasheet is a must read).
  • My i2c 1602 blue lcd display has a 2-pin jumper which says BLK and VCC. Removing the jumper enabled the code to take control of the back-light. (otherwise the backlight is always on).
  • On my MAC, I right clicked on the Arduino application file, and selected “Show Package Contents”. Then looked in Contents->Resources->Java->libraries. Renamed LiquidCrystal to “LiquidCrystal.DonotUse.ignoreWarning”. When I restart Arduino, I get warning that the LiquidCrystal.DonotUse.ignoreWarning library cannot be used and I just ignore the warning. This way, I get a reminder that I’m using a external library for LiquidCrystal. I just downloaded the excellent fmalpartida’s LiquidCrystal_V1.2.1.zip (to my Downloads folder). Then from Arduino application, I did a Sketch->“Import Library”->“Add library” and selected the LiquidCrystal_V1.2.1.zip file. That’s all. The library got installed under my “Documents/Arduino/Libraries” as a folder called LiquidCrystal .
  • tip: don’t skip the address scanner step!

i've got my i2c backpacked LCD (PCF8574-based one from ebay, like the Sainsmart or YFRobot ones) working with my Mega2560r3 using the newLiquidCrystal library but does anyone know how to get them working with the LiquidCrystal_I2C library?

The reason I'd prefer the LiquidCrystal_I2C version is that there is a modified version that works with the ATtiny85 on the Playground by the author of TinyWireM, although I can't get it to work either.

If I could get it to work on the Mega, I think I could get it to work on the Tiny, although I'm not convinced TinyWireM actually works with IDE 1.0+ anyway, I've already wasted 2 days fighting with it!

It does seem odd that there are so many LiquidCrystal libraries floating about and pretty much the only one that works with the HD44780 with or without I2C is newLiquidCrystal! I had the same problem with the Raspberry Pi, I modified the Adafruit library to work with that (no I2C) after trying about five different ones.

To me, it sounds like the answer needs to be to get fm’s code working with TinyWireM rather than
the other way around.

I’ll take a look and see what it would take.
I’ve taken a quick look at the USli2c library. It is unfortunate that the library object
was named TinyWireM rather than Wire but that can be handled with some clever #defines

It shouldn’t be that difficult. The pain is that since it is different library and the STUPID! ide
doesn’t automatically set up include paths to the libraries, the user sketch will have
to include the proper wire library <Wire.h> or <TineWireM.h> and if the user
wants a sketch that “just works” on any hardware ifdefs will be needed and the STUPID! ide
is too wimpy to understand ifdefs so I’m not sure it will work.

— bill

To me, it sounds like the answer needs to be to get fm’s code working with TinyWireM rather than
the other way around.

yes i had a go at getting it sorted but ended up with a mess of trying to rename all the Wire calls to TinyWireM ones, its not very portable that way, the author makes use of a bunch of ifdefs when he tried to make it work with the older LiquidCrystal library:

#if defined(__AVR_ATtiny85__) || (__AVR_ATtiny2313__)
#include "TinyWireM.h"      // include this if ATtiny85 or ATtiny2313
#include <Wire.h>           // original lib include

i also tried patching the latest arduino-mk so i could do without that god-awful ide but didn’t get very far, there’s still a lot of hardcoding in there.

sej7278: yes i had a go at getting it sorted but ended up with a mess of trying to rename all the Wire calls to TinyWireM ones, its not very portable that way.

The key is not to rename anything in the code but rather use macros to do it for your. i.e. things like:

define Wire TinyWireM

--- bill

Thanks ianben. I wished I Iooked here first... would have saved me a few hours of frustration. The vendor gave me the wrong I2c address and wrong version of library code. I have a serial LCD from another vendor that I have been using for awhile and I thought this I2c module would be a snap to configure. I was wrong.

Just posting to say thanks to Ian for the excellent guide on this, and also to fm for creating the library in the first place!

I would just like to echo the sentiment of jessesteinen, and thank fm and Ian for making the process of getting a i2C LCD up and going child's play. Thanks also to Krodal who as far as I can see, wrote the I2C scanner code originally.