You are viewing an older revision! See the latest version

Text LCD Enhanced

This page describes an enhanced forked version of the basic driver code library for Text LCD panels using the 4-bit HD44780 LCD display controller.

/media/uploads/wim/_scaled_hd44780.jpeg

Note that there are several compatible LCD controllers around (e.g. KS0066, SPC780, SED1278, LC7985A). There are also controllers available that are compatible and provide additional features like an increased number of segment drivers for more characters or internal LCD contrast voltage generators (e.g. KS0073, KS0078, ST7036, SSD1803 and WS0010 (OLED driver)).

New features

  • Support for more LCD types
    • TextLCD::LCD8x1 8x1 LCD panel
    • TextLCD::LCD8x2 8x2 LCD panel
    • TextLCD::LCD8x2B 8x2 LCD panel (actually 16x1 in different layout)
    • TextLCD::LCD12x2 12x2 LCD panel
    • TextLCD::LCD12x4 12x4 LCD panel
    • TextLCD::LCD16x1 16x1 LCD panel (actually 8x2 in different layout)
    • TextLCD::LCD16x2 16x2 LCD panel (default)
    • TextLCD::LCD16x4 16x4 LCD panel
    • TextLCD::LCD20x2 20x2 LCD panel
    • TextLCD::LCD20x4 20x4 LCD panel
    • TextLCD::LCD24x2 24x2 LCD panel
    • TextLCD::LCD24x4 24x4 LCD panel (for KS0078 controller)
    • TextLCD::LCD40x2 40x2 LCD panel
    • TextLCD::LCD40x4 40x4 LCD panel
  • Support for Backlight control
  • Support for Cursor and/or Blinking current character
  • Support for User Defined Characters to display special symbols
  • Improved methods to get and set the memory address of the current character
  • Support for I2C PCF8574 Portexpander or SPI Portexpander as alternate interface to save on mbed pins

Background

The LCD driver HD44780 is designed for 2 rows of max 40 chars. Note that it needs some support drivers to control that maximum number of chars.

The address for the first char on the first line is 0x00. The address for the first char on the second line is 0x40. Four line displays are generally created by splitting the two line display and arranging the two parts above eachother. For example 2x40 is split in 2 parts of 2x20 and arranged as 4x20. The addresses for the 3rd and 4th line just continue where the split was made:

  • The address for the first char on the first line is 0x00, the last char is 0x13.
  • The address for the first char on the second line is 0x40, the last char is 0x53.
  • The address for the first char on the third line is 0x14, the last char is 0x27.
  • The address for the first char on the fourth line is 0x54, the last char is 0x67.

The original TextLCD lib uses the address(column,row) method to return the memory address. However, the method adds 0x80 to the returned addressvalue to include the 'set display datamemory address' command. This is rather confusing when you try to make sense of the actual address. See discussion here.

The enhanced library provides the getAddress(column,row) method to return the correct address. The original method is still provided for compatibility reasons.

Notes: The HD44780 is pretty flexible and variations of driverhardware and LCD glass layout may result in differences. Some 4 line displays actually use two controllers with separate enable pins. The HD44780 supports left/right shifting of memory locations (address) wrt displayposition. That changes the address of the char that is shown on a displaylocation.

LCD wiring

The new lib supports several ways of connecting with mbed:

  • Direct connection with mbed pins using a parallel bus (same as original TextLCD)
  • Serial connection using mbed I2C bus and a PCF8574 portexpander
  • Serial connection using mbed SPI bus and a 74595 shiftregister

Warning

The most commonly found connector on LCDs has 14 pins in a single row or as 2x7 pins. Note there may also be 2 additional pins for the backlight. The pinout for the LCD connector is fairly standard. However, exceptions are known. Always check the datasheet and verify by visual or conductivity testing of the GND pin. GND is normally connected to the metal frame around the LCD glass.

The 'standard' pinout has been used in the tables below.

/media/uploads/wim/_scaled_cbc0802e_rys.jpg

Warning

The contrast VO pin may have different behaviour on different displays, so you may need to experiment for your display to see anything. Adjustable contrast can be achieved with a 10k trim-pot in a voltage divider configuration: one side to Vcc, other side to GND, wiper to VO. Adjust until you see a top line of solid rectangles, then back off until they just disappear. Displays powered at 3V3 instead of 5V may need a (small) negative voltage at VO. One side of the trimpot is connected to the negative voltage instead of GND in that case.

Standard or fully compatible controllers should at least show a top row of black rectangles as soon as power and contrast voltage are OK even without any other connections or without running any software. However, note that some (almost) compatible controllers remain in powerdown mode and must be fully initialised before showing anything.

