Commits

F Malpartida  committed 8e273a4

First version of the generic 3wire latch library.

  • Participants
  • Parent commits 83bc88d

Comments (0)

Files changed (7)

 #define LCD_5x10DOTS            0x04
 #define LCD_5x8DOTS             0x00
 
-#define LCD_4BIT                1
-#define LCD_8BIT                0
 
-// Define COMMAND and DATA LCD Rs
+// Define COMMAND and DATA LCD Rs (used by send method).
 // ---------------------------------------------------------------------------
 #define COMMAND                 0
 #define DATA                    1
     @discussion Sets the pin in the device to control the backlight. The behaviour
     of this method is very dependent on the device. Some controllers support
     dimming some don't. Please read the actual header file for each individual
-    device. The setBacklightPin method has to be called before setting the backlight.
+    device. The setBacklightPin method has to be called before setting the backlight
+    or the adequate backlight control constructor.
     @see setBacklightPin.
     
     NOTE: The prefered methods to control the backlight are "backlight" and
     "noBacklight".
     
     @param      0..255 - the value is very dependent on the LCD, however, 0
-    will be interpreted as off. If backlight polarity set to negative, the
-    values will be inverted.
+    will be interpreted as off.
     */
    virtual void setBacklight ( uint8_t value ) { };
    
    // Internal LCD variables to control the LCD shared between all derived
    // classes.
    uint8_t _displayfunction;  // LCD_5x10DOTS or LCD_5x8DOTS, LCD_4BITMODE or 
-   // LCD_8BITMODE, LCD_1LINE or LCD_2LINE
+                              // LCD_8BITMODE, LCD_1LINE or LCD_2LINE
    uint8_t _displaycontrol;   // LCD base control command LCD on/off, blink, cursor
-   // all commands are "ored" to its contents.
+                              // all commands are "ored" to its contents.
    uint8_t _displaymode;      // Text entry mode to the LCD
    uint8_t _numlines;         // Number of lines of the LCD, initialized with begin()
    uint8_t _cols;             // Number of columns in the LCD

File LiquidCrystal.cpp

 // ---------------------------------------------------------------------------
 #define LCD_NOBACKLIGHT 0xFF
 
+// LCD driver configuration (4bit or 8bit driver control)
+#define LCD_4BIT                1
+#define LCD_8BIT                0
+
 // STATIC helper functions
 // ---------------------------------------------------------------------------
 

File LiquidCrystal_I2C.cpp

 // ---------------------------------------------------------------------------
 
 // flags for backlight control
+/*!
+    @defined 
+    @abstract   LCD_NOBACKLIGHT
+    @discussion No BACKLIGHT MASK
+*/
 #define LCD_NOBACKLIGHT 0x00
+
+/*!
+ @defined 
+ @abstract   LCD_BACKLIGHT
+ @discussion BACKLIGHT MASK used when backlight is on
+ */
 #define LCD_BACKLIGHT   0xFF
 
 
  @abstract   Enable bit of the LCD
  @discussion Defines the IO of the expander connected to the LCD Enable
  */
-#define EN B01000000  // Enable bit
+#define EN 6  // Enable bit
 
 /*!
  @defined 
  @abstract   Read/Write bit of the LCD
  @discussion Defines the IO of the expander connected to the LCD Rw pin
  */
-#define RW B00100000  // Read/Write bit
+#define RW 5  // Read/Write bit
 
 /*!
  @defined 
  @abstract   Register bit of the LCD
  @discussion Defines the IO of the expander connected to the LCD Register select pin
  */
