Home Arduino Projects Arduino to LCD projects – Using 3 Different Types of LCDs

Arduino to LCD projects – Using 3 Different Types of LCDs

by Tutorial45

The Arduino IDE supports a serial monitor window that is very convenient for printing values when debugging a project but a small screen attached to your project for feedback, menus, and results would be much better. You could also make your project totally portable.

I’m going to be looking at three small and inexpensive LED screens which you can easily connect to your Arduino.

The Technology

These devices are Liquid Crystal Displays and have been around for some time. They do not emit light but block it. They may have a back-light or rely on reflected light. 

Each display is made up of several layers and makes use of polarised light. If you polarise light horizontally with one filter you can cut off the light completely with a vertically polarised filter. Some liquids will twist the angle of polarisation when a voltage is applied to them allowing polarised light to pass through the filters.

They are called “twisted nematic liquid crystals”. If you sandwich such a crystal between two polarizers, crossed at 90°, the light would normally be blocked. If a voltage is applied to the crystal it ‘twists’ the light’s polarisation as it passes through the crystal and it is allowed through the second polarizing filter. A liquid crystal display is made up of many layers but remains very thin.

The one of the first uses of LCD displays was with electronic calculators in the early 1970s, replacing the previous tiny red 8 segment displays with magnifying lenses. These small monochrome devices were soon used in clocks, watches and other small, low power applications.

Advantages Disadvantages
High contrast
Low cost
Low power
Compact and very light
Often need an additional light source
Fragile
Slow to react
Limited temperature range – avoid freezing

The Display Modules

I’m going to be looking at 3 different boards:

  • MakerHawk 12C OLED display with 128×64 pixels (blue) 
  • MakerHawk 12C OLED display with 128×32 pixels (white)
  • AZ-Delivery HD44780 2004 Display with I2C converter (4 rows of 20 characters)

The first two can display graphic elements (lines, circles, pictures etc and text) while the last is a character only display.

MakerHawk OLED displays with SSD1306 driver chip

These are I2C devices and only need to be connected to 3.3V-5V, GND, SCL, and SDA. They are very small (diagonals are 0.96” and 0.91” respectively) lightweight, with tiny pixels and excellent contrast, making them very easy to read. The larger display is blue while the smaller is white.

They do not have a backlight and rely on reflection. The larger is supplied with 40 colored DuPont F-F cables and connection pins that need to be soldered to the board. You get two of the smaller displays in the packet, but no connection pins, sockets, or cables. There is no information supplied on how to connect them up to your Arduino or how to control them. The screens are protected with a plastic cover. (Take off carefully as the screens are delicate.) The four connections for I2C are clearly marked on the boards. Both devices have I2C addresses of 0x3C.

The next step is to solder on the pins or sockets and connect them up to your Arduino.

MakerHawk 12C OLED display with 128×64 (blue)

Arduino to LCD projects - Using 3 Different Types of LCDs

MakerHawk 12C OLED display with 128×32 pixels (white)

Arduino to LCD projects - Using 3 Different Types of LCDs

Project #1: Using Arduino with the LCD 128×64 pixel SSD1306 board

Materials needed:

  • Arduino – standard or cloned UNO 
  • MakerHawk 12C OLED display with 128×64
  • Connecting wires
  • 10K Ohm potentiometer

For these demonstrations the potentiometer will provide a variable input voltage on the A0 pin of the Arduino.

LCD 128x64 pixel SSD1306 board

A4 is the SDA pin and A5 is the SCL pin on an Arduino UNO. Other boards may have different pins so check before you connect up.  VCC goes to 5V and GND to GND.  The wiper of the potentiometer goes to A0 on the Arduino and the other pins to 5V and GND.

Now we need to obtain suitable libraries for the SSD1306 boards and for the graphics routines. Adafruit has provided some very useful libraries which are easy to install on the current version of the Arduino IDE.