The specsheet of the standard HD44780 says that powersupply should be between 4.5V and 5.5V. These displays should connect pin 2 VCC to 5V as shown in the tables below. The datapins will typically work with the 3V3 logiclevels provided by the processor since the minimum threshold for logic high is 2V2. Powersupply range is often less tolerant. More recent HD44780 compatible controllers may also run on 3V3 powersupply. Check the datasheet for details.

Use decoupling capacitors (100uF parallel to 100nF) on your 5V or 3V3 powersupply for the display, especially when the power is provided my mbed. This will help avoid brief powerline dips which could lead to distorted characters on the display.

Parallel bus wiring

TextLCD pinsmbed pins
p1 GNDp1 0V
p2 VCCp39 5V Vout
p3 VOvia wiper of 10k pot
p4 RSp15
p5 RWp1 0V
p6 Ep16
p7 D0not connected
p8 D1not connected
p9 D2not connected
p10 D3not connected
p11 D4p17
p12 D5p18
p13 D6p19
p14 D7p20

The mbed pins can be supplied in the TextLCD constructor and may be changed. Some LCD displays will work OK with a 3V3 powersupply voltage. You may have to provide a small negative Vo in that case to get good contrast.

Serial I2C bus wiring

The advantage of using the I2C bus and a PCF8574 portexpander is that you save on mbed pins. This is even more true when you use the bus anyhow for other purposes. The small disadvantage that the I2C may be slower than a parallel bus is not a big problem for a slow device like a text display.

TextLCD pinsPCF8574 pinsmbed pins
p1 GNDp8 0Vp1 0V
p2 VCCp16 Vccp39 5V Vout
p3 VOvia wiper of 10k potnot connected
p4 RSp9 P4not connected
p5 RWp8 0Vp1 0V
p6 Ep10 P5not connected
p7 D0not connectednot connected
p8 D1not connectednot connected
p9 D2not connectednot connected
p10 D3not connectednot connected
p11 D4p4 P0not connected
p12 D5p5 P1not connected
p13 D6p6 P2not connected
p14 D7p7 P3not connected
not connectedp11 P6not connected
not connectedp12 P7not connected
not connectedp1 A0 GND or Vccnot connected
not connectedp2 A1 GND or Vccnot connected
not connectedp3 A2 GND or Vccnot connected
not connectedp15 SDAp9 or p28
not connectedp14 SCLp10 or p27

The mbed I2C bus must be supplied in the TextLCD constructor and may be changed (p9,p10) or (p28,p27). Note that you must provide pullup Rs of about 4K7. PCF8574 addresspins (p1,p2,p3) must be strapped to GND or Vcc to set the deviceAddress. That address must also be supplied in the LCDText constructor. The PCF8574 supports 8 different addresses (0x40..0x4E). The PCF8574A is similar but has a different baseaddress (0x70..0x7E). So in total you can connect upto 16 LCDs to one I2C bus!

  • Note1: Several other vendors supply clones of the PCF8574 (eg Texas Instruments)
  • Note2: You can change the connections between the PCF8574 pins and the LCD. Just update the appropriate pin definitions in TextLCD.h
  • Note3: You can roll-your-own PCF8574 interface or try to find one ready made on ebay. Search for TWI or I2C and LCD. You may have to change the pin definitions. An example pin definition table is given for the LCD2004 module from DFROBOT.

Example of ready made I2C expander for LCDs

/media/uploads/wim/_scaled_image2.jpg

Example schematic of homemade I2C expander for LCDs

/media/uploads/wim/_scaled_lcd1602_i2c_sch.png

Serial SPI bus wiring

The advantage of using the SPI bus rather than I2C is that the 74595 shiftregister is cheaper than a PCF8574. Disadvantages are that it needs more pins (MOSI, SCLK and CS). You also need a separate CS for every new device since SPI does not support a slaveAddress.

TextLCD pins74595 pinsmbed pins
p1 GNDp8 0Vp1 0V
p2 VCCp16 Vccp39 5V Vout
p3 VOvia wiper of 10k potnot connected
p4 RSp4 Q4not connected
p5 RWp8 0Vp1 0V
p6 Ep5 Q5not connected
p7 D0not connectednot connected
p8 D1not connectednot connected
p9 D2not connectednot connected
p10 D3not connectednot connected
p11 D4p15 Q0not connected
p12 D5p1 Q1not connected
p13 D6p2 Q2not connected
p14 D7p3 Q3not connected
not connectedp10 nMR Vccp39 5V
not connectedp11 SHCPp7 or p13 SCK
not connectedp12 STCPp8 CS
not connectedp14 DSp5 or p11 MOSI
not connectedp13 nOE GNDp1 0V