-#define RS B00010000  // Register select bit
+#define RS 4  // Register select bit
+
+/*!
+ @defined 
+ @abstract   LCD dataline allocation this library only supports 4 bit LCD control
+ mode.
+ @discussion D4, D5, D6, D7 LCD data lines pin mapping of the extender module
+*/
+#define D4 0
+#define D5 1
+#define D6 2
+#define D7 3
 
 
 // CONSTRUCTORS
 // ---------------------------------------------------------------------------
 LiquidCrystal_I2C::LiquidCrystal_I2C( uint8_t lcd_Addr )
 {
-   _Addr = lcd_Addr;
-   
-   _backlightPinMask = 0x0;
-   _backlightStsMask = LCD_NOBACKLIGHT;
-   _polarity = POSITIVE;
-   
-   _En = EN;
-   _Rw = RW;
-   _Rs = RS;
-   
-   // Initialise default values data[0] pin 0, data[1] pin 1, ...
-   for ( uint8_t i = 0; i < 4; i++ )
-   {
-      _data_pins[i] = ( 1 << i );
-   }
+   config(lcd_Addr, EN, RW, RS, D4, D5, D6, D7);
 }
 
 
 LiquidCrystal_I2C::LiquidCrystal_I2C(uint8_t lcd_Addr, uint8_t backlighPin, 
                                      t_backlighPol pol = POSITIVE)
 {
-   _Addr = lcd_Addr;
-   
-   _backlightPinMask = 0x0;
-   _backlightStsMask = LCD_NOBACKLIGHT;
-   _polarity = POSITIVE;
-   
-   _En = EN;
-   _Rw = RW;
-   _Rs = RS;
-   
-   // Initialise default values data[0] pin 0, data[1] pin 1, ...
-   for ( uint8_t i = 0; i < 4; i++ )
-   {
-      _data_pins[i] = ( 1 << i );
-   }
+   config(lcd_Addr, EN, RW, RS, D4, D5, D6, D7);
    setBacklightPin(backlighPin, pol);
 }
 
 LiquidCrystal_I2C::LiquidCrystal_I2C(uint8_t lcd_Addr, uint8_t En, uint8_t Rw,
                                      uint8_t Rs)
 {
-   _Addr = lcd_Addr;
-   
-   _backlightPinMask = 0;
-   _backlightStsMask = LCD_NOBACKLIGHT;
-   _polarity = POSITIVE;
-   
-   _En = ( 1 << En );
-   _Rw = ( 1 << Rw );
-   _Rs = ( 1 << Rs );
-   
-   // Initialise default values data[0] pin 0, data[1] pin 1, ...
-   for ( uint8_t i = 0; i < 4; i++ )
-   {
-      _data_pins[i] = ( 1 << i );
-   }
+   config(lcd_Addr, En, Rw, Rs, D4, D5, D6, D7);
 }
 
 LiquidCrystal_I2C::LiquidCrystal_I2C(uint8_t lcd_Addr, uint8_t En, uint8_t Rw,
                                      uint8_t Rs, uint8_t backlighPin, 
                                      t_backlighPol pol = POSITIVE)
 {
-   _Addr = lcd_Addr;
-   
-   _backlightPinMask = 0;
-   _backlightStsMask = LCD_NOBACKLIGHT;
-   _polarity = POSITIVE;
-   
-   _En = ( 1 << En );
-   _Rw = ( 1 << Rw );
-   _Rs = ( 1 << Rs );
-   
-   // Initialise default values data[0] pin 0, data[1] pin 1, ...
-   for ( uint8_t i = 0; i < 4; i++ )
-   {
-      _data_pins[i] = ( 1 << i );
-   }
+   config(lcd_Addr, En, Rw, Rs, D4, D5, D6, D7);
    setBacklightPin(backlighPin, pol);
 }
 
 LiquidCrystal_I2C::LiquidCrystal_I2C(uint8_t lcd_Addr, uint8_t En, uint8_t Rw,
-                                     uint8_t Rs, uint8_t d0, uint8_t d1,
-                                     uint8_t d2, uint8_t d3 )
+                                     uint8_t Rs, uint8_t d4, uint8_t d5,
+                                     uint8_t d6, uint8_t d7 )
 {
-   _Addr = lcd_Addr;
-   
-   _backlightPinMask = 0;
-   _backlightStsMask = LCD_NOBACKLIGHT;
-   _polarity = POSITIVE;
-   
-   _En = ( 1 << En );
-   _Rw = ( 1 << Rw );
-   _Rs = ( 1 << Rs );
-   
-   // Initialise pin mapping
-   _data_pins[0] = ( 1 << d0 );
-   _data_pins[1] = ( 1 << d1 );
-   _data_pins[2] = ( 1 << d2 );
-   _data_pins[3] = ( 1 << d3 );
+   config(lcd_Addr, En, Rw, Rs, d4, d5, d6, d7);
 }
 
 LiquidCrystal_I2C::LiquidCrystal_I2C(uint8_t lcd_Addr, uint8_t En, uint8_t Rw,
-                                     uint8_t Rs, uint8_t d0, uint8_t d1,
-                                     uint8_t d2, uint8_t d3, uint8_t backlighPin, 
+                                     uint8_t Rs, uint8_t d4, uint8_t d5,
+                                     uint8_t d6, uint8_t d7, uint8_t backlighPin, 
                                      t_backlighPol pol = POSITIVE )
 {
-   _Addr = lcd_Addr;
-   
-   _backlightPinMask = 0;
-   _backlightStsMask = LCD_NOBACKLIGHT;
-   _polarity = POSITIVE;
-   
-   _En = ( 1 << En );
-   _Rw = ( 1 << Rw );
-   _Rs = ( 1 << Rs );
-   
-   // Initialise pin mapping
-   _data_pins[0] = ( 1 << d0 );
-   _data_pins[1] = ( 1 << d1 );
-   _data_pins[2] = ( 1 << d2 );
-   _data_pins[3] = ( 1 << d3 );
+   config(lcd_Addr, En, Rw, Rs, d4, d5, d6, d7);
    setBacklightPin(backlighPin, pol);
 }
 
 
 //
 // setBacklightPin
