Updated for more display types. Fixed memoryaddress confusion in address() method. Added new getAddress() method. Added support for UDCs, Backlight control and other features such as control through I2C and SPI port expanders and controllers with native I2C and SPI interfaces. Refactored to fix issue with pins that are default declared as NC.

Dependents:   GPSDevice TestTextLCD SD to Flash Data Transfer DrumMachine ... more

Fork of TextLCD by Simon Ford

Example

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);                // RS, E, D4-D7, LCDType=LCD16x2, BL=NC, E2=NC, LCDTCtrl=HD44780
//TextLCD_SPI lcd(&spi_lcd, p8, TextLCD::LCD40x4);   // SPI bus, 74595 expander, CS pin, LCD Type  
TextLCD_I2C lcd(&i2c_lcd, 0x42, TextLCD::LCD20x4);  // I2C bus, PCF8574 Slaveaddress, LCD Type
//TextLCD_I2C lcd(&i2c_lcd, 0x42, TextLCD::LCD16x2, TextLCD::WS0010); // I2C bus, PCF8574 Slaveaddress, LCD Type, Device Type
//TextLCD_SPI_N lcd(&spi_lcd, p8, p9);               // SPI bus, CS pin, RS pin, LCDType=LCD16x2, BL=NC, LCDTCtrl=ST7032_3V3   
//TextLCD_I2C_N lcd(&i2c_lcd, ST7032_SA, TextLCD::LCD16x2, NC, TextLCD::ST7032_3V3); // I2C bus, Slaveaddress, LCD Type, BL=NC, LCDTCtrl=ST7032_3V3  

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);    

}

Handbook page

More info is here

Revision:
38:cbe275b0b647
Parent:
37:ce348c002929
Child:
39:e9c2319de9c5
--- a/TextLCD.cpp	Sun Mar 29 13:08:03 2015 +0000
+++ b/TextLCD.cpp	Sat Apr 18 11:33:02 2015 +0000
@@ -18,6 +18,8 @@
  *               2014, v15: WH, Added AC780 support, added I2C expander modules, fixed setBacklight() for inverted logic modules. Fixed bug in LCD_SPI_N define 
  *               2014, v16: WH, Added ST7070 and KS0073 support, added setIcon(), clrIcon() and setInvert() method for supported devices 
  *               2015, v17: WH, Clean up low-level _writeCommand() and _writeData(), Added support for alternative fonttables (eg PCF21XX), Added ST7066_ACM controller for ACM1602 module 