The mbed SPI bus must be supplied in the TextLCD constructor and may be changed (p5,NC,p7) or (p11,NC,p13). You must also provide a CS pin.

  • Note1: The 74HC595 should work on 3V3, but 5V is the prefered supplyvoltage
  • Note2: You can change the connections between the 74595 pins and the LCD. Just update the appropriate pin definitions in TextLCD.h

Wiring for 40x4 LCDs

The 40x4 LCDs are different from the regular types because they have two controllers. In fact this is a combination of two 40x2 displays. They have a different pinout with two enable lines (e1 and e2). The example below shows how to connect it using the SPI 74595 shiftregister.

TextLCD pins74595 pinsmbed pins
p1 D7p3 Q3not connected
p2 D6p2 Q2not connected
p3 D5p1 Q1not connected
p4 D4p15 Q0not connected
p5 D3not connectednot connected
p6 D2not connectednot connected
p7 D1not connectednot connected
p8 D0not connectednot connected
p9 E1p5 Q5not connected
p10 RWp8 0Vp1 0V
p11 RSp4 Q4not connected
p12 VOvia wiper of 10k potnot connected
p13 GNDp8 0Vp1 0V
p14 VCCp16 Vccp39 5V Vout
p15 E2p6 Q6not connected
p16 NC/Veenot connectednot connected
not connectedp10 nMR Vccp39 5V
not connectedp11 SHCPp7 or p13 SCK
not connectedp12 STCPp8 CS
not connectedp14 DSp5 or p11 MOSI
not connectedp13 nOE GNDp1 0V

The mbed SPI bus must be supplied in the TextLCD constructor and may be changed (p5,NC,p7) or (p11,NC,p13). You must also provide a CS pin.

  • Note1: The 74HC595 should work on 3V3, but 5V is the prefered supplyvoltage
  • Note2: You can change the connections between the 74595 pins and the LCD. Just update the appropriate pin definitions in TextLCD.h

The display can also be interfaced to the I2C portexpander or directly to mbed pins using an additional pin for E2.

TextLCD pinsPCF8574 pinsmbed pins
p1 D7p7 P3not connected
p2 D6p6 P2not connected
p3 D5p5 P1not connected
p4 D4p4 P0not connected
p5 D3not connectednot connected
p6 D2not connectednot connected
p7 D1not connectednot connected
p8 D0not connectednot connected
p9 E1p10 P5not connected
p10 RWp8 0Vp1 0V
p11 RSp9 P4not connected
p12 VOvia wiper of 10k potnot connected
p13 GNDp8 0Vp1 0V
p14 VCCp16 Vccp39 5V Vout
p15 E2p11 P6not connected
p16 NC/Veenot connectednot connected
not connectedp12 P7not connected
not connectedp1 A0 GND or Vccnot connected
not connectedp2 A1 GND or Vccnot connected
not connectedp3 A2 GND or Vccnot connected
not connectedp15 SDAp9 or p28
not connectedp14 SCLp10 or p27

Text LCD Enhanced Library

Import library

Public Types

enum LCDType {
LCD8x1 , LCD8x2 , LCD8x2B , LCD12x2 ,
LCD12x4 , LCD16x1 , LCD16x2 , LCD16x2B ,
LCD16x4 , LCD20x2 , LCD20x4 , LCD24x2 ,
LCD24x4 , LCD40x2 , LCD40x4
}

LCD panel format.

More...
enum LCDCtrl { HD44780 , WS0010 , ST7036 }

LCD Controller Device.

More...
enum LCDCursor { CurOff_BlkOff = 0x00, CurOn_BlkOff = 0x02, CurOff_BlkOn = 0x01, CurOn_BlkOn = 0x03 }

LCD Cursor control.

More...
enum LCDMode { DispOff = 0x00, DispOn = 0x04 }

LCD Display control.

More...
enum LCDBacklight { LightOff , LightOn }

LCD Backlight control.

More...

Public Member Functions

