Introduction: Tutorial: I2C LCD

This Instructable covers the use of the I2C 1602 LCD display with a variety of microcontrollers, including the ESP32, Leonardo, and, of course, the UNO, as it still is the most popular microcontroller board. Fortunately, the changes between these microcontrollers is minimal and a sketch that works with one microcontroller will likely work with another, as shown here.

The I2C 1602 is very easy to use, and its connections (there are only four (4)) are easy to make. Its use by Makers is even easier. Thus, it is a surprise it is not used in more Maker projects. Hopefully, this Instructable can help ameliorate that situation.

This Instructable uses components that are likely already in most microcontroller Makers parts inventory. Of course, if you are not already a circuit or microcontroller Maker, you may not have these components.

Fortunately, whether you use a "raw" 1602 or an I2C one, all 1602 LCDs are relatively easy to use.

The nice things about the I2C 1602, or the I2C 2004 ("raw" versions of these two (2) displays have these advantages as well): (1) they allow Makers to become untethered from the display console; i.e., Makers have both mobility and portability, and they can display any items needed on an LCD display, rather than the display console, and (2) these LCD displays are easy to use.

Before covering I2C 1602 displays, it will be useful to discuss non-I2C 1602 LCD displays. I2C LCDs have additions to the "raw" 1602 and 2004 displays.

First, these displays are categorized as 1602s, as they display sixteen (16) characters on each of two (2) lines (i.e., thirty (32) characters in total).

There are protective mounts for the "raw" 1602s. However, the I2C 1602s have four (4) pin connectors that almost touch the sides of the 1602 holders, and so I2C 1602s are not as easily mounted (see attached photograph of an assembled 1602 mount). That is, there is little room to connect Dupont cables, unless the I2C 1602s are mounted on the outside, i.e., outside the acrylic front of their mounts, and not protected. These mounts are extremely difficult to assemble, so, even if a Maker is using "raw" 1602s, these mounts are not recommended.

Each character is represented in a seven (7), usually eight (8), or, unusually, eleven (11), rows by five (5) columns matrix (see attached still photograph). The elements of this matrix are small rectangles.

Characters are make by illuminating some of the small rectangles in a matrix (see attached still photograph).

It is possible to design a small number of your own custom characters.

There are spaces separating characters and lines, so that adjacent lines or characters can be easily distinguished.

A related module, mentioned above, is the 2004, which displays twenty (20) characters on each of four (4) rows, i.e., eighty (80) characters in total.

That is, it primarily differs in having more rows, and more characters per row. Other than the extra rows and characters, it is quite similar to the 1602. These, i.e., 2004s, can also be obtained as I2C modules, and so the information here can be easily translated to these larger displays. One, or both, of these LCD displays are probably already available in most Makers "bins".

The 1602, or 2004, LCD displays can be directly connected to an Arduino UNO, or other microcontroller, in what are called "parallel" modes. That is, not in the I2C mode.

In these parallel modes, there are four, or eight port connections. Unfortunately, there are problems with all parallel modes. Specifically, these modes take up too many of the UNO’s headers, or other microcontroller headers/pins, leaving little room for sensors.

Here I show one of the parallel modes for a 1602 LCD connected to an Arduino UNO, i.e., the four port mode, this mode is displayed in an attached photograph.

Compared to the 4-parallel mode, we can "free-up" additional headers if we use an I2C 1602.

Some Makers may have some 1602s, or 2004, LCDs that are not I2C ones. Fortunately, non-I2C 1602s, or 2004s, that is, plain 1602s, or 2004s, can be substituted for what follows, but this is not recommended.

What is even better is that a "piggyback" module can be added to a non-I2C 1602, or non-I2C 2004, LCD to make an I2C one That is, an I2C 1602s, or I2C 2004, can be made, as noted above, by adding an I2C port/serial interface, “piggyback module” (see attached photograph of a "piggyback" module) to make a non-I2C LCD into one that uses I2C.

