Circuitos_1
Circuitos_2

The circuits presented today allow the control of a LCD display that has a very common chip to be controlled by a micro-controller HD44780 or one that is compatible with this one.

There are several formats for this LCD, however the most used is the 16x2 (16 columns with 2 lines). There are also several colors for the LCDs.

Being an LCD display that receives the information that will present in serial format, this uses a very significant number of pins of a micro-controller.

Circuitos_3_LCDpins

The HD44780 is a module that exposes the following pins:

PinNameDescription
1VSSPower (GND)
2VCCPower (+5V)
3VEEContrast Adjustment
4RS0 = instruction input, 1 = data input
5R/W0 = write to the module, 1 - read from the module
6ENEnable Signal
7D0Data bus line 0 (LSB)
8D1Data bus line 1
9D2Data bus line 2
10D3Data bus line 3
11D4Data bus line 4
12D5Data bus line 5
13D6Data bus line 6
14D7Data bus line 7 (MSB)
15ALED Backlight +
16KLED Backlight -

To send data or commands to the module, follow these steps:

  1. Set the Enable to HIGH
  2. Set RS and D0-D7 to the desired values.
  3. Set the Enable to LOW

It is necessary to ensure that there is a timing of about 37 usec between the described operations.

The module has two modes of operation:

  • 8-bits mode
  • 4-bits mode

The first uses the 8 data pins and the second only 4 of them (D4 to D7).

In the circuits presented we will use the 4-bit mode using 6 pins (4 pins for the data, one for the Enable and another for the Instruction type). This saves 4 pins (D0 to D3 are not used) and the data is sent in two steps (two nibbles).

The HD44780 supports a set of commands that are documented in its datasheet, however as we will use a library it is not necessary to know in detail these Commands.

To decrease the number of pins used we will implement the communication via I2C or TWI. The second circuit presented has an Integrated - PCF8574 - which implements the I2C interface and allows the sending of commands to the HD44780 via this protocol. This uses only 2 pins of the I2C protocol (SDA, SCL) plus the 5V and GND.

In this circuit we will use 6 of the 8 pins that the PCF8574 makes available to us. The same 6 that were needed in the first circuit.

When we are using an Integrated I2C it allows you to configure the address by pins. The PCF8574 has 3 pins for this purpose A0 to A2.

These must be connected to GND or 5V (with a pull-up) to set the desired address. In our case they were all connected to GND. It gets integrated with the address 0x20.

Pin combination:

A2A1A0I2C Address
LLL0x20
LLH0x21
LHL0x22
LHH0x23
HLL0x24
HLH0x25
HHL0x26
HHH0x27

As shown on Malpartida’s site, the performance of the I2C interface is much lower than having the HD44780 directly connected to the AVR, but when it is intended porpuse is just showing information the pin savings may be required.

Schematic

Circuitos_3_Schematics

Bill of material (BOM)

Circuit 1:

  • 1x LCD (DS1)
  • 1x 330 Ohms Resistor (R1)
  • 1x 10K Variable Resistor (RV1)

Circuit 2:

  • 1x LCD (DS2)
  • 1x 330 Ohms Resistor (R2)
  • 1x 10K Variable Resistor (RV2)
  • 1x PCF8574 (U1)

IC Pin-out

Circuitos_4_Pinout

Sketch to run in CSEduino / Arduino

The code shown uses an external library that can be downloaded from this link, or locally on this link and it has to be installed in the Arduino IDE.

This library replaces the Arduino library including support for I2C communication among other things.

Code for the 4-bit serial connection:

#include <Wire.h>
#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

// Creat a set of new characters
byte smiley[8] = {
  0b00000,
  0b00000,
  0b01010,
  0b00000,
  0b00000,
  0b10001,
  0b01110,
  0b00000
};

byte armsUp[8] = {
  0b00100,
  0b01010,
  0b00100,
  0b10101,
  0b01110,
  0b00100,
  0b00100,
  0b01010
};

byte frownie[8] = {
  0b00000,
  0b00000,
  0b01010,
  0b00000,
  0b00000,
  0b00000,
  0b01110,
  0b10001
};

void setup()
{
  lcd.begin(16,2);               // initialize the lcd 

  lcd.createChar (0, smiley);    // load character to the LCD
  lcd.createChar (1, armsUp);    // load character to the LCD
  lcd.createChar (2, frownie);   // load character to the LCD

  lcd.home ();                   // go home
  lcd.print("Hello, CSEduino ");  
  lcd.setCursor ( 0, 1 );        // go to the next line
  lcd.print (" FORUM - fm   ");      
}

void loop()
{
  // Do a little animation by writing to the same location
  lcd.setCursor ( 14, 1 );
  lcd.print (char(2));
  delay (200);
  lcd.setCursor ( 14, 1 );
  lcd.print ( char(0));
  delay (200);
}

//Sketch uses 4,048 bytes (12%) of program storage space. Maximum is 32,256 bytes.
// Global variables use 327 bytes (15%) of dynamic memory, leaving 1,721 bytes for local variables. Maximum is 2,048 bytes.

Code for 4-bit connection over I2C:

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

#define BACKLIGHT_PIN     13

LiquidCrystal_I2C lcd(0x20, BACKLIGHT_PIN, POSITIVE);  // Set the LCD I2C address

// Creat a set of new characters
const uint8_t charBitmap[][8] = {
   { 0xc, 0x12, 0x12, 0xc, 0, 0, 0, 0 },
   { 0x6, 0x9, 0x9, 0x6, 0, 0, 0, 0 },
   { 0x0, 0x6, 0x9, 0x9, 0x6, 0, 0, 0x0 },
   { 0x0, 0xc, 0x12, 0x12, 0xc, 0, 0, 0x0 },
   { 0x0, 0x0, 0xc, 0x12, 0x12, 0xc, 0, 0x0 },
   { 0x0, 0x0, 0x6, 0x9, 0x9, 0x6, 0, 0x0 },
   { 0x0, 0x0, 0x0, 0x6, 0x9, 0x9, 0x6, 0x0 },
   { 0x0, 0x0, 0x0, 0xc, 0x12, 0x12, 0xc, 0x0 }
};

void setup()
{
   int charBitmapSize = (sizeof(charBitmap ) / sizeof (charBitmap[0]));

  // Switch on the backlight
  pinMode ( BACKLIGHT_PIN, OUTPUT );
  digitalWrite ( BACKLIGHT_PIN, HIGH );

  lcd.begin(16,2);               // initialize the lcd 

  for ( int i = 0; i < charBitmapSize; i++ )
   {
      lcd.createChar ( i, (uint8_t *)charBitmap[i] );
   }

  lcd.home ();                   // go home
  lcd.print("Hello, Altlab");  
  lcd.setCursor ( 0, 1 );        // go to the next line
  lcd.print("CSEduino LCD i2C");  
  delay ( 10000 );
}

void loop()
{
   lcd.home ();
   // Do a little animation by writing to the same location
   for ( int i = 0; i < 2; i++ )
   {
      for ( int j = 0; j < 16; j++ )
      {
         lcd.print (char(random(7)));
      }
      lcd.setCursor ( 0, 1 );
   }
   delay (200);
}
// Sketch uses 4,784 bytes (14%) of program storage space. Maximum is 32,256 bytes.
// Global variables use 374 bytes (18%) of dynamic memory, leaving 1,674 bytes for local variables. Maximum is 2,048 bytes.