Start the Arduino software and use the Library Manager to search for and install the Adafruit SSD1306 library (2.2.1 at the time of writing). It covers both sizes of board and I2C and SPI versions. It also installs all the dependencies. Take the option to install the GFX library and the BusIO library at the same time. (https://github.com/adafruit/Adafruit_SSD1306

Check at the bottom of the Examples Menu that all necessary libraries have been installed.

Adding Arduino library

Notice that the library covers both sizes of screen as well as SPI and I2C protocols.

Now we are ready to see can see what the display can do. I’ve provided a couple of scripts to demonstrate the versatility of these displays. The first shows the graphical capabilities, without any user intervention via the potentiometer. I’ve included plenty of comments so you can see what is going on.

SSD1306

The screen origin is top left (0,0) with 128 horizontal pixels (0…127) moving right and 64 vertical pixels (0…63) moving down.

SSD1306

The screen may be small but it is very clear and sharp with enough room to be very useful.

/* SSD1306 128x64 I2C OLED display with Arduino UNO
 * Illustrates text elements and graphics
 * Tony Goodhew  3rd July 2020
 * Tutorial45.com
 */

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

void show() { // Often used sequence - Function to simplify code
  display.display();
  delay(2000);
  display.fillScreen(SSD1306_BLACK);
}
void show2() { // Faster
  display.display();
  delay(400);
  display.fillScreen(SSD1306_BLACK);
}
void setup() {
  Serial.begin(9600);
  randomSeed(analogRead(0));
  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Old Address 0x3D for 128x64
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }
  
// Initialise some variables
  int cw = SSD1306_WHITE; // colour white
  int cb = SSD1306_BLACK; // colour black
  int wait = 2000; // 2 second delay
  int x0 = 7; // 3 pairs of co-ordinates
  int y0 = 7;
  int x1 = 123;
  int y1 = 23;
  int x2 = 50;
  int y2 = 61;
  int w = 117; // Width
  int h = 56;  // Height
  
// Draw a Title screen
  display.clearDisplay();
  display.setTextSize(2);              // Middle
  display.setTextColor(cw);
  display.setCursor(0,15);
  display.println("SSD1306");
  display.println("       GFX");
  display.setCursor(10,53);
  display.setTextSize(1);
  display.println("Tutorial45.com");
  display.display(); delay(wait);
  randomSeed(analogRead(1));
  display.fillScreen(cw);              // Fill screen WHITE
  display.setTextColor(cb);
  display.setCursor(40,53);
  display.println("Tutorial45.com");
  display.setTextColor(cw);
  display.display(); delay(wait); 
  display.fillScreen(cb);              // Fill screen BLACK
  display.display();
  
// Display some Pixels
  for (int m = 0; m <= 17; m++)  {     // 17 random pixels
    int xx = random(127);
    int yy = random(63);
    display.drawPixel(xx, yy, cw);
    display.display();
    delay(130);
  }
  delay(wait); 
  display.clearDisplay();
  
// Draw a Sine curve
  float sine[127]; 
// Initialise variables
  display.fillScreen(cb);
  display.setTextColor(cw);
  display.setCursor(10,56);
  display.setTextSize(1);
  display.println("Sine Curve");
  display.drawFastHLine(0, 32, 127 ,cw);
  for (int i = 0; i < 128; i++){
    sine[i] = (sin(radians(i *2.8125))) * -1; 
    display.drawPixel(i,int(sine[i]*25+32),cw);
    display.display();
  }
  show();

// Demonstrate basic shapes
  display.drawLine(x0, y0, x1, y1 + 30, cw);
  show2();
  display.drawFastVLine(50, 12, h, cw);  // Fast vertical line of length l
  show2();
  display.drawFastHLine(5, 45, w ,cw);   // Fast horizontal line of length w 
  show2();
  // Random lines
  for( int m = 0; m <10; m++) {
    int xr = random(127);
    int yr = random(63);
    int xl = random(127);
    int yl = random(63);
    display.drawLine(xr,yr,xl,yl,cw);
    display.display();
  }
  show();
  display.drawRect(x0, y0, w, h, cw);
  show2();
  display.fillRect(x0, y0, w, h, cw);
  show2();
  display.drawRoundRect(x0, y0, w, h, 14, cw);  // Rounded corners of radius 14  
  show2();
  display.fillRoundRect(x0, y0, w, h, 14, cw);
  show2();

// Grid
  for (int x =0; x < 130; x=x +10) {
    display.drawFastVLine(x, 0, 64, cw);
  display.display();
  }
  for (int y = 0; y < 64; y = y + 10) {
    display.drawFastHLine(0, y, 127 ,cw);
  display.display();
  }
  show();
    
// A few circles
  for (int r = 5;r <32; r=r+5){
    display.drawCircle(63, 31, r, cw);
    display.display();
    delay(500);
  }
  display.fillCircle(63, 31, 31, cw);
  show();
  display.drawTriangle(x0, y0, x1, y1, x2, y2, cw);
  show();
  display.fillTriangle(x0, y0, x1, y1, x2, y2, cw);
  show();

// Screen rotation - 4 0ptions 0, 90 180 and 270 degrees 
  display.clearDisplay();
  display.setCursor(25,32);   // Title splash
  display.print("Rotate Screen");
  display.display(); delay(wait);
  for (int rt = 0; rt <= 4; rt++){
    display.setRotation(rt % 4);               // Values 0..3
    display.clearDisplay();
    display.fillTriangle(0,0,0,30,30,0,cw);     // (x,y,x1,y1,x2,y2,colour)
    display.fillTriangle(0,15,40,50,15,0,cw);
    display.fillTriangle(15,0,50,40,0,15,cw);
    display.fillTriangle(40,50,50,40,20,20,cw);
    display.setTextSize(2);                     // Middle size
    display.setTextColor(cb); 
    display.setCursor(5,5);             
    display.println(rt % 4);
    display.display(); delay(wait);  
  }

// Text Sizes
  display.clearDisplay();
  display.setTextSize(1);                // Normal 1:1 pixel scale
  display.setTextColor(cw);   // Draw white text
  display.setCursor(0,0);                // Start at top-left corner
  display.println("Text Sizes");
  display.setTextSize(2);                // Medium
  display.println("SSD1306");
  display.setTextSize(3);                // Large - rather blocky  
  display.println("SSD1306");
  display.setTextSize(1);
  display.setCursor(40,53);
  display.println("Tutorial45.com");
  show();
  display.clearDisplay();

// Text along a path
  char msg[] =  "+++ Tutorial45.com +++";
  display.clearDisplay();
  for (int n = 0; n < 21; n++){
    char ch = msg[n];
    int p = n*6;
    float y1 = (sin(radians(p *2.8125)) * -1);
    int yy = int(y1 *25.0 + 32);
    display.drawChar(p, yy, ch, cw, cb, 1);
    display.display();
  }
  show();
  display.clearDisplay();
  char msg2[] = "SSD1306+Arduino=MAGIC";
  for (int n = 0; n < 21; n++){
    char ch = msg2[n];
    int p = n*6;
    float y1 = (cos(radians(p *2.8125)) * -1);
    int yy = int(y1 *25.0 + 32);
    display.drawChar(p, yy, ch, cw, cb, 1);
    display.display();
  }
  show();
  display.clearDisplay();
  char Msg[] = ".+Arduino+.";
  y2 = 50;
  for (int n = 0; n < 11; n++){
    char ch = Msg[n];
    int xx = n*12;
    display.drawChar(xx, y2, ch, cw, cb, 2); // (x,y,Char,foreGnd,backGnd,size)
    y2 = y2 - 5;  // Moving up the screen
    display.display();
  }
  show();
  
// Finish up
  display.setTextSize(1);             // Normal 1:1 pixel scale
  display.setTextColor(cw); 
  display.setCursor(0,25);
  display.setTextSize(2);             
  display.println("Finished");
  display.setCursor(40,53);
  display.setTextSize(1); 
  display.println("Tutorial45.com");
  display.display();
}
void loop() {
  // Empty - Linear program which halts
}