-void LiquidCrystal_I2C::setBacklightPin ( uint8_t pin, t_backlighPol pol = POSITIVE )
+void LiquidCrystal_I2C::setBacklightPin ( uint8_t value, t_backlighPol pol = POSITIVE )
 {
-   _backlightPinMask = ( 1 << pin );
+   _backlightPinMask = ( 1 << value );
    _polarity = pol;
 }
 
    return ( status );
 }
 
+//
+// config
+void LiquidCrystal_I2C::config (uint8_t lcd_Addr, uint8_t En, uint8_t Rw, uint8_t Rs, 
+                                 uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7 )
+{
+   _Addr = lcd_Addr;
+   
+   _backlightPinMask = 0;
+   _backlightStsMask = LCD_NOBACKLIGHT;
+   _polarity = POSITIVE;
+   
+   _En = ( 1 << En );
+   _Rw = ( 1 << Rw );
+   _Rs = ( 1 << Rs );
+   
+   // Initialise pin mapping
+   _data_pins[0] = ( 1 << d4 );
+   _data_pins[1] = ( 1 << d5 );
+   _data_pins[2] = ( 1 << d6 );
+   _data_pins[3] = ( 1 << d7 );   
+}
+
+
+
 // low level data pushing commands
 //----------------------------------------------------------------------------
 
 
 //
 // pulseEnable
-void LiquidCrystal_I2C::pulseEnable (uint8_t _data)
+void LiquidCrystal_I2C::pulseEnable (uint8_t data)
 {
-   _i2cio.write (_data | _En);   // En HIGH
-   _i2cio.write (_data & ~_En);  // En LOW
+   _i2cio.write (data | _En);   // En HIGH
+   _i2cio.write (data & ~_En);  // En LOW
 }

File LiquidCrystal_I2C.h

     @param      En[in] LCD En (Enable) pin connected to the IO extender module
     @param      Rw[in] LCD Rw (Read/write) pin connected to the IO extender module
     @param      Rs[in] LCD Rs (Reset) pin connected to the IO extender module
-    @param      d0[in] LCD data 0 pin map on IO extender module
-    @param      d1[in] LCD data 1 pin map on IO extender module
-    @param      d2[in] LCD data 2 pin map on IO extender module
-    @param      d3[in] LCD data 3 pin map on IO extender module
+    @param      d4[in] LCD data 0 pin map on IO extender module
+    @param      d5[in] LCD data 1 pin map on IO extender module
+    @param      d6[in] LCD data 2 pin map on IO extender module
+    @param      d7[in] LCD data 3 pin map on IO extender module
     */
    LiquidCrystal_I2C(uint8_t lcd_Addr, uint8_t En, uint8_t Rw, uint8_t Rs, 
-                     uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3 );
+                     uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7 );
    // Constructor with backlight control
    LiquidCrystal_I2C(uint8_t lcd_Addr, uint8_t En, uint8_t Rw, uint8_t Rs, 
-                     uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
+                     uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7,
                      uint8_t backlighPin, t_backlighPol pol);
    /*!
     @function
     The setBacklightPin has to be called before setting the backlight for
     this method to work. @see setBacklightPin.
     
-    @param      mode: backlight mode (HIGH|LOW)
+    @param      value: backlight mode (HIGH|LOW)
     */
