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:
21:9eb628d9e164
Parent:
20:e0da005a777f
Child:
22:35742ec80c24
--- a/TextLCD.cpp	Mon May 13 19:29:13 2013 +0000
+++ b/TextLCD.cpp	Tue Apr 01 21:30:25 2014 +0000
@@ -7,6 +7,7 @@
  *               2013, v05: WH, Added support for 8x2B, added some UDCs   
  *               2013, v06: WH, Added support for devices that use internal DC/DC converters 
  *               2013, v07: WH, Added support for backlight and include portdefinitions for LCD2004 Module from DFROBOT 
+ *               2014, v08: WH, Refactored in Base in Derived Classes to deal with mbed lib change regarding 'NC' defined pins 
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -30,105 +31,23 @@
 #include "TextLCD.h"
 #include "mbed.h"
 
-
-/* Create a TextLCD interface for using regular mbed pins
- *
- * @param rs     Instruction/data control line
- * @param e      Enable line (clock)
- * @param d4-d7  Data lines for using as a 4-bit interface
- * @param type   Sets the panel size/addressing mode (default = LCD16x2)
- * @param bl     Backlight control line (optional, default = NC)  
- * @param e2     Enable2 line (clock for second controller, LCD40x4 only) 
- * @param ctrl   LCD controller (default = HD44780)   
- */ 
-TextLCD::TextLCD(PinName rs, PinName e,
-                 PinName d4, PinName d5, PinName d6, PinName d7,
-                 LCDType type, PinName bl, PinName e2, LCDCtrl ctrl) : _rs(rs), _e(e), _bl(bl), _e2(e2),
-                                                                       _d(d4, d5, d6, d7),
-                                                                       _cs(NC), 
-                                                                       _type(type),
-                                                                       _ctrl(ctrl) {
-
-  _busType = _PinBus;
-
-  _init();
-
-}
-
-/* Create a TextLCD interface using an I2C PC8574 portexpander
- *
- * @param i2c             I2C Bus
- * @param deviceAddress   I2C slave address (PCF8574)
- * @param type            Sets the panel size/addressing mode (default = LCD16x2)
- * @param ctrl            LCD controller (default = HD44780)    
- */
-TextLCD::TextLCD(I2C *i2c, char deviceAddress, LCDType type, LCDCtrl ctrl) :
-        _rs(NC), _e(NC), _bl(NC), _e2(NC),
-        _d(NC),
-        _i2c(i2c),        
-        _cs(NC),
-        _type(type), 
-        _ctrl(ctrl) {        
-         
-  _slaveAddress = deviceAddress;
-  _busType = _I2CBus;
-
-  
-  // Init the portexpander bus
-  _lcd_bus = D_LCD_BUS_DEF;
-  
-  // write the new data to the portexpander
-  _i2c->write(_slaveAddress, &_lcd_bus, 1);    
-
-  _init();
-    
-}
-
- /* Create a TextLCD interface using an SPI 74595 portexpander
+/** Create a TextLCD_Base interface
   *
-  * @param spi             SPI Bus
-  * @param cs              chip select pin (active low)
-  * @param type            Sets the panel size/addressing mode (default = LCD16x2)
-  * @param ctrl            LCD controller (default = HD44780)      
+  * @param type  Sets the panel size/addressing mode (default = LCD16x2)
+  * @param ctrl  LCD controller (default = HD44780)           
   */