The most important thing to remember is that none of the changes specified by the script will actually appear on the screen until the instruction display.display() is executed. The changes go on in the background and this instruction forces updates to the display. In this script it is often hidden inside the show() routine.

The documentation for the library is found here: https://cdn-learn.adafruit.com/downloads/pdf/adafruit-gfx-graphics-library.pdf

Remember that these are simple monochrome displays so we only have two colours.

The second example demonstrates the user updating the display by changing the physical input. As the potentiometer is twisted some of the values displayed change and the bar graph changes in length.

SSD1306
/* SSD1306 128x64 I2C OLED display, Arduino UNO and 10K Ohm pot on A0
 * Tony Goodhew  3rd July 2020
 * Tutorial45.com
 */

#include <Wire.h>              
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

int sensorPin = A0;   // select the input pin for the potentiometer
int sensorValue = 0;  // variable to store the value coming from the sensor

void setup() {
  Serial.begin(9600);
  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }
  display.clearDisplay();
  display.setTextSize(1);             // Small
  display.setTextColor(SSD1306_WHITE); 
  display.setCursor(0,0);             // Top Left corner
  display.println("SSD1306 Project");
  display.setCursor(20,10);
  display.println("Volts - Turn Pot");
  display.setCursor(64,118);
  display.setCursor(0,57);
  display.println("  Raw Pot    Volts");
  display.display();
}
// Functions for right alignment of integers
int iAlign2(int s){  // Space in 100s and 10s
  if (s < 100) {display.print(" ");}
    if (s < 10) {display.print(" ");}    
}
int iAlign3(int s){  // Space in 1000s
  if (s < 1000) {display.print(" ");}
  iAlign2(s);
}
int bar(int yy,int v) {
  display.drawLine(0,yy,0,yy+14, SSD1306_WHITE);
  display.fillRect(1,yy+2,127,10,SSD1306_BLACK);
  display.fillRect(0,yy+2,v,10, SSD1306_WHITE);
  display.setCursor(102,yy+2);
  iAlign2(v);
  display.print(v);
  display.println("%");
  display.display();
}
// ++++++++++++Main Loop ++++++++++++++
void loop() {
  // Read pot and display values
  sensorValue = analogRead(sensorPin); // Read the value from the sensor
  float volts = (sensorValue * 5.0 / 1023.0);  // Calculate voltage
  int x = float(sensorValue * 100.0/1018);     // Calculate percentage
  bar(20,x);  // Redraw bar graph
  display.fillRect(0, 40, 127, 15, SSD1306_BLACK); // Clear line
  display.setCursor(5,40);
  display.setTextSize(2);
  iAlign3(sensorValue);  
  display.println(sensorValue);  // Raw pot value
  display.setCursor(78,40);
  display.print(volts);          // Equivalent voltage
  display.setTextSize(1);
}

