New LiquidCrystal library - LCD library

tack:

fm:
If you look in the project's wiki you will see that the 2 wire SR version of the library is about 4,5 times faster than the stock parallel LiquidCrystal an almos 40 times faster than the I2C versio.

Wow, that's some difference. I actually expected it to be slower for some reason. No real basis for that though, other than I guess some intuition that a cheaper method using generic SR would be slower than a specific implementation like I2C, or a parallel interface using a lot more pins.

There are some things to consider as well. The default i2c clock 100 khz - That is according to the I2C spec.
And that is the clock rate that Arduino programs the i2c interface to clock at. That is pretty slow.
Some of the newer i2c chips support higher speed and can can clock up to 10mhz.
(I bet wiring and pullups/termination becomes much more critical at those speeds)
So there is some room there if you use a faster i2c chip and put in an Arduino hack to speed up the i2c bus.
(But that might interfere with other slower i2c devices if present).

On the parallel mode, it is a bit unfair in that the serial shift register code is using indirect port i/o
while not as fast as direct port i/o, it is MUCH faster than using the SLOW digitalWrite() functions
in the Arduino core code. Currently the 4bit code is not using the indirect port i/o functions. This would be
a small change to the code and would speed up the 4bit code quite a bit.

I'll definitely give that a try at some point as I have plenty of 595N's coming. I think I'll be off to design a new 2W SR based backpack. :wink:

I guess the only difference is with controlling multiple LCD's. With 2W SR would I need another 2 pins for a an LCD displaying different data?

How does the library handle daisy chained SR? Does it, or would it be possible, to support multiple LCD's by writing 16, 24, 32 bits across multiple SR to display the same or different data on each? I'm thinking of this from the way ShiftPWM works. If you actually have 2 SR connected, but specify only 1 then the data gets repeated on the second.

Maybe the SR constructor could include a NUM_SR data to effectively specify how many LCD's. I suppose you'd need some kind of reference to each one for lcd.write() etc, such as lcd1.write, lcd2.write like you would if declaring multiple constructors normally.

There are three different SR device layer interfaces.
SR - output bits and wiring is hard coded but supports 2 wire or 3 wire mode. Currently no backlight support.

SR2W - (I did this this one) output bits and wiring is hard coded for 2 wire mode (clock, data) but
supports backlight control and has ASCII wiring diagrams in the header file for using various shift registers
and a sample backlight control circuit. Because the output bits/pins are hard-coded and can take advantage of certain
optimizations, it is actually faster than the SR3W code.
As expected, less flexibility = faster. (byte xfer time of 76us for SR2W vs 102us for SR3W)

SR3W - runs with 3 wires (data, clock, latch) and allows configuring output bits to allow any wiring - supports backlight.

The obvious down side of SR modes vs i2c is the number of pins.
I2c adds no additional pins for additional devices whereas SR modes do.
For driving multiple LCDs with the the existing SR code, you can share data and latch pins but not clock pins.
So the total numbers of Arduino pins doesn't have to be replicated for each additional LCD.
It will be I+(N-1) pins. Where I is the initial number of pins (2 or 3) and N is the total number of displays.
So for 4 displays in 2 wire mode it would be 2+(4-1) or 5 pins.

--- bill

I'll certainly play with the SR modes as well.

Noted on the number of pins required for multiple LCD's via SR.

Could you not cascade by connecting Q7S of one into DS of the next, with Latch and Clock shared. If you kept track of whih LCD was to be updated the could you not shift in the required number of bits, with unchanged LCD(s) having the SR bit set to state that would cause no change?

Would that not effectively allow you to daisy chain more and more displays for no extra pins? It might have a speed effect if you had many many displays, but how many would seriously affect update speed by causing so many bits to be shifted in?

I'm not conversant with the low level driving of the LCD's, but it just occurs to me that you might control LCD3, for example, by only changing bits 8-15. With bits 0-7 and 16-31 in a 'neutral' state then LCD's 1, 2 & 3 wouldn't be driven by their SR.

When we you want to drive one display you have to do a full write across all SR but the bits for the others are just set to cause no change?

Many things are theoretically possible. The issue with cascading the shift registers is that the
low level library functions would somehow have to know about this.
The current model is that each lcd object is separate and the configuration data for
each lcd device is contained within its object.
None of the lcd objects know about each other.

The challenge is that you can't really change the other outputs (at least not the backlight output)
when updating any given lcds outputs.
So the code that handles the updating/writing to the SR would somehow have to have knowledge of all
the devices attached and a bit of knowledge of their current state.


The general method the LCD is controlled for writes (which is all that is happening here)
is that the data and control lines are setup.
(d4-d7, RS, RW) and then EN is raised high and then EN is lowered.

The lcd ignores the signals while EN is low.

