Using the I2C expander for 16×2 and 20×4 LCD displays

by Floris Wouterlood – the Netherlands – July 4, 2017

Summary

An easy solution to display data on a LCD display, especially when you are about to run out of pins on your Arduino is to use I2C mediated display. This way of communication requires only two pins on the microcontroller bord: A4 and A5

The purpose of this paper is to provide a beginner with the basics of connecting a LCD display to an Arduino via an i2C adapter: the 16-pin IIC/I2C/1602/2004 LCD adapter, also called ‘i2c expander’

Introduction  

The standard way for an Arduino to display measured data or to keep track of output is its Serial Monitor functionality. Serial Monitor is extremely important for the programmer to know what’s going on, what the microcontroller is doing and whether the microcontroller is doing things as expected. For instance, if a sensor is attached to the microcontroller one wants to know whether this sensor is recognized, whether it works or not and what it measures.

There are several ways other than Serial Monitor for an Arduino to present output, e.g., LCD displays, TFT displays, OLED displays, led matrices, output to file or to a server. The output devices have in common that their wiring requires a bunch of wires that, by consequence, require many of the available pins of the microcontroller board. The conventional LCD display needs 6 lines plus power and GND which means serious competition for pins that are necessary for other devices such as sensors. Classical output devices can be categorized as ‘pin hungry’.
Apart from analogous and digital pin input/output there exist for Arduinos three ways of communication with peripheral devices: standard Tx-Rx serial communication, soft serial communication and the I2C protocol. The attraction of I2C lies herein that it can be used to communicate with all kinds of peripheral devices: both for sensors and displays. Every I2C device has its own address and only when that address is called the device responds. There are only two wires and, consequently, two pins involved on the micrcontroller board: pins A4 and A5. Using the I2C protocol to drive LCD displays is becoming popular. The market is becoming flooded with inexpensive LCD displays fitted with a soldered-on backpack I2C expander. Also ‘traditional’ 16×2 or 20×4, Hitachi HD44780 controlled LCD displays with their 16-pin parallel interface can be combined with a standalone I2C expander.

Pull up resistors

When multiple I2C devices are connected with an Arduino, a 4.7 kΩ pullup resistor is recommended, placed between SCL and 5V, and a similar one between SDA and 5V. In the current project, with only one I2C device, pullup resistors are not necessary.

Figure 1: Wires between an standalone LCD expander and an Arduino. Red: 5V, black GND, green SDA , yellow SCL. With a screwdriver the potentiometer on the adapter can be turned to adjust contrast of the LCD screen.

Electronics and supplies

1x Arduino Uno microcontroller board, breadboard, Dupont jumper wires, 20×4 LCD display, Hitachi HD44780 compliant, 1 x 16-pin IIC/I2C/1602/2004 LCD adapter.