Notice that the whole screen is not updated. The top two lines and the bottom line are written in the setup() section. In the loop we update the bar graph and the 3 values. Flicker is minimal and caused by the ADC rather than the screen. The Raw Pot value has been right aligned by add spaces with the functions.

Project #2 Using the Arduino with the LCD SSD1306 128×32 pixel board

I’m now going to look at the smaller board. Obviously, it has half the screen size of the previous board, but this may have advantages if you only want to display a small amount of information or fit the display into a very confined space. 

The connections are the same as on the previous display and properly labeled so just swap over the displays. This is a digital voltmeter using the potentiometer as input.

/* SSD1306 128x32 I2C OLED display, Arduino UNO and 10K Ohm pot on A0
 * Tony Goodhew  3rd July 2020
 * Tutorial45.com
 */

#include <Wire.h>              
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

int sensorPin = A0;   // select the input pin for the potentiometer
int sensorValue = 0;  // variable to store the value coming from the sensor

void setup() {
  Serial.begin(9600);
  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }

// Title screen
  display.clearDisplay();
  display.setTextSize(2);             // Medium size
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(5,5);
  display.println("Volt Meter");
  display.setCursor(40,24);
  display.setTextSize(1); 
  display.println("Tutorial45.com");
  display.display();
  delay(3000);