Obviously, if any Maker chooses to use non-I2C 1602s, or non-I2C 2004s, the Sketches below will need to be modified slightly.

The 1602 LCD can also be obtained as a shield (see another attached photograph).

The advantage of shields is that they provide buttons that can be used for a variety of functions.

The disadvantage is that these shields also use too many headers on the UNO, or headers/pins on other microcontroller, and thus leave little room for adding sensors.

Therefore, for most Maker projects it is probably best to use an I2C 1602 display, rather than using one of the 1602 parallel modes or a shield.

It is probably easiest to buy I2C 1602 displays already assembled, although perhaps not the least expensive way to proceed.

See the attached pictures for an assembled I2C 1602 module, front and back. The 1602 shown already has the “piggyback” module soldered on.

At the time of this publication, I2C 1602 displays were available from China for less than USD $2.00 each, and I2C "piggyback" adapters were available in bulk for less than USD $1.00 each.

Supplies

- An I2C 1602 display

- An Arduino UNO, an Arduino Leonardo, and an Espressif ESP32

- Twelve (12) Dupont wires (Four (4) Male to female for the Arduino UNO, four (4) male to female for the Arduino Leonardo, and four (4) female to female for the Espressif ESP32)

Step 1: 1602 I2C and Arduino UNO Configuration

As the UNO, as noted, is still the most popular microcontroller board, this Step, and some below, address the I2C 1602 and the UNO. Fortunately, the connections are quite straight-forward, and essentially the same, regardless of the microcontroller used.

The attached pictures shows connections to the Arduino UNO, but connections to any other microcontroller are similar (see Steps below). The I2C 1602 only needs connections to 5 vDC power and ground, and SDA and SCL lines.

The I2C 1602 "piggyback" adapter is behind the 1602 LCD display (when this adapter is soldered on to the 1602, it can be found behind the display). It has four pins, as can be seen in the attached photograph. These are respectively: GND, VCC, SDA, and SCL, i.e., exactly, and only, what is needed by the I2C 1602.

These pins can be connected to the Arduino UNO, or other microcontroller, as explained below.

The GND on the back of the I2C 1602 with "piggyback" module connects to any ground on the UNO (or other microcontroller). The VCC pin on the "piggyback" module connects to the five (5) volt header on the Arduino UNO, or the 5 volt pin/header on another microcontroller. SDA and SCL pins on the "piggyback" adapter connect to the SDA and SCL headers on the UNO, or the same identified headers/pins on another microcontroller. On the UNO the SDA and SCL headers are headers 16 and 17, on the digital header side, although this may differ (and does on the ESP32) for some other microcontrollers.

By using I2C, only four headers on the Arduino UNO, ESP32, or other microcontroller, need be used for these connections. Two for power, and two for the SDA and SCL connections.

If an experimental platform is used, the ground and five (5) volts DC headers can connect through Dupont cables to the power rails on the experimental platform, so that easy power connections can be made to other devices.

If an experimental platform is not used, i.e., an Arduino UNO is used without one, the pins on the "piggyback" adapter can be easily connected to the Arduino UNO directly using four (4) female to male Dupont cables.

These are the same connections if the "piggyback" module was used on a 2004 display.

Step 2: Displaying Fixed Characters

The display of fixed characters is very easy using the I2C 1602 LCD and an Arduino UNO, or other microcontroller. We just need to ensure that we use the appropriate #include.

In Sketches, the counters on the 1602 LCD for lines and characters start at zero (0).

Thus, in our Sketch, the first line of the I2C 1602 display is designated as line zero (0), and the first character on each line starts at position zero (0). The second line is designated as line one (1), etc.

Unfortunately, the Instructable site removes the greater than and less than brackets, and the text in between them.

The text between the greater than and less than brackets in the #include that should be used is LiquidCrystal_I2C.h.

Both the missing brackets and the needed text, i.e., the text inside the brackets, are provided in the attached text file.