-TextLCD::TextLCD(SPI *spi, PinName cs, LCDType type, LCDCtrl ctrl) :
-        _rs(NC), _e(NC), _bl(NC), _e2(NC),
-        _d(NC),
-        _spi(spi),        
-        _cs(cs),
-        _type(type),
-        _ctrl(ctrl) {                
-        
-  _busType = _SPIBus;
-
-  // Setup the spi for 8 bit data, low steady state clock,
-  // rising edge capture, with a 500KHz or 1MHz clock rate  
-  _spi->format(8,0);
-  _spi->frequency(500000);    
-  //_spi.frequency(1000000);    
-
-
-  // Init the portexpander bus
-  _lcd_bus = D_LCD_BUS_DEF;
-  
-  // write the new data to the portexpander
-  _setCS(false);  
-  _spi->write(_lcd_bus);   
-  _setCS(true);  
-  
-  _init();
-    
+TextLCD_Base::TextLCD_Base(LCDType type, LCDCtrl ctrl) : _type(type), _ctrl(ctrl) {
 }
 
 
-/*  Init the LCD Controller(s)
- *  Clear display 
- */
-void TextLCD::_init() {
+/**  Init the LCD Controller(s)
+  *  Clear display 
+  */
+void TextLCD_Base::_init() {
   
   // Select and configure second LCD controller when needed
   if(_type==LCD40x4) {
-    _ctrl_idx=TextLCD::_LCDCtrl_1; // Select 2nd controller
+    _ctrl_idx=_LCDCtrl_1; // Select 2nd controller
     
     _initCtrl();                   // Init 2nd controller
     
@@ -140,7 +59,7 @@
   }
     
   // Select and configure primary LCD controller
-  _ctrl_idx=TextLCD::_LCDCtrl_0; // Select primary controller  
+  _ctrl_idx=_LCDCtrl_0; // Select primary controller  
 
   _initCtrl();                   // Init primary controller
   
@@ -152,13 +71,13 @@
     
 } 
 
-/*  Init the LCD controller
- *  4-bit mode, number of lines, fonttype, no cursor etc
- *  
- */
-void TextLCD::_initCtrl() {
+/**  Init the LCD controller
+  *  4-bit mode, number of lines, fonttype, no cursor etc
+  *  
+  */
+void TextLCD_Base::_initCtrl() {
 
-    _setRS(false);      // command mode
+    this->_setRS(false);      // command mode
     
     wait_ms(20);        // Wait 20ms to ensure powered up
 
@@ -275,20 +194,21 @@
 
 //    _writeCommand(0x0C); // Display Ctrl 0000 1 D C B
 //                         //   Display On, Cursor Off, Blink Off   
-    setCursor(TextLCD::CurOff_BlkOff);     
-    setMode(TextLCD::DispOn);     
+    setCursor(CurOff_BlkOff);     
+    setMode(DispOn);     
 }
 
 
-// Clear the screen, Cursor home. 
-void TextLCD::cls() {
+/** Clear the screen, Cursor home. 
+  */
+void TextLCD_Base::cls() {
 
   // Select and configure second LCD controller when needed
   if(_type==LCD40x4) {
-    _ctrl_idx=TextLCD::_LCDCtrl_1; // Select 2nd controller
+    _ctrl_idx=_LCDCtrl_1; // Select 2nd controller
 
     // Second LCD controller Cursor always Off
-    _setCursorAndDisplayMode(_currentMode, TextLCD::CurOff_BlkOff);
+    _setCursorAndDisplayMode(_currentMode, CurOff_BlkOff);
 
     // Second LCD controller Clearscreen
     _writeCommand(0x01); // cls, and set cursor to 0    
@@ -297,7 +217,7 @@
                      // Since we are not using the Busy flag, Lets be safe and take 10 ms
 
   
-    _ctrl_idx=TextLCD::_LCDCtrl_0; // Select primary controller
+    _ctrl_idx=_LCDCtrl_0; // Select primary controller
   }
   
   // Primary LCD controller Clearscreen
@@ -315,8 +235,9 @@
   _column=0;
 }
 
-// Move cursor to selected row and column
-void TextLCD::locate(int column, int row) {
+/** Move cursor to selected row and column
+  */
+void TextLCD_Base::locate(int column, int row) {
     
    // setAddress() does all the heavy lifting:
    //   check column and row sanity, 
@@ -328,8 +249,9 @@
 }
     
 
-// Write a single character (Stream implementation)
-int TextLCD::_putc(int value) {
+/** Write a single character (Stream implementation)
+  */
+int TextLCD_Base::_putc(int value) {
   int addr;
     
     if (value == '\n') {
@@ -366,250 +288,19 @@
 
 
 // get a single character (Stream implementation)
-int TextLCD::_getc() {
+int TextLCD_Base::_getc() {
     return -1;
 }
 
-// Set E pin (or E2 pin)
-// Used for mbed pins, I2C bus expander or SPI shifregister
-void TextLCD::_setEnable(bool value) {
-
-  switch(_busType) {
-    case _PinBus : 
-                    if(_ctrl_idx==TextLCD::_LCDCtrl_0) {
-                      if (value)
-                        _e  = 1;    // Set E bit 
-                      else  
-                        _e  = 0;    // Reset E bit  
-                    }    
-                    else {   
-                      if (value)
-                        _e2 = 1;    // Set E2 bit 
-                      else  
-                        _e2 = 0;    // Reset E2 bit  
-                    }    
-
-                    break;  
-    
-    case _I2CBus : 
-    
-                   if(_ctrl_idx==TextLCD::_LCDCtrl_0) {
-                     if (value)
-                       _lcd_bus |= D_LCD_E;     // Set E bit 
-                     else                     
-                       _lcd_bus &= ~D_LCD_E;    // Reset E bit                     
-                   }
-                   else {
-                     if (value)
-                       _lcd_bus |= D_LCD_E2;    // Set E2 bit 
-                     else                     
-                       _lcd_bus &= ~D_LCD_E2;   // Reset E2bit                     
-                   }    
-
-                   // write the new data to the I2C portexpander
-                   _i2c->write(_slaveAddress, &_lcd_bus, 1);    
-
-                   break;  
-    
-    case _SPIBus :
-                   if(_ctrl_idx==TextLCD::_LCDCtrl_0) {
-                     if (value)
-                       _lcd_bus |= D_LCD_E;     // Set E bit 
-                     else                     
-                       _lcd_bus &= ~D_LCD_E;    // Reset E bit                     
-                   }
-                   else {
-                     if (value)
-                       _lcd_bus |= D_LCD_E2;    // Set E2 bit 
-                     else                     
-                       _lcd_bus &= ~D_LCD_E2;   // Reset E2 bit                     
-                   }
-                  
-                   // write the new data to the SPI portexpander
-                   _setCS(false);  
-                   _spi->write(_lcd_bus);   
-                   _setCS(true);  
-  
-                   break;
-  }
-}    
-
-// Set RS pin
-// Used for mbed pins, I2C bus expander or SPI shifregister
-void TextLCD::_setRS(bool value) {
-
-  switch(_busType) {
-    case _PinBus : 
-                    if (value)
-                      _rs  = 1;    // Set RS bit 
-                    else  
-                      _rs  = 0;    // Reset RS bit 
-
-                    break;  
-    
-    case _I2CBus : 
-                   if (value)
-                     _lcd_bus |= D_LCD_RS;    // Set RS bit 
-                   else                     
-                     _lcd_bus &= ~D_LCD_RS;   // Reset RS bit                     
-
-                   // write the new data to the I2C portexpander
-                   _i2c->write(_slaveAddress, &_lcd_bus, 1);    
-                   
-                   break;
-                       
-    case _SPIBus :
-                   if (value)
-                     _lcd_bus |= D_LCD_RS;    // Set RS bit 
-                   else                     
-                     _lcd_bus &= ~D_LCD_RS;   // Reset RS bit                     
-      
-                   // write the new data to the SPI portexpander
-                   _setCS(false);  
-                   _spi->write(_lcd_bus);   
-                   _setCS(true);  
-     
-                   break;
-  }
-
-}    
-
-// Set BL pin
-// Used for mbed pins, I2C bus expander or SPI shifregister
-void TextLCD::_setBL(bool value) {
-
-  switch(_busType) {
-    case _PinBus : 
-                    if (value)
-                      _bl  = 1;    // Set BL bit 
-                    else  
-                      _bl  = 0;    // Reset BL bit 
-
-                    break;  
-    
-    case _I2CBus : 
-                   if (value)
-                     _lcd_bus |= D_LCD_BL;    // Set BL bit 
-                   else                     
-                     _lcd_bus &= ~D_LCD_BL;   // Reset BL bit                     
-
-                   // write the new data to the I2C portexpander
-                   _i2c->write(_slaveAddress, &_lcd_bus, 1);    
-                   
-                   break;
-                       
-    case _SPIBus :
-                   if (value)
-                     _lcd_bus |= D_LCD_BL;    // Set BL bit 
-                   else                     
-                     _lcd_bus &= ~D_LCD_BL;   // Reset BL bit                     
-      
-                   // write the new data to the SPI portexpander
-                   _setCS(false);  
-                   _spi->write(_lcd_bus);   
-                   _setCS(true);  
-     
-                   break;
-  }
-
-}    
-
-
-
-// Place the 4bit data on the databus
-// Used for mbed pins, I2C bus expander or SPI shifregister
-void TextLCD::_setData(int value) {
-  int data;
-  
-  switch(_busType) {
-    case _PinBus : 
-                    _d = value & 0x0F;   // Write Databits 
-
-                    break;  
-    
-    case _I2CBus : 
-                    data = value & 0x0F;
-                    if (data & 0x01)
-                      _lcd_bus |= D_LCD_D4;   // Set Databit 
-                    else                     
-                      _lcd_bus &= ~D_LCD_D4;  // Reset Databit                     
-
-                    if (data & 0x02)
-                      _lcd_bus |= D_LCD_D5;   // Set Databit 
-                    else                     
-                      _lcd_bus &= ~D_LCD_D5;  // Reset Databit                     
-
-                    if (data & 0x04)
-                      _lcd_bus |= D_LCD_D6;   // Set Databit 
-                    else                     
-                      _lcd_bus &= ~D_LCD_D6;  // Reset Databit                     
-
-                    if (data & 0x08)
-                      _lcd_bus |= D_LCD_D7;   // Set Databit 
-                    else                     
-                      _lcd_bus &= ~D_LCD_D7;  // Reset Databit                     
-                    
-                    // write the new data to the I2C portexpander
-                    _i2c->write(_slaveAddress, &_lcd_bus, 1);  
-                   
-                    break;                    
-                    
-    case _SPIBus :
-    
-                    data = value & 0x0F;
-                    if (data & 0x01)
-                      _lcd_bus |= D_LCD_D4;   // Set Databit 
-                    else                     
-                      _lcd_bus &= ~D_LCD_D4;  // Reset Databit                     
-
-                    if (data & 0x02)
-                      _lcd_bus |= D_LCD_D5;   // Set Databit 
-                    else                     
-                      _lcd_bus &= ~D_LCD_D5;  // Reset Databit                     
-
-                    if (data & 0x04)
-                      _lcd_bus |= D_LCD_D6;   // Set Databit 
-                    else                     
-                      _lcd_bus &= ~D_LCD_D6;  // Reset Databit                     
-
-                    if (data & 0x08)
-                      _lcd_bus |= D_LCD_D7;   // Set Databit 
-                    else                     
-                      _lcd_bus &= ~D_LCD_D7;  // Reset Databit                     
-                    
-                   // write the new data to the SPI portexpander
-                   _setCS(false);  
-                   _spi->write(_lcd_bus);   
-                   _setCS(true);  
-        
-                   break;
-  }
-
-}    
-
-
-// Set CS line.
-// Only used for SPI bus
-void TextLCD::_setCS(bool value) {
-
-  if (value) {   
-    _cs  = 1;    // Set CS pin 
-  }  
-  else  
-    _cs  = 0;    // Reset CS pin 
-  
-}
-
 
 // Write a nibble using the 4-bit interface
-// Used for mbed pins, I2C bus expander or SPI shifregister
-void TextLCD::_writeNibble(int value) {
+void TextLCD_Base::_writeNibble(int value) {
 
 // Enable is Low
-    _setEnable(true);        
-    _setData(value & 0x0F);   // Low nibble
+    this->_setEnable(true);        
+    this->_setData(value & 0x0F);   // Low nibble
     wait_us(1); // Data setup time        
-    _setEnable(false);    
+    this->_setEnable(false);    
     wait_us(1); // Datahold time
 
 // Enable is Low
@@ -618,41 +309,42 @@
 
 
 // Write a byte using the 4-bit interface
-// Used for mbed pins, I2C bus expander or SPI shifregister
-void TextLCD::_writeByte(int value) {
+void TextLCD_Base::_writeByte(int value) {
 
 // Enable is Low
-    _setEnable(true);          
-    _setData(value >> 4);   // High nibble
+    this->_setEnable(true);          
+    this->_setData(value >> 4);   // High nibble
     wait_us(1); // Data setup time    
-    _setEnable(false);   
+    this->_setEnable(false);   
     wait_us(1); // Data hold time
     
-    _setEnable(true);        
-    _setData(value >> 0);   // Low nibble
+    this->_setEnable(true);        
+    this->_setData(value >> 0);   // Low nibble
     wait_us(1); // Data setup time        
-    _setEnable(false);    
+    this->_setEnable(false);    
     wait_us(1); // Datahold time
 
 // Enable is Low
 
 }
 
-void TextLCD::_writeCommand(int command) {
+// Write a command byte to the LCD controller
+void TextLCD_Base::_writeCommand(int command) {
 
-    _setRS(false);        
+    this->_setRS(false);        
     wait_us(1);  // Data setup time for RS       
     
-    _writeByte(command);   
+    this->_writeByte(command);   
     wait_us(40); // most instructions take 40us            
 }
 
-void TextLCD::_writeData(int data) {
+// Write a data byte to the LCD controller
+void TextLCD_Base::_writeData(int data) {
 
-    _setRS(true);            
+    this->_setRS(true);            
     wait_us(1);  // Data setup time for RS 
         
-    _writeByte(data);
+    this->_writeByte(data);
     wait_us(40); // data writes take 40us                
 }
 
@@ -662,7 +354,7 @@
 // It is confusing since it returns the memoryaddress or-ed with the set memorycommand 0x80.
 // Left it in here for compatibility with older code. New applications should use getAddress() instead.
 // 
-int TextLCD::_address(int column, int row) {
+int TextLCD_Base::_address(int column, int row) {
     switch (_type) {
         case LCD20x4:
             switch (row) {
@@ -688,13 +380,13 @@
 
 // This replaces the original _address() method.
 // Left it in here for compatibility with older code. New applications should use getAddress() instead.
-int TextLCD::_address(int column, int row) {
+int TextLCD_Base::_address(int column, int row) {
   return 0x80 | getAddress(column, row);
 }
 
 // This is new method to return the memory address based on row, column and displaytype.
 //
-int TextLCD::getAddress(int column, int row) {
+int TextLCD_Base::getAddress(int column, int row) {
 
     switch (_type) {
         case LCD8x1:
@@ -784,7 +476,7 @@
             if (_ctrl_idx != _LCDCtrl_0) {
 
               // Second LCD controller Cursor Off
-              _setCursorAndDisplayMode(_currentMode, TextLCD::CurOff_BlkOff);    
+              _setCursorAndDisplayMode(_currentMode, CurOff_BlkOff);    
 
               // Select primary controller
               _ctrl_idx = _LCDCtrl_0;
@@ -800,7 +492,7 @@
             // Test to see if we need to switch between controllers  
             if (_ctrl_idx != _LCDCtrl_1) {
               // Primary LCD controller Cursor Off
-              _setCursorAndDisplayMode(_currentMode, TextLCD::CurOff_BlkOff);    
+              _setCursorAndDisplayMode(_currentMode, CurOff_BlkOff);    
 
               // Select secondary controller
               _ctrl_idx = _LCDCtrl_1;
@@ -821,7 +513,7 @@
 
 // Set row, column and update memoryaddress.
 //
-void TextLCD::setAddress(int column, int row) {
+void TextLCD_Base::setAddress(int column, int row) {
    
 // Sanity Check column
     if (column < 0) {
@@ -848,7 +540,7 @@
     _writeCommand(0x80 | addr);
 }
 
-int TextLCD::columns() {
+int TextLCD_Base::columns() {
     switch (_type) {
         case LCD8x1:
         case LCD8x2:
@@ -883,7 +575,7 @@
     }
 }
 
-int TextLCD::rows() {
+int TextLCD_Base::rows() {
     switch (_type) {
         case LCD8x1: 
         case LCD16x1:         
@@ -914,7 +606,7 @@
 
 
 // Set the Cursor Mode (Cursor Off & Blink Off, Cursor On & Blink Off, Cursor Off & Blink On, Cursor On & Blink On
-void TextLCD::setCursor(TextLCD::LCDCursor cursorMode) { 
+void TextLCD_Base::setCursor(LCDCursor cursorMode) { 
 
   // Save new cursor mode, needed when 2 controllers are in use or when display is switched off/on
   _currentCursor = cursorMode;
@@ -925,35 +617,35 @@
 }
 
 // Set the Displaymode (On/Off)
-void TextLCD::setMode(TextLCD::LCDMode displayMode) { 
+void TextLCD_Base::setMode(LCDMode displayMode) { 
 
   // Save new displayMode, needed when 2 controllers are in use or when cursor is changed
   _currentMode = displayMode;
     
   // Select and configure second LCD controller when needed
   if(_type==LCD40x4) {
-    if (_ctrl_idx==TextLCD::_LCDCtrl_0) {
+    if (_ctrl_idx==_LCDCtrl_0) {      
       // Configure primary LCD controller
       _setCursorAndDisplayMode(_currentMode, _currentCursor);
 
       // Select 2nd controller
-      _ctrl_idx=TextLCD::_LCDCtrl_1;
+      _ctrl_idx=_LCDCtrl_1;
   
       // Configure secondary LCD controller    
-      _setCursorAndDisplayMode(_currentMode, TextLCD::CurOff_BlkOff);
+      _setCursorAndDisplayMode(_currentMode, CurOff_BlkOff);
 
       // Restore current controller
-      _ctrl_idx=TextLCD::_LCDCtrl_0;       
+      _ctrl_idx=_LCDCtrl_0;       
     }
     else {
       // Select primary controller
-      _ctrl_idx=TextLCD::_LCDCtrl_0;
+      _ctrl_idx=_LCDCtrl_0;
     
       // Configure primary LCD controller
-      _setCursorAndDisplayMode(_currentMode, TextLCD::CurOff_BlkOff);
+      _setCursorAndDisplayMode(_currentMode, CurOff_BlkOff);
        
       // Restore current controller
-      _ctrl_idx=TextLCD::_LCDCtrl_1;
+      _ctrl_idx=_LCDCtrl_1;
 
       // Configure secondary LCD controller    
       _setCursorAndDisplayMode(_currentMode, _currentCursor);
@@ -969,38 +661,38 @@
 
 
 // Set the Displaymode (On/Off) and Cursortype for current controller
-void TextLCD::_setCursorAndDisplayMode(TextLCD::LCDMode displayMode, TextLCD::LCDCursor cursorType) { 
+void TextLCD_Base::_setCursorAndDisplayMode(LCDMode displayMode, LCDCursor cursorType) { 
     
     // Configure current LCD controller       
     _writeCommand(0x08 | displayMode | cursorType);
 }
 
 // Set the Backlight mode (Off/On)
-void TextLCD::setBacklight(TextLCD::LCDBacklight backlightMode) {
+void TextLCD_Base::setBacklight(LCDBacklight backlightMode) {
 
     if (backlightMode == LightOn) {
-      _setBL(true);
+      this->_setBL(true);
     }
     else {
-      _setBL(false);    
+      this->_setBL(false);    
     }
 } 
 
 
-void TextLCD::setUDC(unsigned char c, char *udc_data) {
+void TextLCD_Base::setUDC(unsigned char c, char *udc_data) {
   
   // Select and configure second LCD controller when needed
   if(_type==LCD40x4) {
     _LCDCtrl_Idx current_ctrl_idx = _ctrl_idx; // Temp save current controller
    
     // Select primary controller     
-    _ctrl_idx=TextLCD::_LCDCtrl_0;
+    _ctrl_idx=_LCDCtrl_0;
     
     // Configure primary LCD controller
     _setUDC(c, udc_data);
 
     // Select 2nd controller
-    _ctrl_idx=TextLCD::_LCDCtrl_1;
+    _ctrl_idx=_LCDCtrl_1;
   
     // Configure secondary LCD controller    
     _setUDC(c, udc_data);
@@ -1015,7 +707,7 @@
     
 }
 
-void TextLCD::_setUDC(unsigned char c, char *udc_data) {
+void TextLCD_Base::_setUDC(unsigned char c, char *udc_data) {
   
   // Select CG RAM for current LCD controller
   _writeCommand(0x40 + ((c & 0x07) << 3)); //Set CG-RAM address,
@@ -1030,3 +722,350 @@
   _writeCommand(0x80 | addr);
   
 }
+
+
+///-------------------------------------------------------------------
+
+
+/* Create a TextLCD interface for using regular mbed pins
+ *
+ * @param rs     Instruction/data control line
+ * @param e      Enable line (clock)
+ * @param d4-d7  Data lines for using as a 4-bit interface
+ * @param type   Sets the panel size/addressing mode (default = LCD16x2)
+ * @param bl     Backlight control line (optional, default = NC)  
+ * @param e2     Enable2 line (clock for second controller, LCD40x4 only) 
+ * @param ctrl   LCD controller (default = HD44780)   
+ */ 
+TextLCD::TextLCD(PinName rs, PinName e,
+                 PinName d4, PinName d5, PinName d6, PinName d7,
+                 LCDType type, PinName bl, PinName e2, LCDCtrl ctrl) :
+                 TextLCD_Base(type, ctrl), 
+                 _rs(rs), _e(e), _bl(bl), _e2(e2),
+                 _d(d4, d5, d6, d7) {
+                                                                           
+  _init();
+
+}
+
+// Set E pin (or E2 pin)
+// Used for mbed pins, I2C bus expander or SPI shiftregister
+void TextLCD::_setEnable(bool value) {
+
+                    if(_ctrl_idx==_LCDCtrl_0) {
+                      if (value)
+                        _e  = 1;    // Set E bit 
+                      else  
+                        _e  = 0;    // Reset E bit  
+                    }    
+                    else {   
+                      if (value)
+                        _e2 = 1;    // Set E2 bit 
+                      else  
+                        _e2 = 0;    // Reset E2 bit  
+                    }    
+
+}    
+
+// Set RS pin
+// Used for mbed pins, I2C bus expander or SPI shiftregister
+void TextLCD::_setRS(bool value) {
+
+  if (value)
+    _rs  = 1;    // Set RS bit 
+  else  
+    _rs  = 0;    // Reset RS bit 
+
+}    
+
+// Set BL pin
+// Used for mbed pins, I2C bus expander or SPI shiftregister
+void TextLCD::_setBL(bool value) {
+
+  if (value)
+    _bl  = 1;    // Set BL bit 
+  else  
+    _bl  = 0;    // Reset BL bit 
+
+}    
+
+
+
+// Place the 4bit data on the databus
+// Used for mbed pins, I2C bus expander or SPI shifregister
+void TextLCD::_setData(int value) {
+  _d = value & 0x0F;   // Write Databits 
+}    
+
+
+
+
+///----------------------------------------------------------------------------------------
+
+
+/* Create a TextLCD interface using an I2C PC8574 portexpander
+ *
+ * @param i2c             I2C Bus
+ * @param deviceAddress   I2C slave address (PCF8574)
+ * @param type            Sets the panel size/addressing mode (default = LCD16x2)
+ * @param ctrl            LCD controller (default = HD44780)    
+ */
+TextLCD_I2C::TextLCD_I2C(I2C *i2c, char deviceAddress, LCDType type, LCDCtrl ctrl) :
+                         TextLCD_Base(type, ctrl), 
+                         _i2c(i2c){
+                              
+  _slaveAddress = deviceAddress;
+  
+  // Init the portexpander bus
+  _lcd_bus = D_LCD_BUS_DEF;
+  
+  // write the new data to the portexpander
+  _i2c->write(_slaveAddress, &_lcd_bus, 1);    
+
+  _init();
+    
+}
+
+// Set E pin (or E2 pin)
+// Used for mbed pins, I2C bus expander or SPI shiftregister
+void TextLCD_I2C::_setEnable(bool value) {
+
+                   if(_ctrl_idx==_LCDCtrl_0) {
+                     if (value)
+                       _lcd_bus |= D_LCD_E;     // Set E bit 
+                     else                     
+                       _lcd_bus &= ~D_LCD_E;    // Reset E bit                     
+                   }
+                   else {
+                     if (value)
+                       _lcd_bus |= D_LCD_E2;    // Set E2 bit 
+                     else                     
+                       _lcd_bus &= ~D_LCD_E2;   // Reset E2bit                     
+                   }    
+
+                   // write the new data to the I2C portexpander
+                   _i2c->write(_slaveAddress, &_lcd_bus, 1);    
+
+}    
+
+// Set RS pin
+// Used for mbed pins, I2C bus expander or SPI shiftregister
+void TextLCD_I2C::_setRS(bool value) {
+
+                   if (value)
+                     _lcd_bus |= D_LCD_RS;    // Set RS bit 
+                   else                     
+                     _lcd_bus &= ~D_LCD_RS;   // Reset RS bit                     
+
+                   // write the new data to the I2C portexpander
+                   _i2c->write(_slaveAddress, &_lcd_bus, 1);    
+                  
+}    
+
+// Set BL pin
+// Used for mbed pins, I2C bus expander or SPI shiftregister
+void TextLCD_I2C::_setBL(bool value) {
+
+  if (value)
+    _lcd_bus |= D_LCD_BL;    // Set BL bit 
+  else                     
+    _lcd_bus &= ~D_LCD_BL;   // Reset BL bit                     
+
+  // write the new data to the I2C portexpander
+  _i2c->write(_slaveAddress, &_lcd_bus, 1);    
+                 
+}    
+
+
+
+// Place the 4bit data on the databus
+// Used for mbed pins, I2C bus expander or SPI shifregister
+void TextLCD_I2C::_setData(int value) {
+  int data;
+  
+                    data = value & 0x0F;
+                    if (data & 0x01)
+                      _lcd_bus |= D_LCD_D4;   // Set Databit 
+                    else                     
+                      _lcd_bus &= ~D_LCD_D4;  // Reset Databit                     
+
+                    if (data & 0x02)
+                      _lcd_bus |= D_LCD_D5;   // Set Databit 
+                    else                     
+                      _lcd_bus &= ~D_LCD_D5;  // Reset Databit                     
+
+                    if (data & 0x04)
+                      _lcd_bus |= D_LCD_D6;   // Set Databit 
+                    else                     
+                      _lcd_bus &= ~D_LCD_D6;  // Reset Databit                     
+
+                    if (data & 0x08)
+                      _lcd_bus |= D_LCD_D7;   // Set Databit 
+                    else                     
+                      _lcd_bus &= ~D_LCD_D7;  // Reset Databit                     
+                    
+                    // write the new data to the I2C portexpander
+                    _i2c->write(_slaveAddress, &_lcd_bus, 1);  
+                   
+
+}    
+
+
+
+
+
+///------------------------------------------------------------------------------------
+
+
+
+
+
+
+// TextLCD_SPI Implementation
+
+
+ /* Create a TextLCD interface using an SPI 74595 portexpander
+  *
+  * @param spi             SPI Bus
+  * @param cs              chip select pin (active low)
+  * @param type            Sets the panel size/addressing mode (default = LCD16x2)
+  * @param ctrl            LCD controller (default = HD44780)      
+  */
+TextLCD_SPI::TextLCD_SPI(SPI *spi, PinName cs, LCDType type, LCDCtrl ctrl) :
+                         TextLCD_Base(type, ctrl), 
+                         _spi(spi),        
+                         _cs(cs) {      
+        
+  // Setup the spi for 8 bit data, low steady state clock,
+  // rising edge capture, with a 500KHz or 1MHz clock rate  
+  _spi->format(8,0);
+  _spi->frequency(500000);    
+  //_spi.frequency(1000000);    
+
+
+  // Init the portexpander bus
+  _lcd_bus = D_LCD_BUS_DEF;
+  
+  // write the new data to the portexpander
+  _setCS(false);  
+  _spi->write(_lcd_bus);   
+  _setCS(true);  
+  
+  _init();
+    
+}
+
+// Set E pin (or E2 pin)
+// Used for mbed pins, I2C bus expander or SPI shiftregister
+void TextLCD_SPI::_setEnable(bool value) {
+
+                   if(_ctrl_idx==_LCDCtrl_0) {
+                     if (value)
+                       _lcd_bus |= D_LCD_E;     // Set E bit 
+                     else                     
+                       _lcd_bus &= ~D_LCD_E;    // Reset E bit                     
+                   }
+                   else {
+                     if (value)
+                       _lcd_bus |= D_LCD_E2;    // Set E2 bit 
+                     else                     
+                       _lcd_bus &= ~D_LCD_E2;   // Reset E2 bit                     
+                   }
+                  
+                   // write the new data to the SPI portexpander
+                   _setCS(false);  
+                   _spi->write(_lcd_bus);   
+                   _setCS(true);  
+  
+}    
+
+// Set RS pin
+// Used for mbed pins, I2C bus expander or SPI shiftregister
+void TextLCD_SPI::_setRS(bool value) {
+
+  if (value)
+    _lcd_bus |= D_LCD_RS;    // Set RS bit 
+  else                     
+    _lcd_bus &= ~D_LCD_RS;   // Reset RS bit                     
+     
+  // write the new data to the SPI portexpander
+  _setCS(false);  
+  _spi->write(_lcd_bus);   
+  _setCS(true);     
+
+}    
+
+// Set BL pin
+// Used for mbed pins, I2C bus expander or SPI shiftregister
+void TextLCD_SPI::_setBL(bool value) {
+
+  if (value)
+    _lcd_bus |= D_LCD_BL;    // Set BL bit 
+  else                     
+    _lcd_bus &= ~D_LCD_BL;   // Reset BL bit                     
+      
+  // write the new data to the SPI portexpander
+  _setCS(false);  
+  _spi->write(_lcd_bus);   
+  _setCS(true);  
+     
+}    
+
+
+
+// Place the 4bit data on the databus
+// Used for mbed pins, I2C bus expander or SPI shiftregister
+void TextLCD_SPI::_setData(int value) {
+  int data;
+  
+                    data = value & 0x0F;
+                    if (data & 0x01)
+                      _lcd_bus |= D_LCD_D4;   // Set Databit 
+                    else                     
+                      _lcd_bus &= ~D_LCD_D4;  // Reset Databit                     
+
+                    if (data & 0x02)
+                      _lcd_bus |= D_LCD_D5;   // Set Databit 
+                    else                     
+                      _lcd_bus &= ~D_LCD_D5;  // Reset Databit                     
+
+                    if (data & 0x04)
+                      _lcd_bus |= D_LCD_D6;   // Set Databit 
+                    else                     
+                      _lcd_bus &= ~D_LCD_D6;  // Reset Databit                     
+
+                    if (data & 0x08)
+                      _lcd_bus |= D_LCD_D7;   // Set Databit 
+                    else                     
+                      _lcd_bus &= ~D_LCD_D7;  // Reset Databit                     
+                    
+                   // write the new data to the SPI portexpander
+                   _setCS(false);  
+                   _spi->write(_lcd_bus);   
+                   _setCS(true);  
+        
+}    
+
+
+// Set CS line.
+// Only used for SPI bus
+void TextLCD_SPI::_setCS(bool value) {
+
+  if (value) {   
+    _cs  = 1;    // Set CS pin 
+  }  
+  else  
+    _cs  = 0;    // Reset CS pin 
+  
+}
+
+
+
+
+
+
+
+
+
+
+