// Static part of screen
  display.clearDisplay();
  display.setTextSize(1);             // Small
  display.setTextColor(SSD1306_WHITE); 
  display.setCursor(0,0);             // Top Left corner
  display.println("Volts - Turn Pot");
}

int wedge(int v,float vv) {  // Wedge shaped bar graph - like Volume control
  display.drawLine(0,12,0,31, SSD1306_WHITE);
  display.fillRect(1,12,127,20,SSD1306_BLACK);
  display.fillTriangle(0,31,v,31,v,(31 - (19*v / 100)),SSD1306_WHITE);
  display.setCursor(102,20);
  display.print(vv);
  display.display();
}
// ++++++++++++Main Loop ++++++++++++++
void loop() {
  // Read pot and display values
  sensorValue = analogRead(sensorPin); // Read the value from the sensor
  float volts = (sensorValue * 5.0 / 1023.0);  // Calculate voltage
  int x = float(sensorValue * 100.0/1023);     // Calculate percentage
  wedge(x,volts);  // Redraw bar graph
  delay(100);      // Delay to reduce jitter  
}

There are two ways of overwriting text on the screen. Print the same text on top of the previous text in the background colour. This has the disadvantage of having to store the old value for reprinting. Alternatively, you can draw a background coloured filled rectangle over the text. I’ve used the latter in these examples.

Conclusion

These displays are inexpensive, very simple to connect up, use few Arduino pins and are easy to program. They are very clear and support a range of graphical elements. They may be a bit too small, especially the 128×32 board. 

Suggested projects

  • Using a temperature sensor build a Current and Max-Min digital thermometer. 
  • Using two temperature sensors and a humidity sensor build an Outside/Inside  temperature & Humidity display.
  • Using a joystick as an input device (Horizonal plus vertical potentiometers and a button switch) with the larger screen build an ‘Etch-A-Sketch’ type game. The current position of the ‘pen’ could be shown by small dots on the four edges of the display and the button used to switch between foreground and background colours.

AZ-Delivery HD44780 2004 LCD Display Bundle 4×20

This beautifully packed product was supplied from Deggendorf, German. I bought it through Amazon UK which advertised, “The included E-Book provides useful information on how to begin your project, helps with a quick setup, and saves time on the configuration process.” I sent AZ an email requesting the E-Book and it arrived impressively quickly.

There was one small problem. The pdf describes how to use the bare display with its many connections but not how to use the I2C adaptor.

LCD front face

Luckily, I have used these before and know that you have to solder the interface board onto the display board. Normal practice is to solder it underneath with connection I2Cpins pointing out the side at the top left.

Alternatives:

  • Leave it off and use the board as outlined in the AZ guide – uses too many pins!
  • Solder on a row sockets; above or below the board so you can remove the backpack.
  • Solder a row of sockets with long legs so that you can use the display on a breadboard or put the adapter into the sockets. 

Putting the interface board on the back has the advantage of gently tilting the display forward making it easier to read while working at your bench.

LCD back

You will need a small screwdriver to adjust the setting of the blue trim-pot once the display is connected and running a script.