+ *               2015, v18: WH, Performance improvement I2C portexpander
+ *               2015, v19: WH, Fixed Adafruit I2C/SPI portexpander pinmappings, fixed SYDZ Backlight 
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -69,6 +71,8 @@
   *  @return none 
   */
 void TextLCD_Base::_init(_LCDDatalength dl) {
+
+  wait_ms(100);                  // Wait 100ms to ensure powered up
   
   // Select and configure second LCD controller when needed
   if(_type==LCD40x4) {
@@ -101,8 +105,6 @@
   int _lines=0;      // Set lines (Ext Instr Set), temporary variable.
 
     this->_setRS(false); // command mode
-    
-    wait_ms(20);         // Wait 20ms to ensure powered up
 
     if (dl == _LCD_DL_4) {
       // The Controller could be in 8 bit mode (power-on reset) or in 4 bit mode (warm reboot) at this point.
@@ -110,18 +112,18 @@
       // between the uP and the LCD can only write the 4 most significant bits (Most Significant Nibble, MSN).
       // In 4 bit mode the LCD expects the MSN first, followed by the LSN.
       //
-      //    Current state:               8 bit mode                |  4 bit mode, MSN is next      | 4 bit mode, LSN is next          
+      //    Current state:               8 bit mode                |      4 bit mode, MSN is next        | 4 bit mode, LSN is next          
                            //-------------------------------------------------------------------------------------------------                          
-      _writeNibble(0x3);   //  set 8 bit mode (MSN) and dummy LSN, |   set 8 bit mode (MSN),       |    set dummy LSN, 
-                           //  remains in 8 bit mode               |    change to 8 bit mode       |  remains in 4 bit mode
+      _writeNibble(0x3);   //  set 8 bit mode (MSN) and dummy LSN, |   set 8 bit mode (MSN),             |    set dummy LSN, 
+                           //  remains in 8 bit mode               |    remains in 4 bit mode            |  remains in 4 bit mode
       wait_ms(15);         //                           
      
-      _writeNibble(0x3);   //  set 8 bit mode and dummy LSN,       | set 8 bit mode and dummy LSN, |    set 8bit mode (MSN), 
-                           //  remains in 8 bit mode               |   remains in 8 bit mode       |  remains in 4 bit mode
+      _writeNibble(0x3);   //  set 8 bit mode (MSN) and dummy LSN, |      set dummy LSN,                 |    set 8bit mode (MSN), 
+                           //  remains in 8 bit mode               |   change to 8 bit mode              |  remains in 4 bit mode
       wait_ms(15);         // 
     
-      _writeNibble(0x3);   //  set 8 bit mode and dummy LSN,       | set 8 bit mode and dummy LSN, |    set dummy LSN, 
-                           //  remains in 8 bit mode               |   remains in 8 bit mode       |  change to 8 bit mode
+      _writeNibble(0x3);   //  set 8 bit mode (MSN) and dummy LSN, | set 8 bit mode (MSN) and dummy LSN, |    set dummy LSN, 
+                           //  remains in 8 bit mode               |   remains in 8 bit mode             |  change to 8 bit mode
       wait_ms(15);         // 
 
       // Controller is now in 8 bit mode
@@ -132,6 +134,10 @@
       // Controller is now in 4-bit mode
       // Note: 4/8 bit mode is ignored for most native SPI and I2C devices. They dont use the parallel bus.
       //       However, _writeNibble() method is void anyway for native SPI and I2C devices.
+    }
+    else {
+      // Reset in 8 bit mode, final Function set will follow 
+      _writeCommand(0x30); // Function set 0 0 1 DL=1 N F x x       
     }      
    
     // Device specific initialisations: DC/DC converter to generate VLCD or VLED, number of lines etc
@@ -1422,7 +1428,7 @@
 
 // Enable is Low
     this->_setEnable(true);        
-    this->_setData(value);        // Low nibble
+    this->_setData(value);        // Low nibble of value on D4..D7
     wait_us(1); // Data setup time        
     this->_setEnable(false);    
     wait_us(1); // Datahold time
@@ -2676,8 +2682,8 @@
     // No Hardware Enable pin       
     _e2 = NULL;                 //Construct dummy pin     
   }  
-
-  _init(_LCD_DL_4);   // Set Datalength to 4 bit for mbed bus interfaces
+  
+   _init(_LCD_DL_4);   // Set Datalength to 4 bit for mbed bus interfaces
 }
 
 /** Destruct a TextLCD interface for using regular mbed pins
@@ -2791,7 +2797,7 @@
 //  _writeRegister(OLAT,    0x00);  // Output Latch  
     
   // Init the portexpander bus
-  _lcd_bus = D_LCD_BUS_DEF;
+  _lcd_bus = LCD_BUS_I2C_DEF;
   
   // write the new data to the portexpander
   _writeRegister(GPIO, _lcd_bus);      
@@ -2799,7 +2805,7 @@
   // PCF8574 of PCF8574A portexpander
 
   // Init the portexpander bus
-  _lcd_bus = D_LCD_BUS_DEF;
+  _lcd_bus = LCD_BUS_I2C_DEF;
 
   // write the new data to the portexpander
   _i2c->write(_slaveAddress, &_lcd_bus, 1);    
@@ -2814,18 +2820,18 @@
 
   if(_ctrl_idx==_LCDCtrl_0) {
     if (value) {
-      _lcd_bus |= D_LCD_E;     // Set E bit 
+      _lcd_bus |= LCD_BUS_I2C_E;     // Set E bit 
     }  
     else {                    
-      _lcd_bus &= ~D_LCD_E;    // Reset E bit                     
+      _lcd_bus &= ~LCD_BUS_I2C_E;    // Reset E bit                     
     }  
   }
   else {
     if (value) {
-      _lcd_bus |= D_LCD_E2;    // Set E2 bit 
+      _lcd_bus |= LCD_BUS_I2C_E2;    // Set E2 bit 
     }  
     else {
-      _lcd_bus &= ~D_LCD_E2;   // Reset E2bit                     
+      _lcd_bus &= ~LCD_BUS_I2C_E2;   // Reset E2bit                     
     }  
   }    
 }    
@@ -2856,10 +2862,10 @@
 void TextLCD_I2C::_setRS(bool value) {
 
   if (value) {
-    _lcd_bus |= D_LCD_RS;    // Set RS bit 
+    _lcd_bus |= LCD_BUS_I2C_RS;    // Set RS bit 
   }  
   else {                    
-    _lcd_bus &= ~D_LCD_RS;   // Reset RS bit                     
+    _lcd_bus &= ~LCD_BUS_I2C_RS;   // Reset RS bit                     
   }
 
 #if (MCP23008==1)
@@ -2880,10 +2886,10 @@
 void TextLCD_I2C::_setBL(bool value) {
 
   if (value) {
-    _lcd_bus |= D_LCD_BL;    // Set BL bit 
+    _lcd_bus |= LCD_BUS_I2C_BL;    // Set BL bit 
   }  
   else {                    
-    _lcd_bus &= ~D_LCD_BL;   // Reset BL bit                     
+    _lcd_bus &= ~LCD_BUS_I2C_BL;   // Reset BL bit                     
   }
   
 #if (MCP23008==1)
@@ -2899,40 +2905,76 @@
 #endif                 
 }    
 
-
+#if(0)
+// New optimized v018
+// Test faster _writeByte 0.11s vs 0.27s for a 20x4 fillscreen (PCF8574), same as v018
+// Place the 4bit data in the databus shadowvalue
+// Used for mbed I2C bus expander
+const char _LCD_DATA_BITS[16] = {
+      0x00,
+      (                                                   LCD_BUS_I2C_D4),
+      (                                  LCD_BUS_I2C_D5                 ),
+      (                                  LCD_BUS_I2C_D5 | LCD_BUS_I2C_D4),
+      (                 LCD_BUS_I2C_D6                                  ),                  
+      (                 LCD_BUS_I2C_D6                  | LCD_BUS_I2C_D4),
+      (                 LCD_BUS_I2C_D6 | LCD_BUS_I2C_D5                 ),
+      (                 LCD_BUS_I2C_D6 | LCD_BUS_I2C_D5 | LCD_BUS_I2C_D4),
+      (LCD_BUS_I2C_D7                                                   ),
+      (LCD_BUS_I2C_D7                                   | LCD_BUS_I2C_D4),
+      (LCD_BUS_I2C_D7                  | LCD_BUS_I2C_D5                 ),
+      (LCD_BUS_I2C_D7                  | LCD_BUS_I2C_D5 | LCD_BUS_I2C_D4),                  
+      (LCD_BUS_I2C_D7 | LCD_BUS_I2C_D6                                  ),
+      (LCD_BUS_I2C_D7 | LCD_BUS_I2C_D6                  | LCD_BUS_I2C_D4),
+      (LCD_BUS_I2C_D7 | LCD_BUS_I2C_D6 | LCD_BUS_I2C_D5                 ),
+      (LCD_BUS_I2C_D7 | LCD_BUS_I2C_D6 | LCD_BUS_I2C_D5 | LCD_BUS_I2C_D4)
+    };
+void TextLCD_I2C::_setDataBits(int value) {
+
+  //Clear all databits
+  _lcd_bus &= ~LCD_BUS_I2C_MSK;
+
+  // Set bit by bit to support any mapping of expander portpins to LCD pins 
+  _lcd_bus |= _LCD_DATA_BITS[value & 0x0F];
+}    
+
+#else
+//orig v017
+// Test faster _writeByte 0.11s vs 0.27s for a 20x4 fillscreen (PCF8574)
 // Place the 4bit data in the databus shadowvalue
 // Used for mbed I2C bus expander
 void TextLCD_I2C::_setDataBits(int value) {
 
   // Set bit by bit to support any mapping of expander portpins to LCD pins 
   if (value & 0x01){
-    _lcd_bus |= D_LCD_D4;   // Set Databit 
+    _lcd_bus |= LCD_BUS_I2C_D4;   // Set Databit 
   }  
   else { 
-    _lcd_bus &= ~D_LCD_D4;  // Reset Databit
+    _lcd_bus &= ~LCD_BUS_I2C_D4;  // Reset Databit
   }  
 
   if (value & 0x02){
-    _lcd_bus |= D_LCD_D5;   // Set Databit 
+    _lcd_bus |= LCD_BUS_I2C_D5;   // Set Databit 
   }  
   else {
-    _lcd_bus &= ~D_LCD_D5;  // Reset Databit
+    _lcd_bus &= ~LCD_BUS_I2C_D5;  // Reset Databit
   }  
 
   if (value & 0x04) {
-    _lcd_bus |= D_LCD_D6;   // Set Databit 
+    _lcd_bus |= LCD_BUS_I2C_D6;   // Set Databit 
   }  
   else {                    
-    _lcd_bus &= ~D_LCD_D6;  // Reset Databit
+    _lcd_bus &= ~LCD_BUS_I2C_D6;  // Reset Databit
   }  
 
   if (value & 0x08) {
-    _lcd_bus |= D_LCD_D7;   // Set Databit 
+    _lcd_bus |= LCD_BUS_I2C_D7;   // Set Databit 
   }  
   else {
-    _lcd_bus &= ~D_LCD_D7;  // Reset Databit
+    _lcd_bus &= ~LCD_BUS_I2C_D7;  // Reset Databit
   }                                      
 }    
+#endif
+
 
 // Place the 4bit data on the databus
 // Used for mbed pins, I2C bus expander or SPI shifregister
@@ -3032,8 +3074,7 @@
 TextLCD_SPI::TextLCD_SPI(SPI *spi, PinName cs, LCDType type, LCDCtrl ctrl) :
                          TextLCD_Base(type, ctrl), 
                          _spi(spi),        
-                         _cs(cs) {      
-        
+                         _cs(cs) {              
   // Init cs
   _cs = 1;  
 
@@ -3043,8 +3084,10 @@
   _spi->frequency(500000);    
   //_spi.frequency(1000000);    
 
+  wait_ms(100);                   // Wait 100ms to ensure LCD powered up
+  
   // Init the portexpander bus
-  _lcd_bus = D_LCD_BUS_DEF;
+  _lcd_bus = LCD_BUS_SPI_DEF;
   
   // write the new data to the portexpander
   _cs = 0;  
@@ -3060,18 +3103,18 @@
 
   if(_ctrl_idx==_LCDCtrl_0) {
     if (value) {
-      _lcd_bus |= D_LCD_E;     // Set E bit 
+      _lcd_bus |= LCD_BUS_SPI_E;     // Set E bit 
     }  
     else {                    
-      _lcd_bus &= ~D_LCD_E;    // Reset E bit                     
+      _lcd_bus &= ~LCD_BUS_SPI_E;    // Reset E bit                     
     }  
   }
   else {
     if (value) {
-      _lcd_bus |= D_LCD_E2;    // Set E2 bit 
+      _lcd_bus |= LCD_BUS_SPI_E2;    // Set E2 bit 
     }  
     else {
-      _lcd_bus &= ~D_LCD_E2;   // Reset E2 bit                     
+      _lcd_bus &= ~LCD_BUS_SPI_E2;   // Reset E2 bit                     
     }  
   }
                   
@@ -3086,10 +3129,10 @@
 void TextLCD_SPI::_setRS(bool value) {
 
   if (value) {
-    _lcd_bus |= D_LCD_RS;    // Set RS bit 
+    _lcd_bus |= LCD_BUS_SPI_RS;    // Set RS bit 
   }  
   else {                    
-    _lcd_bus &= ~D_LCD_RS;   // Reset RS bit                     
+    _lcd_bus &= ~LCD_BUS_SPI_RS;   // Reset RS bit                     
   }
      
   // write the new data to the SPI portexpander
@@ -3103,10 +3146,10 @@
 void TextLCD_SPI::_setBL(bool value) {
 
   if (value) {
-    _lcd_bus |= D_LCD_BL;    // Set BL bit 
+    _lcd_bus |= LCD_BUS_SPI_BL;    // Set BL bit 
   }  
   else {
-    _lcd_bus &= ~D_LCD_BL;   // Reset BL bit                     
+    _lcd_bus &= ~LCD_BUS_SPI_BL;   // Reset BL bit                     
   }
       
   // write the new data to the SPI portexpander
@@ -3121,31 +3164,31 @@
 
   // Set bit by bit to support any mapping of expander portpins to LCD pins
   if (value & 0x01) {
-    _lcd_bus |= D_LCD_D4;   // Set Databit 
+    _lcd_bus |= LCD_BUS_SPI_D4;   // Set Databit 
   }  
   else {                    
-    _lcd_bus &= ~D_LCD_D4;  // Reset Databit                     
+    _lcd_bus &= ~LCD_BUS_SPI_D4;  // Reset Databit                     
   }
   
   if (value & 0x02) {
-    _lcd_bus |= D_LCD_D5;   // Set Databit 
+    _lcd_bus |= LCD_BUS_SPI_D5;   // Set Databit 
   }  
   else {
-    _lcd_bus &= ~D_LCD_D5;  // Reset Databit                     
+    _lcd_bus &= ~LCD_BUS_SPI_D5;  // Reset Databit                     
   }
   
   if (value & 0x04) {
-    _lcd_bus |= D_LCD_D6;   // Set Databit 
+    _lcd_bus |= LCD_BUS_SPI_D6;   // Set Databit 
   }  
   else {
-    _lcd_bus &= ~D_LCD_D6;  // Reset Databit                     
+    _lcd_bus &= ~LCD_BUS_SPI_D6;  // Reset Databit                     
   }
   
   if (value & 0x08) {
-    _lcd_bus |= D_LCD_D7;   // Set Databit 
+    _lcd_bus |= LCD_BUS_SPI_D7;   // Set Databit 
   }  
   else {
-    _lcd_bus &= ~D_LCD_D7;  // Reset Databit
+    _lcd_bus &= ~LCD_BUS_SPI_D7;  // Reset Databit
   }  
                     
   // write the new data to the SPI portexpander