The 2004 LCD Character Display - uraich/IoT4AQ GitHub Wiki

The 2004 LCD Character Display

Introduction

The 2004 LCD character display can show up to 4 lines of 20 characters each. Each character is defined in a 7x8 pixel matrix of which 5x8 are used (the other pixels provide the spacing between characters). The display therefore needs to have 7x8x20 pixels per row. The display is controlled by a Hitachi HD44780 which contains a ROM defining the pixel arrays for each character. It also has RAM space for 8 user defined characters. The characters to be displayed are stored in character RAM, commands like setting cursor, switching back light ... are accomplished through a command register.

2004 LCD display

On the top left of the photo you see a number of connection pads, ... and there are many! The module needs:

  • Power lines Vcc and GND
  • Eight data lines
  • R/W line
  • RS Register select.

This represents a lot of cabling! Fortunately an additional interface board exists, featuring a PCF8574 I2C expander chip, which is essentially a shift register with I2C interface. With 2 signals (SCL and SDA), 8 bit of data can be serially injected into the shift register and used in parallel.

Back side of 2004 LCD

The circuit diagram below shows the connections made by this board.

Circuit connecting pcf8574 to Hd44780

If you want to understand all the details, be ready for a bit of study: The HD44780 data sheet has 60 pages and the PCF8574 another 24.

The LiquidCrystal_I2C library

This library has been written for use with the HD44780 and PCF8574 combination and contains a large number of functions, used to drive the display. It allows us to

  • Write text to the display
  • Clear the display
  • switch the cursor on or off and to make it blink or not
  • Switch the back light on and off
  • Create custom characters and quite a few more.

In a typical program we must

  • include the LiquidCrystal_I2C.h file
  • create a LiquidCrystal_i2C object
  • initialize it
  • switch on the backlight
  • clear the display
  • set the cursor
  • print text

The program looks somehow like this:

#include <LiquidCrystal.h>
LiquidCrystal_I2C lcd =(0x27,20,4); // The PCF8574 has the I2C address 0x27, it has 20 character per row and 4 rows
                                    // These two lines go before setup()

void setup() {
    lcd.init();                     // initializes the controller
    lcd.backlight();                // switches back light on
    lcd.clear();
    lcd.setCursor(2,0);             // sets the cursor to the third position (we start counting from zero!)
                                    // of the first row
    lcd.print("Hello World!);       // display the text

In case of custom characters we have to define the individual pixels in an array:

uint8_t cross[8] = {0x0,0x1b,0xe,0x4,0xe,0x1b,0x0}; // defines a cross. Take a piece of checkered paper with 5x8 boxes. Extract the
                                                    // individual bits from the hex values and mark each box on the paper that has 
                                                    // a one bit associated with it
                                                    // example cross:
                                                    // 00000  : 0x00
                                                    // xxx01  : 0x1b
                                                    // 0xxx0  : 0x0e
                                                    // 00x00  : 0x04
                                                    // 0xxx0  : 0x0e
                                                    // xxx0x  : 0x1b
                                                    // 00000  : 0x00

cross

Once this is done we can save the character in character RAM:

lcd.create(0,cross); // save it at position zero in the character RAM

and finally we can use the character:

lcd.setCursor(5,1); // put the character at the 6th position on the second line
lcd.write(0);       // write the character

In case of the measurement data, we can write the frame in setup():

temperature:   °C  // ° is a user defined character
humidity:       %

and then only write the measured values at the wanted positions. This avoids flicker.

Converting numbers to strings

The LCD display only takes characters coded in ASCII (American Standard Code for Information Interchange) format.However, the measured values we get are integers or floats, which must be converted to text strings. There are different ways to accomplish this. Here we give just one example, using the itoa (integer to ascii) and dtostrf functions:

  • itoa(intValue,charBuf,numberBase)
  • dtostrf(floatValue,min_width,num_digits_after_decimal,string_buf)

Here is an example:

void loop() {
  float a = 123.45;
  int b = 345;
  char floatBuf[10];        // make sure your buffer is big enough
  char decIntBuf[10];       // in case of the float: 6 chars + terminating zero
  char hexIntBuf[10];

  itoa(b,decIntBuf,10);     // converts integer to string with base 10 (decimal)
  itoa(b,hexIntBuf,16);     // converts integer to string with base 16 (hex) 
  dtostrf(a,3,2,floatBuf);  // converts float to string

  Serial.print("Converted int to decimal: ");
  Serial.println(decIntBuf);

  Serial.print("Converted int to hex: 0x");
  Serial.println(hexIntBuf); 

  Serial.print("Converted float: ");
  Serial.println(floatBuf);

  Serial.println();
  delay(10000);
}