This is another I2C device so we connect up as before. Take care as the SCL and SDA pins are in a different order from the SSD1306! The I2C address of the backpack was 0x27. (There has been a great deal of chat on the various Arduino forums over the years about these backpack boards which are available from many different manufacturers. They come with a variety of I2C addresses but the many libraries available, often with the same name, do not make the address configurable and will only work with a specific board. 

LCD 2004 DisplayArduino UNO
GNDGND
VCC5V
SDAA4
SCLA5

Before we can run the script, we need to download a suitable library for this I2C version of the 2004 LCD. Unfortunately, AZ-Direct did not suggest a suitable site. I’ve been using the library at https://github.com/johnrickman/LiquidCrystal_I2C

and found that it works well with this interface board.

Once the library is installed, we are ready to try out the display. 

Try this short script to test your connections:

// LCD I2C 2004 Test
// Tony Goodhew 4th July 2020
// Tutorial45.com
#include <LiquidCrystal_I2C.h>
// https://github.com/johnrickman/LiquidCrystal_I2C
// Set LCD address to 0x27 with 20 chars by 4 lines display
LiquidCrystal_I2C lcd(0x27, 20, 4);  //(0x27, 16, 2) small LCD

// Character definitions - 5 cols x 7 rows
byte pi[8]  = {0,1,14,26,10,10,10};  // Compact version

byte smiley[8] = {                   // Easy but verbose version
  B00000,
  B01010,
  B00000,
  B00000,
  B10001,
  B01110,
  B00000,
};
byte sad[8] = {
  B00000,
  B01010,
  B00000,
  B00000,
  B01110,
  B10001,
  B00000,
};
void setup() {
  // Initialize the LCD
  lcd.init();
  // Create 3 new characters Max of 8 (0…7)
  lcd.createChar(0, pi);
  lcd.createChar(1, smiley);
  lcd.createChar(2, sad);
  
  // Set Cursor position and print text
  lcd.backlight();
  lcd.setCursor(3,0);
  lcd.print("Hello, world!");
  lcd.setCursor(3,1);
  lcd.print("Arduinos Rock");
  lcd.setCursor(0,2);
  lcd.print("Arduino LCD 2004 I2C");
  lcd.setCursor(3,3);
  lcd.print("Tutorial45.com");
  delay(2000);            //  Wait 2 seconds
  
  // print special characters to 4 corners of screen
  lcd.setCursor(0,3);
  lcd.write(0);
  lcd.setCursor(0,0);
  lcd.write(1);
  lcd.setCursor(19,0);
  lcd.write(2);
  lcd.setCursor(19,3);
  lcd.write(255);  // solid 5x8 block – built in
}

void loop(){}

You should be able to see clear, bright, white characters on a bright blue background. You will probably need to adjust the small blue trim-pot on the back-board to get the best contrast.

Once again, the origin is top left with the corner character at (0, 0). There are 20 characters on a line (0…19) and four rows (0…3).

We need to be very carful about running over the end of a line. 

Change

lcd.print("Arduino LCD i2c 2004");

to

lcd.print("Arduino LCD i2c 2004xx*");

And change

lcd.print("Hello, world!");

to

lcd.print("Hello, world!123456");

When we run the script again, we find that line 0 overflows into line 2 and line 1 overflows onto the  3 line but the “*” gets immediately overwritten by the “T”. 

This can cause some problems so take care not to overrun lines.

This script also demonstrates the definition of special characters. The user can define up to 8 characters on a 7 by 5 grid. This is easily carried out. Just look carefully at the happy and sad face definitions. The 1 bits indicate a white pixel.

byte pi[8]  = {0,1,14,26,10,10,10};
168421
0
11
11114
11126
1110
1110
1110

If you run the script again you will find these defined characters in the corners of the screen. The large block at the bottom right is predefined character 255. https://cdn-shop.adafruit.com/datasheets/TC2004A-01.pdf

This is a long but interesting document and shows the complete ‘built-in’ character set and how the characters you send to the screen are stored. 

Here is a script to display all of the available characters.

// Display LCD 2004 character set
// Tony Goodhew 7th July 2020
// Tutorial45.com
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,20,4);  // set the LCD address to 0x27 and 20x4