BTW, I mad a mistake on the sharing of pins above.
It should be
2 wire mode: data pins can be shared but not clock.
3 wire mode: data and clock pins can be shared but not latch.

Sharing pins is actually kind of cheating in that multiple devices are told the pins belong to them.
Since there is no multitasking you can get away with sharing some of the pins between devices.

--- bill

What If you has a software buffer, 8 bits for each LCD that held the last state it was set to.

In each constructor you have a total_lcds and this_lcd item so that each constructor know how many lcds (buffers 1 to x) there are and what it's own position is. When you write to this LCD, say lcd3, you update buffer 3 and just take the contents of all other buffers and do the full x bit shift out with the buffer data in the correct order, before latching for transfer to outputs.

I guess that there is a sequence of events that occurs, so all other LCD buffers would basically need to obtain data that doesn't alter their respective LCD state, such as setting the RW line to read, or not setting Enable like, for example, while the sequence is carried out with buffer(x) data being shifted to the 'active' LCD.

I'm just think in general terms as a question as to whether the methodology sounds like something achievable.

Being able to get a 2 wire implementation, with daisy chained displays, that is faster than I2C with the same wiring benefits, would be quite an achievement.

tack:
Being able to get a 2 wire implementation, with daisy chained displays, that is faster than I2C with the same wiring benefits, would be quite an achievement.

But I2C can be much faster than 100kbit if you use faster i2c chips and bump the clock rate.

Another way to communicate for use on an output only device like an LCD backpack
would be to use the AVR USART's multi-processor mode. That way you only use 1 pin
and can address up to 256 slaves.

--- bill

I'm using an MJKDZ board I2C SPI LCD serial interface
http://www.ebay.com/itm/170926744803?ssPageName=STRK:MEWNX:IT&_trksid=p3984.m1439.l2649
for a 20x4 display...

The following program works for me:

Program:

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

                  //  addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x20, 4, 5, 6, 0, 1, 2, 3, 7, NEGATIVE);  // Set the LCD I2C address

// Creat a set of new characters
const uint8_t charBitmap[][8] = {
   { 0xc, 0x12, 0x12, 0xc, 0, 0, 0, 0 },
   { 0x6, 0x9, 0x9, 0x6, 0, 0, 0, 0 },
   { 0x0, 0x6, 0x9, 0x9, 0x6, 0, 0, 0x0 },
   { 0x0, 0xc, 0x12, 0x12, 0xc, 0, 0, 0x0 },
   { 0x0, 0x0, 0xc, 0x12, 0x12, 0xc, 0, 0x0 },
   { 0x0, 0x0, 0x6, 0x9, 0x9, 0x6, 0, 0x0 },
   { 0x0, 0x0, 0x0, 0x6, 0x9, 0x9, 0x6, 0x0 },
   { 0x0, 0x0, 0x0, 0xc, 0x12, 0x12, 0xc, 0x0 }
   
};

void setup()
{
   int charBitmapSize = (sizeof(charBitmap ) / sizeof (charBitmap[0]));

   lcd.begin(20,4);               // initialize the lcd 

   for ( int i = 0; i < charBitmapSize; i++ )
   {
      lcd.createChar ( i, (uint8_t *)charBitmap[i] );
   }

  lcd.home ();                   // go home
  lcd.print("Hello, ARDUINO ");  
  lcd.setCursor ( 0, 1 );        // go to the next line
  lcd.print (" FORUM - fm   ");
  delay ( 1000 );
}

void loop()
{
   lcd.home ();
   // Do a little animation by writing to the same location
   for ( int i = 0; i < 2; i++ )
   {
      for ( int j = 0; j < 16; j++ )
      {
         lcd.print (char(random(7)));
      }
      lcd.setCursor ( 0, 1 );
   }
   delay (200);
}

The display backlight comes on, which suggests that the I2C is communicating, however I was not able to see anything but the backlighting.

The potentiometer is a multiturn one with little resistance or feedback so I thought perhaps it was damaged. Using a multimeter I was able to see it reducing resistance after many turns, and finally I saw an image. So if you're just getting backlighting - try adjusting the contrast even if it looks like it's not changing.

FM - thanks for the new library!

--creatrope

Hi

I just wanted to mention that i have updated the menu und user interface library M2tklib fo support your New LiquidCrystal Library.
A beta release of M2klib for New LiquidCrystal can be downloaded from the M2tklib project page Google Code Archive - Long-term storage for Google Code Project Hosting.. New LiquidCrystal needs to be installed before using M2tklib.

All in all, adding support for New LiquidCrystal was really easy and the transition was without any problems. Thank you for the excellent library and the great documentation.

Oliver

That is a very cool contribution! Nice one.