Note: There is an assumption that the I2C address on your I2C 1602 LCD is 0x27, although 0x3F is also commonly found.

To find the appropriate address, if 0x27, or 0x3F does not work, it is probably best to run a scanner program to find the correct I2C address.

Many scanner Sketchs are available on the internet.

The output from one scanner program, i.e., the scanner Sketch I use, looks like this,

I2C Scanner

Scanning...

I2C device found at address 0x27 !

done


/*
* I2C 1602 Display Fixed Characters

* Written August 8, 2020

* Programmer: R Jordan Keindler

*/

#include // See text

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

int delay1 = 1000;

void setup()

{

lcd.init(); // initialize the lcd

lcd.backlight(); // Turn backlight On

}

void loop()

{

lcd.setCursor(0, 0); // Set cursor at position zero(0) on first line of 1602 LCD

lcd.print("This is 1st Line"); // First line of LCD

lcd.setCursor(0, 1); // Set cursor at position zero (0) on second line of 1602 LCD

lcd.print("This is 2nd Line"); // Second line of LCD

delay(delay1); // Delay one second

}

Step 3: Displaying Variables

Fortunately, the I2C 1602 LCD can display variables, as well as fixed characters.

The Sketchs below demonstrate this capability.

In the first Sketch, the I2C LCD shows, i.e., an output is displayed on the LCD's first line as, the digits zero (0) to nine (9), and then the digits backwards from nine (9) to zero (0) on the LCD's second line.


/*

II2C 1602 Variables Display

Written August 8, 2020

Programmer: R Jordan Keindler

*/

#include //See text in earlier Step

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

int delay1 = 500;

void setup() {

lcd.init(); // initialize the lcd

lcd.backlight(); // Turn backlight On

}

void loop() {

lcd.clear();

lcd.setCursor(3, 0); // Set cursor at position three(3) on first line of 1602 LCD

for (int i = 0; i <= 9; i++) {

lcd.print(i); // Display succesive values of variable i

delay(delay1); // Delay delay1 after each display of i

}

lcd.setCursor(3, 1); // Set cursor at position three(3) on 2nd line of 1602 LCD

for (int i = 9; i >= 0; i--) {

lcd.print(i); // Display succesive values of variable i

delay(delay1); // Delay delay1 after each display of i

}

}


In this second (2nd) example, the values zero (0) through twenty (20) are displayed on both lines of the LCD. The first (1st) line displays the values zero (0) through twelve (12), and the second (2nd) line the values thirteen (13) through twenty (20).

As before to mitigate the Instructable brackets issue, the Sketch is attached as a text file.


/*

II2C 1602 Variables Display

Both LCD Lines

Values 0 through 20

Written August 8, 2020

Programmer: R Jordan Keindler

*/

#include //See text in earlier Step

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

int delay1 = 500;

void setup() {

lcd.init(); // initialize the lcd

lcd.backlight(); // Turn backlight On

}

void loop() {

lcd.clear();

lcd.setCursor(0, 0); // Set cursor at position zero(0) on first line of 1602 LCD

for (int i = 0; i <= 12; i++) {

lcd.print(i); // Display succesive values of variable i

delay(delay1); // Delay delay1 after each display of i

}

lcd.setCursor(0, 1); // Set cursor at position zero(0) on second line of 1602 LCD

for (int j = 13; j <= 20; j++) {

lcd.print(j); // Display succesive values of variable j

delay(delay1); // Delay delay1 after each display of j

}

}

Step 4: Displaying Some Non-Keyboard Characters

The 1602 can also display some non-keyboard characters.

The Sketch below shows fourteen (14) of these that I find most useful.

In this Sketch, we cast some binary numbers as characters, and then print the characters.

If you find that you want a character not shown in these fourteen (14), that I find most helpful, you can search the internet for additional non-keyboard characters that can be displayed on a 1602 LCD.

There are many more non-keyboard characters than the fourteen (14) I use most frequently.

You can try the URL,