byte heart[8] = {0,10,31,31,14,4,0};
byte bknht[8] = {10,31,0,31,14,4,0};
byte ok[8] = {0,1,3,22,28,8,0};
byte no[8] = {0,27,14,4,14,27,0};
byte bong[8]  = {4,14,14,14,31,0,4}; 
byte music[8]  = {2,3,2,14,30,12,0};
byte clk[8] =  {0,14,21,29,17,14,0};
byte turn[8] = {1,1,5,9,31,8,4};

void setup(){
  lcd.init();  // initialize the lcd 
  lcd.backlight();
  lcd.createChar(1, heart);
  lcd.createChar(2, bknht);
  lcd.createChar(3, ok);
  lcd.createChar(4, no);
  lcd.createChar(5, bong);
  lcd.createChar(6, music);
  lcd.createChar(7, clk);
  lcd.createChar(0, turn);
  lcd.home();

// Show the character
  int n = 0;
  while (n < 255) {
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("ASCII Codes: ");
    lcd.setCursor(4,1);
    lcd.print("Dec: ");
    lcd.print(n);
    lcd.print("-");
    lcd.print(n+15);
    lcd.setCursor(4,2);
    lcd.print("Hex: ");
    lcd.print(n, HEX);
    lcd.print("-");
    lcd.print(n+15, HEX);
    lcd.setCursor(2, 3);
    for (int m=0; m<16; m++) {
      lcd.write(n+m);
    }
    n = n + 16;
    delay(2000);
  }
 }
void loop() {}
Arduino to LCD projects - Using 3 Different Types of LCDs

Project #3 Using Arduino with the AZ-Delivery LCD 2004 and FC-113 I2C backpack

Materials needed

  • Arduino – standard or cloned UNO 
  • AZ-Delivery LCD 2004 and FC-113 I2C backpack Connecting wires
  • 3 x 10K Ohm potentiometer
  • 1 x RGB LED or single Red, green and Blue resistors
  • 3 x 560 Ohm resistors – nearby value
  • Breadboard or stripboard
  • Connecting wire
pictorial of lCD 2004
// LCD I2C 2004 Project
// Tony Goodhew 4th July 2020
// LCD i2c, Arduino, RGB LED and 3 10K Ohm potentiometers
#include <LiquidCrystal_I2C.h>
// https://github.com/johnrickman/LiquidCrystal_I2C

// Set the LCD address to 0x27 & 20 chars by 2 lines display
LiquidCrystal_I2C lcd(0x27, 20, 4);  //(0x27, 16, 2) small LCD

#define r 6  // Red LED pin
#define g 5  // Green LED pin
#define b 3  // Blue LED pin

// Character definitions - 5 cols x 7 rows
byte smiley[8] = {
  B00000,
  B01010,
  B00000,
  B00000,
  B10001,
  B01110,
  B00000,
};
byte sad[8] = {
  B00000,
  B01010,
  B00000,
  B00000,
  B01110,
  B10001,
  B00000,
};
byte block[8]  = {0,31,31,31,31,31,31};

void align(int v){                // Right align number with spaces
  if (v < 100) {lcd.print(" ");}
  if (v < 10 ) {lcd.print(" ");}
}
void setup() {
  // Initialize the LCD
  lcd.init(); 
  // Create  new characters - Max of 8
  lcd.createChar(0, smiley);
  lcd.createChar(1, sad);
  lcd.createChar(2, block);  // For bar graph
  lcd.backlight(); 
  
  // Set up static Text
  lcd.clear();
  lcd.setCursor(6,3);
  lcd.print("Tutorial45.com"); // Banner
  delay(1500);
  lcd.setCursor(0,0);
  lcd.print("LCD 2004 I2C Project");
  lcd.setCursor(0,1);
  lcd.print("R:     G:     B:    ");  // Headings 
  lcd.setCursor(0,2);
  lcd.print("Power:            ");
}