TextLCD (PinName rs, PinName e, PinName d4, PinName d5, PinName d6, PinName d7, LCDType type=LCD16x2, PinName bl=NC, PinName e2=NC, LCDCtrl ctrl=HD44780)
Create a TextLCD interface for using regular mbed pins.
TextLCD (I2C *i2c, char deviceAddress, LCDType type=LCD16x2, LCDCtrl ctrl=HD44780)
Create a TextLCD interface using an I2C PC8574 portexpander.
TextLCD (SPI *spi, PinName cs, LCDType type=LCD16x2, LCDCtrl ctrl=HD44780)
Create a TextLCD interface using an SPI 74595 portexpander.
int putc (int c)
Write a character to the LCD.
int printf (const char *format,...)
Write a formated string to the LCD.
void locate (int column, int row)
Locate to a screen column and row.
int getAddress (int column, int row)
Return the memoryaddress of screen column and row location.
void setAddress (int column, int row)
Set the memoryaddress of screen column and row location.
void cls ()
Clear the screen and locate to 0,0.
int rows ()
Return the number of rows.
int columns ()
Return the number of columns.
void setCursor ( LCDCursor cursorMode)
Set the Cursormode.
void setMode ( TextLCD::LCDMode displayMode)
Set the Displaymode.
void setBacklight ( TextLCD::LCDBacklight backlightMode)
Set the Backlight mode.
void setUDC (unsigned char c, char *udc_data)
Set User Defined Characters.

Example Code

// Hello World! for the TextLCD

#include "mbed.h"
#include "TextLCD.h"

// Host PC Communication channels
Serial pc(USBTX, USBRX); // tx, rx

// I2C Communication
I2C i2c_lcd(p28,p27); // SDA, SCL

// SPI Communication
SPI spi_lcd(p5, NC, p7); // MOSI, MISO, SCLK


//TextLCD lcd(p15, p16, p17, p18, p19, p20, TextLCD::LCD16x4); // rs, e, d4-d7 ok
//TextLCD lcd(p15, p16, p17, p18, p19, p20, TextLCD::LCD20x2); // rs, e, d4-d7 ok
//TextLCD lcd(p15, p16, p17, p18, p19, p20, TextLCD::LCD20x4); // rs, e, d4-d7 ok
//TextLCD lcd(p15, p16, p17, p18, p19, p20, TextLCD::LCD24x4); // rs, e, d4-d7 ok
//TextLCD lcd(p15, p16, p17, p18, p19, p20, TextLCD::LCD24x2); // rs, e, d4-d7 ok
//TextLCD lcd(p15, p16, p17, p18, p19, p20, TextLCD::LCD40x2); // rs, e, d4-d7 ok
TextLCD lcd(&i2c_lcd, 0x42, TextLCD::LCD20x4); // I2C bus, PCF8574 Slaveaddress, LCD Type ok
//TextLCD lcd(&i2c_lcd, 0x42, TextLCD::LCD16x2, TextLCD::WS0010); // I2C bus, PCF8574 addr, LCD Type, Ctrl Type
//TextLCD lcd(&spi_lcd, p8, TextLCD::LCD24x4); // SPI bus, CS pin, LCD Type ok
//TextLCD lcd(&spi_lcd, p8, TextLCD::LCD40x2); // SPI bus, CS pin, LCD Type ok
//TextLCD lcd(&spi_lcd, p8, TextLCD::LCD40x4); // SPI bus, CS pin, LCD Type ok


int main() {
    pc.printf("LCD Test. Columns=%d, Rows=%d\n\r", lcd.columns(), lcd.rows());
    
    for (int row=0; row<lcd.rows(); row++) {
      int col=0;
      
      pc.printf("MemAddr(Col=%d, Row=%d)=0x%02X\n\r", col, row, lcd.getAddress(col, row));      
//      lcd.putc('-');
      lcd.putc('0' + row);      
      
      for (col=1; col<lcd.columns()-1; col++) {    
        lcd.putc('*');
      }

      pc.printf("MemAddr(Col=%d, Row=%d)=0x%02X\n\r", col, row, lcd.getAddress(col, row));      
      lcd.putc('+');
        
    }    
    
// Show cursor as blinking character
    lcd.setCursor(TextLCD::CurOff_BlkOn);

// Set and show user defined characters. A maximum of 8 UDCs are supported by the HD44780.
// They are defined by a 5x7 bitpattern. 
    lcd.setUDC(0, (char *) udc_0);  // Show |>
    lcd.putc(0);    
    lcd.setUDC(1, (char *) udc_1);  // Show <|
    lcd.putc(1);    
    lcd.setUDC(2, (char *) udc_2);
    lcd.putc(2);    
    lcd.setUDC(3, (char *) udc_3);
    lcd.putc(3);    
    lcd.setUDC(4, (char *) udc_4);
    lcd.putc(4);    
    lcd.setUDC(5, (char *) udc_5);
    lcd.putc(5);    
    lcd.setUDC(6, (char *) udc_6);
    lcd.putc(6);    
    lcd.setUDC(7, (char *) udc_7);
    lcd.putc(7);  
 
}

The terminal will print the actual memory addresses like this:

LCD Test. Columns=20, Rows=4