-   void setBacklight ( uint8_t mode );
+   void setBacklight ( uint8_t value );
    
 private:
    
    int  init();
    
    /*!
+    @function
+    @abstract   Initialises class private variables
+    @discussion This is the class single point for initialising private variables.
+    
+    @param      lcd_Addr[in] I2C address of the IO expansion module. For I2CLCDextraIO,
+    the address can be configured using the on board jumpers.
+    @param      En[in] LCD En (Enable) pin connected to the IO extender module
+    @param      Rw[in] LCD Rw (Read/write) pin connected to the IO extender module
+    @param      Rs[in] LCD Rs (Reset) pin connected to the IO extender module
+    @param      d4[in] LCD data 0 pin map on IO extender module
+    @param      d5[in] LCD data 1 pin map on IO extender module
+    @param      d6[in] LCD data 2 pin map on IO extender module
+    @param      d7[in] LCD data 3 pin map on IO extender module
+    */
+   void config (uint8_t lcd_Addr, uint8_t En, uint8_t Rw, uint8_t Rs, 
+                uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7 );
+   
+   /*!
     @method     
     @abstract   Writes an 4 bit value to the LCD.
     @discussion Writes 4 bits (the least significant) to the LCD control data lines.

File LiquidCrystal_SR3W.cpp

+// ---------------------------------------------------------------------------
+// Created by Francisco Malpartida on 7.3.2012.
+// Copyright 2011 - Under creative commons license 3.0:
+//        Attribution-ShareAlike CC BY-SA
+//
+// This software is furnished "as is", without technical support, and with no 
+// warranty, express or implied, as to its usefulness for any purpose.
+//
+// Thread Safe: No
+// Extendable: Yes
+//
+// @file LiquidCrystal_SRG.h
+// This file implements a basic liquid crystal library that comes as standard
+// in the Arduino SDK but using a generic SHIFT REGISTER extension board.
+// 
+// @brief 
+// This is a basic implementation of the LiquidCrystal library of the
+// Arduino SDK. The original library has been reworked in such a way that 
+// this class implements the all methods to command an LCD based
+// on the Hitachi HD44780 and compatible chipsets using a 3 wire latching
+// shift register. While it has been tested with a 74HC595N shift register
+// it should also work with other latching shift registers such as the MC14094
+// and the HEF4094
+//
+// This particular driver has been created as generic as possible to enable
+// users to configure and connect their LCDs using just 3 digital IOs from the
+// AVR or Arduino, and connect the LCD to the outputs of the shiftregister
+// in any configuration. The library is configured by passing the IO pins
+// that control the strobe, data and clock of the shift register and a map
+// of how the shiftregister is connected to the LCD.
+// 
+//
+//   +--------------------------------------------+
+//   |    Arduino (ATMega 168 or 328)             |
+//   |   IO1           IO2           IO3          |
+//   +----+-------------+-------------+-----------+
+//        |             |             |
+//        |             |             |
+//   +----+-------------+-------------+-----------+
+//   |    Strobe        Data          Clock       |
+//   |          8-bit shift/latch register        |
+//   |    Qa   Qb   Qc   Qd   Qe   Qf   Qg   Qh   |
+//   +----+----+----+----+----+----+----+----+----+
+//        |    |    |    |    |    |    |    
+//        |11  |12  |13  |14  |6   |5   |4    (LCD pins)
+//   +----+----+----+----+----+----+----+----+----+
+//   |    DB4  DB5  DB6  DB7  E    Rw   RS        |
+//   |                 LCD Module                 |
+//
+// The functionality provided by this class and its base class is identical
+// to the original functionality of the Arduino LiquidCrystal library.
+//
+//
+// @author F. Malpartida - fmalpartida@gmail.com
+// ---------------------------------------------------------------------------
+// flags for backlight control
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+#if (ARDUINO <  100)
+#include <WProgram.h>
+#else
+#include <Arduino.h>
+#endif
+#include "LiquidCrystal_SR3W.h"
+
+#include "FastIO.h"
+
+/*!
+ @defined 
+ @abstract   LCD_NOBACKLIGHT
+ @discussion No BACKLIGHT MASK
+ */
+#define LCD_NOBACKLIGHT 0x00
+
+/*!
+ @defined 
+ @abstract   LCD_BACKLIGHT
+ @discussion BACKLIGHT MASK used when backlight is on
+ */
+#define LCD_BACKLIGHT   0xFF
+
+
+// Default library configuration parameters used by class constructor with
+// only the I2C address field.
+// ---------------------------------------------------------------------------
+/*!
+ @defined 
+ @abstract   Enable bit of the LCD
+ @discussion Defines the IO of the expander connected to the LCD Enable
+ */
+#define EN 4  // Enable bit
+
+/*!
+ @defined 
+ @abstract   Read/Write bit of the LCD
+ @discussion Defines the IO of the expander connected to the LCD Rw pin
+ */
+#define RW 5  // Read/Write bit
+
+/*!
+ @defined 
+ @abstract   Register bit of the LCD
+ @discussion Defines the IO of the expander connected to the LCD Register select pin
+ */
+#define RS 6  // Register select bit
+
+/*!
+ @defined 
+ @abstract   LCD dataline allocation this library only supports 4 bit LCD control
+ mode.
+ @discussion D4, D5, D6, D7 LCD data lines pin mapping of the extender module
+ */
+#define D4 0
+#define D5 1
+#define D6 2
+#define D7 3
+
+
+
+LiquidCrystal_SR3W::LiquidCrystal_SR3W(uint8_t data, uint8_t clk, uint8_t strobe)
+{
+   init( data, clk, strobe, RS, RW, EN, D4, D5, D6, D7 );
+}
+
+LiquidCrystal_SR3W::LiquidCrystal_SR3W(uint8_t data, uint8_t clk, uint8_t strobe,
+                                       uint8_t backlighPin, t_backlighPol pol)
+{
+   init( data, clk, strobe, RS, RW, EN, D4, D5, D6, D7 );   
+}
+
+LiquidCrystal_SR3W::LiquidCrystal_SR3W(uint8_t data, uint8_t clk, uint8_t strobe,
+                                       uint8_t En, uint8_t Rw, uint8_t Rs, 
+                                       uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7 )
+{
+   init( data, clk, strobe, En, Rw, En, d4, d5, d6, d7 );
+}
+
+LiquidCrystal_SR3W::LiquidCrystal_SR3W(uint8_t data, uint8_t clk, uint8_t strobe, 
+                                       uint8_t En, uint8_t Rw, uint8_t Rs, 
+                                       uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7,
+                                       uint8_t backlighPin, t_backlighPol pol)
+{
+   init( data, clk, strobe, En, Rw, En, d4, d5, d6, d7 );
+}
+
+
+void LiquidCrystal_SR3W::send(uint8_t value, uint8_t mode)
+{
+   // No need to use the delay routines since the time taken to write takes
+   // longer that what is needed both for toggling and enable pin an to execute
+   // the command.
+   
+   if ( mode == FOUR_BITS )
+   {
+      write4bits( (value & 0x0F), COMMAND );
+   }
+   else 
+   {
+      write4bits( (value >> 4), mode );
+      write4bits( (value & 0x0F), mode);
+   }   
+}
+
+
+void LiquidCrystal_SR3W::setBacklightPin ( uint8_t value, t_backlighPol pol = POSITIVE )
+{
+   _backlightPinMask = ( 1 << value );
+   _polarity = pol;
+}
+
+void LiquidCrystal_SR3W::setBacklight ( uint8_t value )
+{
+   // Check if backlight is available
+   // ----------------------------------------------------
+   if ( _backlightPinMask != 0x0 )
+   {
+      // Check for polarity to configure mask accordingly
+      // ----------------------------------------------------------
+      if  (((_polarity == POSITIVE) && (value > 0)) || 
+           ((_polarity == NEGATIVE ) && ( value == 0 )))
+      {
+         _backlightStsMask = _backlightPinMask & LCD_BACKLIGHT;
+      }
+      else 
+      {
+         _backlightStsMask = _backlightPinMask & LCD_NOBACKLIGHT;
+      }
+      loadSR( _backlightStsMask );
+   }
+}
+
+
+// PRIVATE METHODS
+// -----------------------------------------------------------------------------
+
+int LiquidCrystal_SR3W::init(uint8_t data, uint8_t clk, uint8_t strobe, 
+                             uint8_t Rs, uint8_t Rw, uint8_t En,
+                             uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
+{
+   _data       = fio_pinToBit(data);
+   _clk        = fio_pinToBit(clk);
+   _strobe     = fio_pinToBit(strobe);
+   _data_reg   = fio_pinToOutputRegister(data);
+   _clk_reg    = fio_pinToOutputRegister(clk);
+   _strobe_reg = fio_pinToOutputRegister(strobe);
+   
+   // LCD pin mapping
+   _backlightPinMask = 0;
+   _backlightStsMask = LCD_NOBACKLIGHT;
+   _polarity = POSITIVE;
+   
+   _En = ( 1 << En );
+   _Rw = ( 1 << Rw );
+   _Rs = ( 1 << Rs );
+   
+   // Initialise pin mapping
+   _data_pins[0] = ( 1 << d4 );
+   _data_pins[1] = ( 1 << d5 );
+   _data_pins[2] = ( 1 << d6 );
+   _data_pins[3] = ( 1 << d7 );
+   
+   _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x10DOTS;
+   
+   return (1);
+}
+
+void LiquidCrystal_SR3W::write4bits(uint8_t value, uint8_t mode)
+{
+   uint8_t pinMapValue = 0;
+   
+   // Map the value to LCD pin mapping
+   // --------------------------------
+   for ( uint8_t i = 0; i < 4; i++ )
+   {
+      if ( ( value & 0x1 ) == 1 )
+      {
+         pinMapValue |= _data_pins[i];
+      }
+      value = ( value >> 1 );
+   }
+   
+   // Is it a command or data
+   // -----------------------
+   if ( mode == DATA )
+   {
+      mode = _Rs;
+   }
+   
+   pinMapValue |= mode | _backlightStsMask;
+   loadSR ( pinMapValue | _En );  // Send with enable high
+   loadSR ( pinMapValue & ~_En ); // Send with enable low
+}
+
+
+void LiquidCrystal_SR3W::loadSR(uint8_t value) 
+{
+   // Load the shift register with information
+   fio_shiftOut(_data_reg, _data, _clk_reg, _clk, value, MSBFIRST);
+   
+   // Strobe the data into the latch
+   ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
+   {
+      fio_digitalWrite_HIGH(_strobe_reg, _strobe);
+      waitUsec( 1 ); // strobe pulse must be >450ns
+      fio_digitalWrite_SWITCHTO(_strobe_reg, _strobe, LOW);
+   }
+   waitUsec( 40 ); // commands need > 37us to settle
+}

File LiquidCrystal_SR3W.h

+// ---------------------------------------------------------------------------
+// Created by Francisco Malpartida on 7.3.2012.
+// Copyright 2011 - Under creative commons license 3.0:
+//        Attribution-ShareAlike CC BY-SA
+//
+// This software is furnished "as is", without technical support, and with no 
+// warranty, express or implied, as to its usefulness for any purpose.
+//
+// Thread Safe: No
+// Extendable: Yes
+//
+// @file LiquidCrystal_SR3W.h
+// This file implements a basic liquid crystal library that comes as standard
+// in the Arduino SDK but using a generic SHIFT REGISTER extension board.
+// 
+// @brief 
+// This is a basic implementation of the LiquidCrystal library of the
+// Arduino SDK. The original library has been reworked in such a way that 
+// this class implements the all methods to command an LCD based
+// on the Hitachi HD44780 and compatible chipsets using a 3 wire latching
+// shift register. While it has been tested with a 74HC595N shift register
+// it should also work with other latching shift registers such as the MC14094
+// and the HEF4094
+//
+// This particular driver has been created as generic as possible to enable
+// users to configure and connect their LCDs using just 3 digital IOs from the
+// AVR or Arduino, and connect the LCD to the outputs of the shiftregister
+// in any configuration. The library is configured by passing the IO pins
+// that control the strobe, data and clock of the shift register and a map
+// of how the shiftregister is connected to the LCD.
+// 
+//
+//   +--------------------------------------------+
+//   |    Arduino (ATMega 168 or 328)             |
+//   |   IO1           IO2           IO3          |
+//   +----+-------------+-------------+-----------+
+//        |             |             |
+//        |             |             |
+//   +----+-------------+-------------+-----------+
+//   |    Strobe        Data          Clock       |
+//   |          8-bit shift/latch register        |
+//   |    Qa   Qb   Qc   Qd   Qe   Qf   Qg   Qh   |
+//   +----+----+----+----+----+----+----+----+----+
+//        |    |    |    |    |    |        
+//        |11  |12  |13  |14  |6   |4   
+//   +----+----+----+----+----+----+----+----+----+
+//   |    DB4  DB5  DB6  DB7  E    RS   Rw        |
+//   |                 LCD Module                 |
+//
+// The functionality provided by this class and its base class is identical
+// to the original functionality of the Arduino LiquidCrystal library.
+//
+//
+// @author F. Malpartida - fmalpartida@gmail.com
+// ---------------------------------------------------------------------------
+#ifndef _LIQUIDCRYSTAL_SR3W_H_
+#define _LIQUIDCRYSTAL_SR3W_H_
+
+#include <inttypes.h>
+#include "LCD.h"
+#include "FastIO.h"
+
+
+class LiquidCrystal_SR3W : public LCD 
+{
+public:
+   
+   /*!
+    @method     
+    @abstract   Class constructor. 
+    @discussion Initializes class variables and defines the IO driving the 
+    shift register. The constructor does not initialize the LCD.
+    Default configuration:
+    Shift register      LCD
+    QA                  DB4
+    QB                  DB5
+    QC                  DB6
+    QD                  DB7
+    QE                  E
+    QF                  Rs
+    GND                 Rw
+    
+    @param      strobe[in] shiftregister strobe pin.
+    @param      data[in] shiftregister data pin.
+    @param      clk[in] shiftregister clock pin.
+    */
+   LiquidCrystal_SR3W(uint8_t data, uint8_t clk, uint8_t strobe);
+   // Constructor with backlight control
+   LiquidCrystal_SR3W(uint8_t data, uint8_t clk, uint8_t strobe, 
+                      uint8_t backlighPin, t_backlighPol pol);   
+   
+   /*!
+    @method     
+    @abstract   Class constructor. 
+    @discussion Initializes class variables and defines the control lines of
+    the LCD and the shiftregister. The constructor does not initialize the LCD.
+    
+    @param      strobe[in] shiftregister strobe pin.
+    @param      data[in] shiftregister data pin.
+    @param      clk[in] shiftregister clock pin.
+    @param      En[in] LCD En (Enable) pin connected to the IO extender module
+    @param      Rw[in] LCD Rw (Read/write) pin connected to the IO extender module
+    @param      Rs[in] LCD Rs (Reg Select) pin connected to the IO extender module
+    @param      d0[in] LCD data 0 pin map on IO extender module
+    @param      d1[in] LCD data 1 pin map on IO extender module
+    @param      d2[in] LCD data 2 pin map on IO extender module
+    @param      d3[in] LCD data 3 pin map on IO extender module
+    */
+   LiquidCrystal_SR3W(uint8_t data, uint8_t clk, uint8_t strobe, 
+                      uint8_t En, uint8_t Rw, uint8_t Rs, 
+                      uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7 );
+   // Constructor with backlight control
+   LiquidCrystal_SR3W( uint8_t data, uint8_t clk, uint8_t strobe,
+                      uint8_t En, uint8_t Rw, uint8_t Rs, 
+                      uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7,
+                      uint8_t backlighPin, t_backlighPol pol);
+   
+   /*!
+    @function
+    @abstract   Send a particular value to the LCD.
+    @discussion Sends a particular value to the LCD for writing to the LCD or
+    as an LCD command.
+    
+    Users should never call this method.
+    
+    @param      value[in] Value to send to the LCD.
+    @param      mode[in] DATA - write to the LCD CGRAM, COMMAND - write a 
+    command to the LCD.
+    */
+   virtual void send(uint8_t value, uint8_t mode);
+   
+   /*!
+    @function
+    @abstract   Sets the pin to control the backlight.
+    @discussion Sets the pin in the device to control the backlight. This device
+    doesn't support dimming backlight capability.
+    
+    @param      0: backlight off, 1..255: backlight on.
+    */
+   void setBacklightPin ( uint8_t value, t_backlighPol pol );
+   
+   /*!
+    @function
+    @abstract   Switch-on/off the LCD backlight.
+    @discussion Switch-on/off the LCD backlight.
+    The setBacklightPin has to be called before setting the backlight for
+    this method to work. @see setBacklightPin.
+    
+    @param      value: backlight mode (HIGH|LOW)
+    */
+   void setBacklight ( uint8_t value );
+   
+private:
+   
+   /*!
+    @method     
+    @abstract   Initializes the LCD class
+    @discussion Initializes the LCD class and IO expansion module.
+    */
+   int  init(uint8_t data, uint8_t clk, uint8_t strobe, 
+             uint8_t Rs, uint8_t Rw, uint8_t En,
+             uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7);
+   
+   /*!
+    @method     
+    @abstract   Writes an 4 bit value to the LCD.
+    @discussion Writes 4 bits (the least significant) to the LCD control data lines.
+    @param      value[in] Value to write to the LCD
+    @param      more[in]  Value to distinguish between command and data.
+    COMMAND == command, DATA == data.
+    */
+   void write4bits(uint8_t value, uint8_t mode);
+   
+   /*!
+    @function
+    @abstract   load into the shift register a byte
+    @discussion loads into the shift register a byte
+    @param      value[in]: value to be loaded into the shiftregister.
+    */
+   void loadSR(uint8_t value);
+   
+   
+   fio_bit      _strobe;           // shift register strobe pin
+   fio_register _strobe_reg;       // SR strobe pin MCU register
+   fio_bit      _data;             // shift register data pin
+   fio_register _data_reg;         // SR data pin MCU register
+   fio_bit      _clk;              // shift register clock pin
+   fio_register _clk_reg;          // SR clock pin MCU register
+   uint8_t      _En;               // LCD expander word for enable pin
+   uint8_t      _Rw;               // LCD expander word for R/W pin
+   uint8_t      _Rs;               // LCD expander word for Register Select pin
+   uint8_t      _data_pins[4];     // LCD data lines
+   uint8_t      _backlightPinMask; // Backlight IO pin mask
+   uint8_t      _backlightStsMask; // Backlight status mask
+   
+};
+
+#endif
+

File examples/performanceLCD/performanceLCD.pde

 // ---------------------------------------------------------------------------
 #include <Wire.h>
 
-#define _LCD_I2C_
+#define _LCD_SR3W_
 
 #ifdef _LCD_I2C_
 #include <LiquidCrystal_I2C.h>
 #include <LiquidCrystal_SR.h>
 #endif
 
-#ifdef _LCD_SRLCD3_
-#include <LiquidCrystal_SR_LCD3.h>
+#ifdef _LCD_SR3W_
+#include <LiquidCrystal_SR3W.h>
 #endif
 
 #ifdef _LCD_SR1_
 const int    CONTRAST      = 0;
 #endif
 
-#ifdef _LCD_SRLCD3_
+#ifdef _LCD_SR3W_
 const int    CONTRAST_PIN  = 0; // none
 const int    BACKLIGHT_PIN = 5;
 const int    CONTRAST      = 0;
 {
    t_benchmarkOp   benchmark; /**< Function pointer associated to the benchmark */
    long            benchTime; /**< execution time for benchmark 1 in useconds */
-   uint8_t         numWrites; /**< Number of write cycles of the benchmark    */
+   uint16_t        numWrites; /**< Number of write cycles of the benchmark    */
 } t_benchMarks;
 
 
 LiquidCrystal_SR1 lcd(2);
 #endif
 
-#ifdef _LCD_SRLCD3_
-LiquidCrystal_SR_LCD3 lcd(3, 4, 2);
+#ifdef _LCD_SR3W_
+LiquidCrystal_SR3W lcd(4, 3, 2);
 #endif
 
 // benchMarks definitions
 static t_benchMarks myBenchMarks[NUM_BENCHMARKS] =
 {
    { benchmark1, 0, (LCD_ROWS * LCD_COLUMNS) + 2 },
-   { benchmark2, 0, LCD_ROWS * LCD_COLUMNS * 6 },
+   { benchmark2, 0, LCD_ROWS * LCD_COLUMNS * 6 * 2 },
    { benchmark3, 0, 40 + 2 },
    { benchmark4, 0, 40 + 2 }
 };
    for ( i = 0; i < NUM_BENCHMARKS; i++ )
    {
       myBenchMarks[i].benchTime = 
-         myBenchMarks[i].benchmark (ITERATIONS)/ITERATIONS;
+         (myBenchMarks[i].benchmark (ITERATIONS))/ITERATIONS;
          Serial.println (i);
    }
    
-   float fAllWrites=0;
+   float fAllWrites=0.0;
    
    for ( i = 0; i < NUM_BENCHMARKS; i++ )
    {   
       Serial.print ( myBenchMarks[i].benchTime );
       Serial.print ( F(" us - ") );
       Serial.print ( F(" write: ") );
-      Serial.print ( myBenchMarks[i].benchTime / myBenchMarks[i].numWrites );
+      Serial.print ( myBenchMarks[i].benchTime / (float)myBenchMarks[i].numWrites );
       Serial.println ( F(" us") );
       fAllWrites += myBenchMarks[i].benchTime / (float)myBenchMarks[i].numWrites;
    }
    Serial.print( F("avg. write: ") );
    Serial.println( fAllWrites / (float)NUM_BENCHMARKS );
- }
+ }