void loop(){
  int rValue = analogRead(A0)/4;  // Get Red
  analogWrite(r, rValue);
  lcd.setCursor(2,1);
  align(rValue);
  lcd.print(rValue);  
  int gValue = analogRead(A1)/4;  // Get Green
  analogWrite(g, gValue);
  lcd.setCursor(9,1);
  align(gValue);
  lcd.print(gValue);
  int bValue = analogRead(A2)/4;  // Get Blue
  analogWrite(b, bValue);
  lcd.setCursor(16,1);
  align(bValue);
  lcd.print(bValue);
  int t = (rValue + gValue + bValue) *10 / 255 / 3; // Calc Power
  lcd.setCursor(6,2);
  lcd.print("          ");  // Clear bar graph
  lcd.setCursor(17,2);      // Display power number
  align(t);
  lcd.print(t);
  lcd.setCursor(6,2);
  for (int i=0; i<t; i++) {  // Bar graph
    lcd.write(2); 
  }
  lcd.setCursor(0,3); // Bottom left corner
  if (t > 5) {
    lcd.write(0);     // Happy face
  }
  else {
    lcd.write(1);     // Sad face
  }
}
lcd 2002 i2c

Once again, we need to be careful when we overwrite. If you overwrite ‘100’ with ‘99’ you will get ‘990’. Always fill all of the character positions with new characters. It is easy to write 3 spaces, reset the cursor and write the number.

You can set the cursor to flash, but I’ve never found it useful.

After many days and e-mails back and forth with AZ-Delivery in Germany, I found that there is a separate E-book for the backpack board, called LCD16x2_FC-113.pdf – but it is only available in German. 

It tells you to use the “New LiquidCrystal” library at: https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads/

and provides this minimal script (adapted for 20 characters and 4 lines) to get you started:

// Uses the new-liquidcrystal_i2c library
// https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads/
// This is the Test Script from AZ-Delivery matched with the 
// FC-113 Serial LCD Adapter Board Module I2C Interface

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

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

void setup()
{
  lcd.begin(20,4);
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print(">AZ-Delivery.de<");
  lcd.setCursor(0,1);
  lcd.print(">20x4 & FC-113!<");
}

void loop()
{
   lcd.setBacklight(HIGH);  // blink the backlight
   delay(1000);
   lcd.setBacklight(LOW);
   delay(1000);
}
printing through lcd

Conclusion

This screen is large and much easier to read. Its update rate is quite slow. If you re-write the whole screen in one go you can see a ripple across the display. The main drawback is that it cannot display graphical objects. There is a slight problem with the documentation supplied to English speaking customers by AZ-Delivery. However, the suppliers of the SSD1306 boards provided no help or documentation. Finding a suitable Arduino library which works properly could be a problem. The SSD1602 and 2004 LCD displays are very popular with Arduino users and the I2C backpack does leave more pins free for your projects.

Project suggestions

  • Define some more characters.
  • Connect up some sensors and display the values received on the screen. You could use temperature, humidity, air pressure, distance, tilt, or accelerometer sensors. 

Comparing the boards

SSD1306 128×64SSD1306 128×32LCD 2004
AdvantagesExcellent graphics3 sizes of charactersExcellent support libraryVery clear – high contrastOnly needs 2 pinsInexpensiveFree cablesExcellent graphics3 sizes of charactersExcellent support libraryVery clear – high contrastOnly needs 2 pins(2 in the packet)CheapVery easy to readLarge charactersEasy to see from a distanceOnly needs 2 pins with backpack
DisadvantagesA bit smallProbably too smallCannot display graphicsFinding a suitable library

Overview

I’ve been using LCD 1602 and LCD2004 boards for years and purchased them soon after buying my first Arduino. The backpack makes them even more useful. I’ve only been using the larger SSD1306 board for about 18 months but have found it even more useful. There is so much you can do with this small display. Really, it’s ‘horses for courses’, depending on your project and the viewing distance.

Related Posts

This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish. Accept Read More

Privacy & Cookies Policy