MemAddr(Col=0, Row=0)=0x00

MemAddr(Col=19, Row=0)=0x13

MemAddr(Col=0, Row=1)=0x40

MemAddr(Col=19, Row=1)=0x53

MemAddr(Col=0, Row=2)=0x14

MemAddr(Col=19, Row=2)=0x27

MemAddr(Col=0, Row=3)=0x54

MemAddr(Col=19, Row=3)=0x67

User Defined Characters (UDC)

The HD44780 supports 8 different custom characters. They are shown by printing a charactervalue between 0 and 7. So rather than lcd.putc(‘a’) to display an ‘a’ you would call lcd.putc(0) to show the first user defined character. The UDC will display at the current cursorlocation. Any displaylocation where you have written a 0 will show that same UDC.

Obviously you first need to store a bitpattern before using this new UDC. All characters on the LCD consist of a 5 (horizontal) x 7 (vertical) pixel font. You can easily recognise that outline shape on the display by inspecting any character. There is in fact an 8th row at the bottom, but that is reserved for the cursor.

You define the 5x7 pattern by writing 8 bytes to 8 sequential UDC memory locations inside the LCD controller. The initial address for the UDC memory depends on which of the 8 available UDCs you want to define. The stored bit pattern will show on the display from top to bottom. So the first byte you store will later show up as the top row:

bit4 bit3 bit2 bit1 bit0.

Note that b7-b5 are don’t care since the font is only 5 pixels horizontal.

The second byte shows up as the next row of pixels etc.

The 8th byte should be all 0’s to avoid problems with the cursor.

Example from this site

/media/uploads/wim/_scaled_udc_map.jpg

The method lcd.setUDC(unsigned char c, char *udc_data) makes UDC storage more easy. The first parameter selects the UDC you want to define (should be between 0 and 7). The second param is a pointer to an array of 8 bytes that holds the pattern. Some sample patterns are defined in TextLCD.h

const char udc_Bat_Hi[] = {0x0E, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00};  // Battery Full

lcd.setUDC(0, (char *) udc_Bat_Hi);  // Define Bat High pattern for UDC index number 0
lcd.putc(0);                                        // Display the Bat High pattern by printing a 0

Decode the above example UDC by drawing an 8x8 grid and filling each cell that represents a 1 in the bitpattern above. You will see the ''battery full'' symbol appear.

You can redefine the UDCs at any time, but note that whenever you change the UDC pattern for an index all occurrences of that index showing on the display will instantly change to the new pattern.

Compatible or Enhanced LCD Controllers

There are several HD44780 compatible LCD controllers around (e.g. KS0066, SPC780, SED1278, LC7985A), which will work fine with this library. There are also controllers available that are compatible while providing additional features like an increased number of segment drivers for more characters or internal LCD contrast voltage generators (e.g. KS0073, KS0078, ST7036, SSD1803 and WS0010 (OLED driver)). Some of these controllers will work fine with the library without further software changes since they just remove the need for some supporting hardware that an HD44780 based display would have used. However, some new features require additional code and some displays won't even work without these specific new set-up instructions. The library has been extended further to support some of the features provided by alternative controllers (i.e. ST7036, and WS0010 OLED driver with internal DC/DC converters). The additional software is found in the init() method and a new parameter in the constructor is needed to identify the alternative controllertype and activate the new code.

[Testing is currently in progress...]

Examples

Some results are shown here:

LCD8x2B (actually 16x1, using SPI expander)

/media/uploads/wim/_scaled_img_2662.jpg

LCD16x1 (using SPI expander)

/media/uploads/wim/_scaled_img_2659.jpg

LCD16x2 (Vacuum Fluorescent Display (VFD) with controller that is compatible to HD44780, using SPI expander)

/media/uploads/wim/_scaled_img_2668.jpg

LCD20x2

/media/uploads/wim/_scaled_img_2636.jpg

LCD24x2

/media/uploads/wim/_scaled_img_2638.jpg

LCD40x2

/media/uploads/wim/_scaled_img_2637.jpg

LCD16x4

/media/uploads/wim/_scaled_img_2640.jpg

LCD20x4

/media/uploads/wim/_scaled_img_2642.jpg

LCD20x4 (I2C portexpander interface)

/media/uploads/wim/_scaled_img_2649.jpg

LCD24x4 (KS0078 controller)

/media/uploads/wim/_scaled_img_2646.jpg

LCD40x4 (2 controllers, SPI shiftregister interface)

/media/uploads/wim/_scaled_img_2655.jpg

User Defined Characters

/media/uploads/wim/_scaled_img_2645_-_copy.jpg

References


All wikipages