Figure 2: Working version of a 20×4 LCD display with 16-pin parallel interface powered via a I2C LCD adapter. Wire colors: red: 5V, black GND, green SDA (pin A4 on the Arduino Uno), yellow SCL (pin A5 on the Arduino Uno. Sketch published in this paper in two versions.

 

Sketch – notes

Below is the complete ‘bare’ sketch. An up- and running Arduino IDE on your computer is necessary. Copy-paste the list of instructions below into an empty new file in the Arduino IDE. There are two alternatives.

The sketch works with 16×2 and 20×4 LCD displays provided that the instruction that initializes the display contains the correct numbers for lines and characters, that is ‘lcd.begin(16,2)’ for 16×2 displays or ‘lcd.begin(20,4)’ for 20×4 displays.

Note: there seems to be a multitude of I2C libraries called ” out there. The library  ‘LiquidCrystal_I2C’ in alternative #1 was created by Francisco Malpartida – also known as the NewLiquidCrystal package. The library can be found at  https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads. The library ‘hd4780’ in alternative #2 was created by Bill Perry. This library can be downloaded from http://www.arduinolibraries.info/libraries/hd44780

I2C address

Each device on the I2C bus has its own unique address. The LCD display useed here has address 0x3F. The I2C address used by a  device can be found with the sketch ‘i2c_scanner’ which is in the public domain. I have integrally copied the sketch to the end of this document

 

Sketch 1 – alternative #1

(based on Francisco Malpartido’s LiquidCrystal_I2C library). In this sketch you have to initialize the LCD display via the construct  LiquidCrystal_I2C lcd (0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

//———————————————————–

//  I2C_hello_world_20x4_LCD_basic
// public domain

//  for a 20×4 16-pin Hitachi HD44780 compliant LCD display

//  works also with 16×2 LCD display – change lcd.begin and the cursor positions

#include <Wire.h>

#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // Set the LCD I2C address

void setup() {

lcd.begin(20,4); //initialize the lcd
lcd.clear();

}

void loop() {

lcd.setCursor(2,1);     // start on third position of the second line of the display

lcd.print(“Hello”);

lcd.setCursor(10,2); // start on the eleventh position of the third line of the display
lcd.print(“World!”);
delay (1000);

for (int j=0; j<4; j++){
lcd.setCursor(00,j);
lcd.clear();              // clears the line where the cursor is positioned
}

delay(500);

}

 

Sketch 1 – alternative #2

(based on Bill Perry’s HD44780 library). Here the I2C expander is automatically recognized.

// I2C_hello_world_20x4_LCD_basic
// public domain
// hd44780 library by Bill Perry

#include <Wire.h>

#include <hd44780.h>                                                    // include hd44780 library header file
#include <hd44780ioClass/hd44780_I2Cexp.h>     // i/o expander/backpack class

hd44780_I2Cexp lcd;                                                      // auto detect backpack and pin mappings

void setup() {

lcd.begin(20,4);                                                                  //initialize the lcd
lcd.clear();

}

void loop () {

lcd.setCursor(2,1);                                                              // start on third position of the second line of the display
lcd.print (“Hello”);

lcd.setCursor(10,2);                                                            // start on the eleventh position of the third line of the display
lcd.print(“World!”);
delay (1000);

for (int j=0; j<4; j++){
lcd.setCursor(00,j);
lcd.clear();                                                                            // clears the line where the cursor is positioned
}

delay(500);

}

Sketch: I2C_scanner

// ————————————–
// i2c_scanner
//
// Version 1
// This program (or code that looks like it)
// can be found in many places.
// For example on the Arduino.cc forum.
// The original author is not know.
// Version 2, Juni 2012, Using Arduino 1.0.1
// Adapted to be as simple as possible by Arduino.cc user Krodal
// Version 3, Feb 26 2013
// V3 by louarnold
// Version 4, March 3, 2013, Using Arduino 1.0.3
// by Arduino.cc user Krodal.
// Changes by louarnold removed.
// Scanning addresses changed from 0…127 to 1…119,
// according to the i2c scanner by Nick Gammon
// http://www.gammon.com.au/forum/?id=10896
// Version 5, March 28, 2013
// As version 4, but address scans now to 127.
// A sensor seems to use address 120.
// Version 6, November 27, 2015.
// Added waiting for the Leonardo serial communication.
//
//
// This sketch tests the standard 7-bit addresses
// Devices with higher bit address might not be seen properly.
//

#include <Wire.h>

void setup()
{
Wire.begin();

Serial.begin(9600);
while (!Serial); // Leonardo: wait for serial monitor
Serial.println(“\nI2C Scanner”);
}

void loop()
{
byte error, address;
int nDevices;

Serial.println(“Scanning…”);

nDevices = 0;
for(address = 1; address < 127; address++ )
{
// The i2c_scanner uses the return value of
// the Write.endTransmisstion to see if
// a device did acknowledge to the 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.print(address,HEX);
Serial.println(” !”);

nDevices++;
}
else if (error==4)
{
Serial.print(“Unknown error at address 0x”);
if (address<16)
Serial.print(“0”);
Serial.println(address,HEX);
}
}
if (nDevices == 0)
Serial.println(“No I2C devices found\n”);
else
Serial.println(“done\n”);

delay(5000); // wait 5 seconds for next scan
}

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s