https://www.sparkfun.com/datasheets/LCD/HD44780.pd...

Scroll down to page 17, Table 4. At the time of publication of this Instructable, this URL existed. However, I do not control this page, so it may or may not be there when you go to this address. If this page is not available, then just do a Google search.

Some Makers find many of the non-keyboard symbols, such as the degree sign, useful.

I hope the fourteen (14) that I use often will contain the characters you need.

On a different note, unfortunately, the Instructables.com site removes all greater and less than brackets and the text between them. To mitigate this problem I have attached a Sketch text file.

The missing brackets should have the text LiquidCrystal_I2C.h between them, and the brackets and text should appear after the #include.

Note: the binary value 1101 1111 that is used to display a degree sign is the same as the decimal value 223. Thus, we could use lcd.print((char)223), in place of lcd.print((char)B11011111). The same holds for the other binary values as well. That is, we could use decimal values, should we choose to do so. Most 1602 LCD tables present the non-keyboard characters as binary values, so for ease of use that is what is presented here.

/*

I2C 1602 Display

Non-Keyboard Characters

Written August 8, 2020

Programmer: R Jordan Keindler

*/

#include //See text above

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

int delay1 = 500;

void setup()

{

lcd.init(); // initialize the lcd

lcd.backlight(); // Turn backlight On

}

void loop()

{

lcd.setCursor(1, 0); // Set cursor at position one(1) on first line of 1602 LCD

lcd.print((char)B11100000); // Display Alpha in First Position

delay(delay1); // Delay delay1

lcd.print((char)B11100010); // Display Beta in Second Position

delay(delay1); // Delay delay1

lcd.print((char)B11100100); // Display Mu in Third Position

delay(delay1); // Delay delay1

lcd.print((char)B11100101); // Display Small Sigma in Fourth Position

delay(delay1); // Delay delay1

lcd.print((char)B11110110); // Display Large Sigma in Fifth Position

delay(delay1); // Delay delay1

lcd.print((char)B11011111); // Display Degree Symbol in Sixth Position

delay(delay1); // Delay delay1

lcd.print((char)B11110111); // Display Pi Symbol in Seventh Position

delay(delay1); // Delay delay1

lcd.print((char)B11111000); // Display X-Bar in Eighth Position

delay(delay1); // Delay delay1

lcd.print((char)B11110011); // Display Infinity Symbol in Ninth Position

delay(delay1); // Delay delay1

lcd.print((char)B11101100); // Display Cent Sign in Tenth Position

delay(delay1); // Delay delay1

lcd.print((char)B11100011); // Display Epsilon in Eleventh Position

delay(delay1); // Delay delay1

lcd.print((char)B11010010); // Display Chi in Twelth Position

delay(delay1); // Delay delay1

lcd.print((char)B11110100); // Display Ohm Symbol in Thirteenth Position

delay(delay1); // Delay delay1

lcd.print((char)B11101000); // Display Square Root Sign in Fourteenth Position

}

Step 5: Displaying Custom Characters

This step illustrates how to construct a custom character using the I2C LCD's, using the small rectangles in each matrix location.

That is, these small rectangles can be used to design a custom character(s).

The character designed here is a smiling face emogi, which we designate in the Sketch as happyemoji.

First, we use the command shown below to describe the matrix of rectangular elements for the custom character, happyemoji.

byte happyemoji[] = {

B00000,

B11011,

B11011,

B00100,

B00100,

B10001,

B10001,

B01110

};

Note: there are eight rows in this definition, one row corresponds to each row in the character matrix.

Where there is a one (1) in the definition, a small rectangular element in the matrix is turned On. Where there is a zero (0) in the definition, a small rectangle is turned Off.

The custom character, we designed, is illustrated by the character represented in the attached photographs.

Next we use the command,

lcd.createChar(0, happyemoji);

to assign the custom character, we just designed, to a single digit, here zero (0).

We have the option of asigning any special character(s) we design to one of eight single digit choices, zero (0) through seven (7).