it it possible to use this library with slightly a different connection between the LCD and the PCF8574? I'm referring to this schematic https://bitbucket.org/fmalpartida/new-liquidcrystal/wiki/i2c_lcd_schematic.jpg

can this be done by hacking a certain .h or .cpp file? I'm asking this was I'm working on a pbc layout of the above circuit, and that change would simplify things a bit :slight_smile:

edit: it's trivial after all, the documentation was clear :slight_smile:
you just use the appropriate constructor which also defines the EN, RW, RS pins
LiquidCrystal_I2C (uint8_t lcd_Addr, uint8_t En, uint8_t Rw, uint8_t Rs)

Yes, it shouldn't be a problem at all. You shouldn't even need to touch the header files. All the "constructors" can be parametrized. Meaning that you can configure the pin mapping to match your connections. Look at the examples and header files.

It is best to specify all the pins in the constructor including the backlight pin and polarity
(if the board supports backlight control) so you know exactly what you are getting.
Example:

LiquidCrystal_I2C lcd(ADDR, EN, RW, RS, D4, D5, D6, D7, BL, polarity);

Which on your design would be: (no backlight control)

LiquidCrytal_I2C lcd(ADDR, 6, 5, 4, 0, 1, 2, 3);

If you are laying out your own board, you could add a transistor for backlight
control. It will only add a few cents to the cost and would save having to promote
an extra pin/wire on the connector for backlight control.
(Would allow you to use a 4 pin header and cable instead of a 5 pin)
The only draw back is that you wouldn't be able to do dimming since the P7 port
on the PCF8574 can only do on/off to drive the transistor.

--- bill

If you go to my web page you can download the schematic and PCB layout cad files too.

By the way Bill nice going with the library and 1wire driver, connection and schematic! I've been out of contact for a few months (work keeping me very busy). I'll try to catch up a bit.

thanks a lot for the replies and the awesome library!

Hey yall,
I'm looking for some real base level help here, and I'm hoping that this is the place. I have a Uno, a generic 20x4 LCD with a QC2004.a and a YwRobot LCM1602 IIC v1 I2C controller on the back. I have done a clean install of both the 1.0.1 and 1.0.5. The stock LiquidCrystal library has been replace with version 1.2.1 of FMalpartida's New LiquidCrystal library. Using a sketch from http://arduino-info.wikispaces.com/LCD-Blue-I2C#v1 (corrected for the library name). The problem I running into is that the sketch wont compile. It keeps throwing the following errors.

\libraries\LiquidCrystal\I2CIO.cpp: In member function 'int I2CIO::begin(uint8_t)':
\libraries\LiquidCrystal\I2CIO.cpp:68: error: 'class TwoWire' has no member named 'read'
\libraries\LiquidCrystal\I2CIO.cpp: In member function 'uint8_t I2CIO::read()':
\libraries\LiquidCrystal\I2CIO.cpp:121: error: 'class TwoWire' has no member named 'read'
\libraries\LiquidCrystal\I2CIO.cpp: In member function 'int I2CIO::write(uint8_t)':
\libraries\LiquidCrystal\I2CIO.cpp:144: error: 'class TwoWire' has no member named 'write'

Im looking, but I have not been able to find anything relevent out there to help me out. Any ideas?

Thanks!

Fixed. There was an old wire library running around on my system. No idea where it came from tho. lol.

Thanks for letting us know that you solved it. I was about to suggest to lookout for any other library cause a collision.

I'd like to use this library with a 595 shift register and an attiny45/85. With the older deprecated arduinoshiftreglcd library, it would be

#include <ShiftRegLCD.h>

const byte dataPin  = 10;    // SR Data from Arduino pin 10
const byte clockPin = 11;    // SR Clock from Arduino pin 11

ShiftRegLCD srlcd(dataPin, clockPin, TWO_WIRE);

and it compiles for attiny85 (Arduino IDE 1.5.5 and https://code.google.com/p/arduino-tiny/ cores)

With the New LiquidCrystal library, I think the corresponding example is the HelloWorld_SR.ino:

#include <Wire.h>
#include <LiquidCrystal_SR.h>

LiquidCrystal_SR lcd(8,7,TWO_WIRE);
//                   | |
//                   | \-- Clock Pin
//                   \---- Data/Enable Pin

but that gives some errors about I2CIO.cpp and Wire.h. Why is it necessary to include the Wire.h library in this case (which will obviously give errors for attiny)? Isn't that needed only for an I2C connection?

Hi all,
Sorry if I open upp an old thread.
I have a picture explaining the adress setting on a ebay module from MJKDZ named I2C lcd1602 (Older rev.)

Maby someone will be helped from it?

rgds.
Niklas

Hello,

Any idea how can i use the unused output (Q0) ?

Im using this library with 74HC595.