The emogi, we just designed, is displayed in consecutive positions on the second line, i.e., line one (1), of the I2C 1602 LCD.

The command lcd.write() can be used when one wants to send custom character(s) to the LCD display.

As was done previously a text file is attached to mitigate the Instructables brackets issue.

/*

by R. Jordan Kreindler

July 27, 2020

happyemoji

*/

#include // See text in earlier Step

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

byte happyemoji[] = { // Setup custom character in matrix

B00000,

B11011,

B11011,

B00100,

B00100,

B10001,

B10001,

B01110

};

int delay1 = 150; // Set delay, so custom character can be seen printing

void setup() {

lcd.init(); // Initilize the LCD

lcd.backlight(); // Turn the LCD backlight On

lcd.createChar(0, happyemoji); // Create custom character and assign to zero (0).

// Can use values zero (0) through seven (7). That is, eight custom characters.

}

void loop() {

lcd.setCursor(0, 0); // Set cursor at 1st line (line zero (0)) at position zero (0)

lcd.print("Custom Character"); // Display "Custom Character" on 1st line of LCD

for (int i = 0; i <= 15; i++) { // Set loop to display custom character in all positions on 2nd line

lcd.setCursor(i, 1); // Set cursor on 2nd line (line one (1)) at position i

lcd.write(0); // Display the custom character on 2nd line of LCD

delay(delay1); // Add delay so custom characters can be seen displayed

}

lcd.clear(); // Clear the LCD so we can start again

}

Step 6: Animation: Four (4) Examples

In this Step I cover four (4) animation examples: an animated Emoji, an animated arrow, an animated bouncing ball, going from left to right, and an animated bouncing ball in the same location on the LCD.

In the Sketch below we design three separate custom characters.

The first is a sad emogi (see first attached still photograph). The second is a neutral emogi, neither happy nor sad, (see second attached still photograph). The third custom character is a happy emogi (see third attached still photograph).

All three are consequtively displayed in the same location on the I2C LCD, thus, providing an animated display.

To mitigate the greater and less than bracket situation with Instructables, the Sketch has also been uploaded as a text file.

Of course, if the delay is reduced from its current setting of 1,500ms, as is appropriate for a tutorial - so changes can be seen, to a lesser value, the animation would move more quickly.

The result is an emoji animation.

/*

* Programmer: R. Jordan Kreindler

* August 8, 2020

* happyemoji animation

*/

#include

LiquidCrystal_I2C lcd(0x27, 16, 2); // Set I2C address to 0x27

byte happyemoji0[] = { // Setup custom character in matrix

B00000,

B11011,

B11011,

B00100,

B00100,

B00000,

B01110,

B10001

};

byte happyemoji1[] = { // Setup custom character in matrix

B00000,

B11011,

B11011,

B00100,

B00100,

B00000,

B11111,

B00000

};

byte happyemoji2[] = { // Setup custom character in matrix

B00000,

B11011,

B11011,

B00100,

B00100,

B10001,

B10001,

B01110

};

int delay1 = 1500; // Set delay, so custom character can be seen printing

void setup() {

lcd.init(); // Initilize the LCD

lcd.backlight(); // Turn the LCD backlight On

lcd.createChar(0, happyemoji0); // Create custom character and assign to zero (0)

lcd.createChar(1, happyemoji1); // Create custom character and assign to one (1)

lcd.createChar(2, happyemoji2); // Create custom character and assign to two (2)

// Can use values zero(0) through seven(7). That is, eight custom characters.

lcd.setCursor(2, 0); // Set cursor at 1st line (line zero (0)) at position two (2)

lcd.clear();

lcd.print(" An Animation "); // Display "An Animation" on 1st line of LCD

lcd.setCursor(7, 1); // Set cursor on 2nd line (line one (1))at position 7

lcd.write(0);

delay(delay1);

}

void loop() {

lcd.setCursor(7, 1); // Set cursor on 2nd line (line one (1))at position 7

lcd.write(0);

delay(delay1);

lcd.setCursor(7, 1); // Set cursor on 2nd line (line one (1))at position 7

lcd.write(1);

delay(delay1); // Add delay so custom characters can be seen displayed

lcd.setCursor(7, 1); // Set cursor on 2nd line (line one (1))at position 7

lcd.write(2);

delay(delay1); // Add delay so custom characters can be seen displayed

}


Below we design two (2) custom characters: a custom arrow and a blank character. That is, the first custom character designed is an arrow. The second is a blank character that will be used to remove each arrow after it is displayed. The custom arrow character is displayed in each of the sixteen (16) visible character positions on the second row, and then removed from each position it appears in. Here we use a 250 ms pause between consecutive arrow displays, to allow each arrow to be easily seen, as is appropriate for a tutorial.

Actually, any delay equal to or greater than 200 ms should also work. As before, the text file for this Sketch is included as an attachment, to mitigate the less than and greater than bracket issue ( or maybe it's a feature :-) ) that Instructables.com has.

This produces an arrow animation, with the arrow moving from the left side to the right side of the display.

/*

* by R. Jordan Kreindler

* arrow Animation

*/

#include

#include

LiquidCrystal_I2C lcd(0x27, 16, 2); // Set I2C address to 0x27

byte arrow[] = {

B01000,

B00100,

B00010,

B11111,

B11111,

B00010,

B00100,

B01000

};

byte nothing[] = {

B00000,

B00000,

B00000,

B00000,

B00000,

B00000,

B00000,

B00000

};

int delay1 = 200;

void setup() {

lcd.init();

lcd.backlight();

lcd.createChar(0, arrow);

lcd.createChar(1, nothing);

lcd.home();

}

void loop() {

lcd.setCursor(0, 0);

lcd.print(" Animation ");

for(int i = 0; i <= 15; i++) {

lcd.setCursor(i, 1);

lcd.write(0);

delay(delay1); // Delay long enough to see arrow

lcd.setCursor(i, 1);

lcd.write(1);

}

lcd.clear();

}


For this animation, we design three (3) custom characters: two (2) custom balls (one to use at the top of a character matrix. and one to use at the bottom of a character matrix), and a blank character. Our goal is to design a "bouncing ball" animation, where the ball "bounces" on the second line of the display from left to right.

Alternating ball characters are displayed in turn at every other one of the sixteen (16) visible character positions (i.e, first ball1 is displayed and then in the next position ball2) on the second row. These are then, subsequently, removed from each position the balls appear in. Here again, we delay 250 ms between displays, so each ball can be easily seen - as is appropriate for a tutorial. Any delay equal to or greater than 200 ms will also work.

/*

* Programmer: R. Jordan Kreindler

* Bouncing Ball Animation

* August 8, 2020

*/

#include // see text

LiquidCrystal_I2C lcd(0x27, 16, 2); // Set I2C address to 0x27

byte ball1[] = {

B01110,

B01110,

B00000,

B00000,

B00000,

B00000,

B00000,

B00000

};

byte ball2[] = {

B00000,

B00000,

B00000,

B00000,

B00000,

B00000,

B01110,

B01110

};

byte nothing[] = {

B00000,

B00000,

B00000,

B00000,

B00000,

B00000,

B00000,

B00000

};

int delay1 = 250;

void setup() {

lcd.init();

lcd.backlight();

lcd.createChar(0, ball1);

lcd.createChar(1, ball2);

lcd.createChar(2, nothing);

lcd.home();

}

void loop() {

lcd.setCursor(0, 0);

lcd.print(" Bouncing Ball"); // Print "Bouncing Ball" on first line of LCD

for(int i = 0; i <= 15; i++) {

lcd.setCursor(i, 1); // Set cursor to second line of LCD

if(i%2==0)lcd.write(0); // Print ball1 if comparison is even

if(i%2==!0)lcd.write(1); // Print ball2 if comparison is odd

delay(delay1); // Delay long enough to see ball1 and ball2

lcd.setCursor(i, 1); // Set cursor to second line of LCD

lcd.write(2); // Erase ball1 or ball2

}

lcd.clear();

}

Lastly, If we change the ball characters slightly, so they are even more visible, and write them to the same location, and shorten the delay. We bounce the ball, i.e., animate it, in the same LCD location.

The Sketch for this is presented below.

You can set the delay to achieve whatever effect you want. A longer delay make make the ball even more visible as it bounces.

/*

* Programmer: R. Jordan Kreindler

* Bouncing Ball Animation

* August 8, 2020

*/

#include // see text

LiquidCrystal_I2C lcd(0x27, 16, 2); // Set I2C address to 0x27

byte ball1[] = {

B01110,

B01110,

B00000,

B00000,

B00000,

B00000,

B00000,

B00000

};

byte ball2[] = {

B00000,

B00000,

B00000,

B00000,

B00000,

B00000,

B01110,

B01110

};

byte nothing[] = {

B00000,

B00000,

B00000,

B00000,

B00000,

B00000,

B00000,

B00000

};

int delay1 = 100;

void setup() {

lcd.init();

lcd.backlight();

lcd.createChar(0, ball1);

lcd.createChar(1, ball2);

lcd.createChar(2, nothing);

lcd.home();

}

void loop() {

lcd.setCursor(0, 0);

lcd.print(" Bouncing Ball"); // Print "Bouncing Ball" on first line of LCD

for(int i = 0; i <= 15; i++) {

lcd.setCursor(8, 1); // Set cursor to second line of LCD

if(i%2==0)lcd.write(0); // Print ball1 if comparison is even

delay(delay1); // Delay long enough to see ball1 and ball2

lcd.write(2); // Erase ball1 or ball2

lcd.setCursor(8, 1); // Set cursor to second line of LCD

if(i%2==!0)lcd.write(1); // Print ball2 if comparison is odd

delay(delay1); // Delay long enough to see ball1 and ball2

lcd.write(2); // Erase ball1 or ball2

delay(delay1); // Delay long enough to see ball1 and ball2

}

lcd.clear();

}

Step 7: I2C 1602 and the Arduino Leonardo

All the Sketches above can also be run on the Arduino Leonardo.

The Arduino UNO and the Arduino Leonardo have essentially the same form factor.

Both microcontrollers are 8-bit and contain 32kB of flash memory.

However, the Arduino Leonardo contains an ATmega32U4 microprocessor, while the Arduino UNO contains an ATmega328. Other than some minor additional differences, these are essentially similar boards. Although they do have different USB connectors.

The only problem with the Arduino Leonardo is that it can, at times, be more difficult to use.

We must be sure within the IDE to select the Tools pull-down menu, and choose Arduino Leonardo to make sure the correct board is choosen for the IDE Sketch environment.

There are no other changes necessary within the IDE. That is, the Sketches above should run on the Leonardo as they are written, after the board selection change is made in the IDE.

Step 8: I2C 1602 and the Espressif ESP32

As mentioned in the Introduction, and shown above with the Arduino Leonardo, the I2C 1602 display can be used with a variety of microcontrollers.

In this Step, we use an Espressif ESP32 development board with the I2C 1602, rather than other Arduinos as we used in previous Steps.

Here we use the Espressif ESP32 to show how it can be used with the I2C 1602 LCD, and also to demonstrate the use of a microcontroller other than an Arduino-based one with the I2C 1602.

We obtain five (5) volts from the VIN pin on the ESP32 (the pin on the bottom left of the board, if the USB connector is facing down and the board components are facing upward, i.e., they are on top of the board).

The GND pin on the ESP32 connects to the GND pin on the "piggyback" module.

We use these connections to provide power from the ESP32 development board to an I2C 1602 display

We also connect the SDA and SCL pins on the "piggyback" module to the appropriate pins on the Espressif ESP32 (See attached photographs).

Below is the Sketch to display both a variable and a variety of fixed characters on an I2C 1602 display connected to an ESP32 development board.

To use this sketch it is necessary to change the IDE tools setting to show we are using this board, i.e., an ESP32 Dev Module.

Again note that the Instructable editor eliminates opening and closing greater than and less than brackets and the text these brackets enclose. These brackets should be present in the #include statement, and the text they should include is LiquidCrystal_I2C.h.

To help migitate this Instructable bracket issue, a text file with the appropriate Sketch is included in the attachments.

/*

* Programmer: R. Jordan Kreindler

* showing the use of the I2C capabilities

* of the ESP32 development board.

* August 8, 2020

*/

#include // See earlier text

LiquidCrystal_I2C lcd(0x27, 16, 2); // Piggyback module address

//(Usually the I2C address is either 0x3F or 0x27)

int j = 2;

void setup() {

lcd.init(); // Initialize the lcd

lcd.backlight(); // Turn the backlight On

lcd.clear(); // Clear the display, and set

// the cursor to home position

lcd.print("1st, Hello World"); // Print " Hello To World " at this

// position

lcd.setCursor(0, 1); // Set the cursor at the starting

// position on the next row

lcd.print(j); // Print variable j with value of 2

lcd.print("nd Line Display"); // Print "nd Line of Display" after printing variable

}

void loop() {

}

Step 9: Character Storage Beyond Display Characters

On the I2C LCDs I have, there are twenty-four (24) character storage positions beyond the sixteen (16) characters that are displayed per line. That is, there are twenty-four (24) additional character positions on each of the two (2) lines of the I2C 1602.

Your 1602 LCD may differ, and so it should be tested if this is not the case. As noted, these extra storage positions are on each of the two lines of the 1602 LCD. That is, there are a total of fourty-eight (48) additional storage locations.

These extra positions can be used for additional memory, or as used here to write extra characters that will appear after scrolling left, one character position at a time, to show each character beyond the usual sixteen (16) displayed. These additional characters, i.e., twenty-four (24) per line, are normally hidden from view.

In this Step, character positions are written beyond the sixteen (16) displayed characters. These extra characters, that are written past position sixteen (16), are then shown consecutively on the screen after each scroll left.

/*

Test II2C 1602 Display for Character Storage Beyond Characters Displayed

Written August 8, 2020

Programmer: R Jordan Keindler

*/

#include // See text in earlier Step

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

int delay1 = 1000;

void setup() {

lcd.init(); // initialize the lcd

lcd.backlight(); // Turn backlight On

}

void loop() {

lcd.clear();

lcd.setCursor(0, 0); // Set cursor at position zero(0) on first line of 1602 LCD

// There are 24 character positions on my LCD beyond those characters displayed

lcd.print("This is 1st Lineabcdefghijklmnopqrstuvwx"); // Test first line of LCD for extra storage

lcd.setCursor(0, 1); // Set cursor at position zero (0) on second line of 1602 LCD

lcd.print("This is 2nd Line123456789112345678921234"); // Test second line of LCD for extra storage

delay(delay1);

for (int i = 0; i <= 23; i++) {

lcd.scrollDisplayLeft();

delay(delay1);

}

}


If you have come to this point - congratulations.

You should now have a basic understanding of some of the key elements of an I2C 1602 LCD, and how to use one in your projects, and with a variety of microcontrollers.

If you liked this tutorial, please be kind enough to check the "Favorited" box at the top of this Instructable. It would be appreciated.

If you have any comments, suggestions, or questions related to this Instructable, please add these to the comments below. Otherwise, start the comment section with your own. If you have any thoughts or questions, about related items not covered in this Instructable, or any suggestions on how I could improve this Instructable, or for future tutorials, I would be pleased to hear from you. You can contact me directly at transiintbox@gmail.com. (Please replace the second 'i' with an 'e' to contact me).