New LiquidCrystal library - LCD library

Thanks for the update!

When using a shift register in 2-wire mode, is it possible to control the backlight with bit 1 of the shift register? My backlight is hooked up according to this schematic.

Thanks!

Woobatron,
yes, you can.
While the SR interface code supports both 2 wire and 3 wire modes,
currently only the SR2W interface code has support for backlight control.
From your link to the schematic it looks like you are using a unlatched SR register like the 74LS164 vs using
a 74HC595 in a "non latched" mode (you can see my version of that just a bit lower on the same page
you linked to)

If you look in the header file LiquidCrystal_SR2W.h you will see a detailed explanation
along with ASCII art of how to hook up either SR register for backlight control using bit 1 of the SR.
If you are looking for a simpler anti-flicker circuit, I also included a diagram for simple backlight control circuit that
also removes the flicker. It uses a FET but is simpler
and more power efficient than the one in the schematic you linked to.

Note:
The ascii art in the header file needs a bit of an update.
I'm now using 4.7k resistors for all resistors except the current limiting resistor
and the diode is a 1N4148.

--- bill

Hi Bill
Thanks for the quick reply! Indeed I am using a 74HC595 in 'non-latching' mode. Thanks for that FPS sketch, it's really neat. I didn't know you could use if and elif statements for defined objects like that, super cool.

Anyhoo, I made a harness at work that has a 2x16 connector on one end for the LCD and the SR and everything else soldering in the middle, so I'd just have 4 wires going to the controller on the other end. I used the backlight anti-flicker with the series diodes and transistor but it doesn't seem to be working. Too bad I heat shrunk it all up before testing...d'oh! I can just snip off the LCD part though and try out your FET version.

You mention using a 1n4148, but I don't see it in your ASCII diagram:

// (LCD BL anode)---[ resistor ]---(vcc)
//
// (LCD BL cathode)-------------------------------+
//                                                |
//                                                D
//                                                |
// (BL input)----[ 4.7k Resistor ]----+-------G-|-<  (2N7000 FET)
//                                    |           |
//                          (0.1uf)   =           S
//                                    |           |
//                                  (gnd)        (gnd)

Would it go between the 4.7k/0.1uF and the gate of the FET (cathode towards the FET)?

There is quite a bit of "magic" that can be done using the C pre-processor.

Sorry for the confusion. The diode isn't part of the backlight circuit.
The backlight circuit is as shown in the backlight ascii art.
If you look above the backlight ascii art in the header file you will see the ascii art for the 595 circuit.
That includes a diode but it didn't say or recommend one. That is where I'm using a 1n4148.

--- bill

Clear as mud 8)

I got 'er going now, thanks a tonne Bill.

Hello,

i installed the library and used your I2C Board.
I'm getting this error message: HelloWorld_i2c:10: error: redefinition of 'LiquidCrystal_I2C lcd'

Can you help me?

What version of the IDE are you using?
Did you remove from the library directory the stock LiquidCrystal library that comes with the Arduino IDE?

Sounds more like the second constructor in the demo code was uncommented
which would then mean there would be two declarations for the constructor.


fm,
On a somewhat unrelated note, this brings up an interesting "issue" in the current library.
Currently the function setBacklightPin() is used to set the bit within the output latch
on the communication interface.
i.e. in the I2C code it is a bit that is used on the other side of the i2c interface
and in the SR3W code it is a bit on the SR output latch. (SR and SR2W don't support this function)
But the potential issue is that some boards, like the I2C extra I/O LCD board don't support
controlling the backlight through the interface, they require using an additional Arduino pin.
The library "as is" has no support for this mode of operation, so users are left to having
to use Arduino core functions like digitalWrite()/AnalogWrite() to control the backlight rather
than being able to use the library functions like backlight(),noBacklight() and setBacklight().

What might be nice would be if the code supported using both modes of operation.
i.e. it could use an output pin within the existing interface or assign an Arduino pin
that works outside the interface.

In the glcd library I use some argument overloading (hidden from c++) to handle a few complex arguments.
While it does side step the normal C++ typechecking, it is easy to do and this library could do the same.
It uses a macro to alter the parameter in a way that it can be distinguished.
So for example, it would be possible to do something like:

LiquidCrystal_I2C lcd(0x38, LCD_ARDUINO_PIN(BACKLIGHT_PIN), POSITIVE);  // Set the LCD I2C address

This would allow the constructor or other functions to be able to tell if the argument
is a bit on the output latch or an actual Arduino pin.
The glcd library version of this type of macro simply negates the value by inserting a minus sign.
This allows to code to quickly and easily detect which type of argument is desired.
In this example it would be:

#define LCD_ARDUINO_PIN(pin) (-pin)

The code receiving the argument can simply look if the argument is negative to tell
if it indicates and Arduino pin vs an interface output latch bit.

Some of the needed support for this would move up to the LCD common code and then depending on the
type of backlight "pin" control selected, it would either handle itself , in the case of an arduino pin, or call
the device layers backlight functions.

It is all doable and not very much code, and while it would allow the existing I2c Extra I/o board
to have backlight control, I haven't seen any other boards out there that use a latching interface
to the LCD and then use a separate Arduino pin for backlight control so
it may not be worth the effort to add this support.

--- bill

Hi Bill, sound very good the proposal.

I was thinking of doing an upgrade to de library over Christmas to abstract out the I2C class so that it can be extended to support multiple I2C devices. It might be a good time to also introduce the backlight mod.

Could you add the "issue" in the bitbucket repository so that I don't forget.

Hi, I think you've done an excellent work. I plan to give it a test ASAP.

I looked at the code but did not find something like getNumRows() or getNumCols(). Quick oneliners that I sometimes missed when playing around with lcds. I think their place would be the LCD class.

Also I noticed a little inconsistency in cols/rows variable naming:
uint8_t _numlines;
uint8_t _cols;
IMVHO they should be called _rows, _cols, or _numrows, _numcols or _numlines, _numcols.

My 0.01 cents :slight_smile:

PS: kudos for the docs (and doxygen), not many libraries are that well documented :slight_smile:

@tuxduino - thanks for the comments, very much appreciated. bperrybap is another contributor for the library.
I will note down your coments for the next up date.

I've been using the standard LiquidCrystal library to a while with both LCD shields (DFRobot) and standalone LCD, both in 4 bit mode. These are 16 x 2 displays.

I have just received some I2C backpacks to convert these to I2C.

My first thought was to move to the New LiquidCrystal Library as it uses all the same Classes and Methods but supports different interface methods, including I2C.

When looking to set it up I noticed there is no option to set the data line connections, as there is with the stabard parallel constructor. Also it wants a #define for the backlight pin, where my backpacks control backlight through the I2C chip (PCF8574).

I finally got it working with a standard LiquidCrystal_I2C library from the main Arsuino site, which controls the hackling with a setBacklight() call, rather than needing a separate Arduino pin to do so.

There appears to be two different LiquidCrystal_I2C libraries, one which controls the backlight through I2C and the other that requires backlight control via a separate Arduino pin. The I2C implementation in New LiquidCrystal Library seems to be based on the latter.

For full backwards compatibility it would need to support both methods and also have the flexibility to define whether backlight is on a pin or I2C (and which expanded bit) plus able to define the expanded bits for the other LCD lines.

Another really good idea for flexibility would be to have an optional declaration for contrast, leave it hardware via a trimmer or control in software via PWM/Analog pin.

I see that the I2C pin configuration is planned for v1.13.

Of course, if I'm missing something here and it already does the above then I welcome any pointers in the right direction.

Many thanks.

As commented on a previous thread, the New LiquidCrystal library does not impose a particular wiring of the LCD module to the I2C extension board. You just need to call the adequate constructor method to drive the LCD and map it to its wiring.

The I2C flavor of the library has support for direct backlight control using the I2C. As before, you need to call the correct constructor to enable backlight control.

Just look at the header files and see the method that meets your needs or browse through the documentation.

By default the simple constructor assumes a particular wiring and no backlight support for all driver types (4 wire, 8 wire, I2C, SR1wire, SR2wires, SR3wires it handles.

It is also about twice faster than the LiquidCrystal_I2C (at least when I released it first time). This means a bunch of additional "MIPs" for your application.

As said in the MENWIZ thread, I appreciate the superb support and fast response.

I was looking at the sample files with the library and should have looked deeper I guess. My bad and I'll go find the correct constructors and give it another go with my backpacks.

Thanks again.

Great, thanks for your kind comments.

Do let us know how it goes.

fm,
I think some of the confusion/mis-interpretation could be coming from the wiki home page:
https://bitbucket.org/fmalpartida/new-liquidcrystal/wiki/Home
The examples on that page do not show using the backlight support functions in the library.
They use standard arduino core calls to control arduino pins for backlight control.
Also, the other i2c backpacks out there are wired differently than EXTRAIO
(I've seen 3 different pin wirings - all different from EXTRAIO) and when they support
s/w backlight control, they use a 8574 output bit rather than depend on a separate
Arduino pin for backlight control.

As a suggestion, I think what would could help would be a couple of things:

  • update the examples to better show the constructor parameters.
  • update the examples to use the backlight control functions
  • update the constructors to have an overloaded pin parameter for backlight control
    that can specify either a interface pin or a Arduino pin.
    (but so far I haven't seen any other lcd i2c board other than EXTRAIO that would need to
    use an Arduino pin for backlight control)

After seeing all the confusion about constructors not only for things like i2c and SR device layers
but for the standard LiquidCrystal library, I'd recommend using const int parameters
in all the examples to show what the parameters are.
And in the examples, show all the parameters rather than
the simplified constructors like the i2c one with just the address that use the defaults.
i.e. don't show examples that use a builtin/default pin wiring.
I think many users are really struggling with the i2c constructor because they simply
don't realize that even with i2c that there is a pin configuration/wiring that must still
be specified when a hd44780 is hooked up to a PCF8574.

For example here is what it would be for a MJKDZ i2c backpack that I have:
(different wiring than EXTRAIO)

#include <Wire.h>
#include <LiquidCrystal_I2C>
const int i2c_addr = 0x27;
const int i2c_en = 4; // 8574 output bit wired to LCD EN
const int i2c_rw = 5; // 8574 output bit wired to LCD RW
const int i2c_rs = 6; // 8574 output bit wired to LCD RS
const int i2c_d4 = 0; // 8574 output bit wired to LCD D4
const int i2c_d5 = 1; // 8574 output bit wired to LCD D5
const int i2c_d6 = 2; // 8574 output bit wired to LCD D6
const int i2c_d7 = 3; // 8574 output bit wired to LCD D7
const int i2c_bl = 7; // use number for output bit and LCD_ARDIUNO_PIN(arduino_pin#) for arduino pin
const int i2c_blpol = NEGATIVE; // backlight polarity

LiquidCrystal_I2C lcd(i2c_addr, i2c_en, i2c_rw, i2c_rs, i2c_d4, i2c_d5, i2c_d6, i2c_d7, i2c_bl, i2c_blpol);

This allows users to see the parameters as well as easily modify them for their application.

As I outlined in issue #27, it would be useful to also (at least for EXTRAIO) to add in an overload
for the backlight pin/bit parameter and update code to deal with it.
That way users could specify either an interface pin/bit or an Arduino pin for backlight control.
For example, this would be the example for the EXTRAIO board:
[ Assuming an overloading macro of LCD_ARDUINO_PIN() ]

#include <Wire.h>
#include <LiquidCrystal_I2C>
const int i2c_addr = 0x27;
const int i2c_en = 6; // 8574 output bit wired to LCD EN
const int i2c_rw = 5; // 8574 output bit wired to LCD RW
const int i2c_rs = 4; // 8574 output bit wired to LCD RS
const int i2c_d4 = 0; // 8574 output bit wired to LCD D4
const int i2c_d5 = 1; // 8574 output bit wired to LCD D5
const int i2c_d6 = 2; // 8574 output bit wired to LCD D6
const int i2c_d7 = 3; // 8574 output bit wired to LCD D7
const int i2c_bl = LCD_ARDUINO_PIN(13);  // arduino pin 13 for backlight control
const int i2c_blpol = POSITIVE; // backlight polarity

LiquidCrystal_I2C lcd(i2c_addr, i2c_en, i2c_rw, i2c_rs, i2c_d4, i2c_d5, i2c_d6, i2c_d7, i2c_bl, i2c_blpol);

This type of initalization example would also be useful for the other interfaces well.
For example this would be an example for many of the lcd keypads out there.

// Include the Liquid Crystal library code:
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
const int lcd_rs = 8; // Arduino pin wired to LCD RS
const int lcd_en = 9; // Arduino pin wired to LCD EN
const int lcd_d4 = 4; // Arduino pin wired to LCD D4
const int lcd_d5 = 5; // Arduino pin wired to LCD D5
const int lcd_d6 = 6; // Arduino pin wired to LCD D6
const int lcd_d7 = 7; // Arduino pin wired to LCD D7
const int lcd_bl = 10; // Arduino pin used for backlight control
const int lcd_blpol = POSITIVE; // backlight polarity

#ifdef BACKLIGHT_ON // check for new library being used
LiquidCrystal lcd( lcd_rs, lcd_en, lcd_d4, lcd_d5, lcd_d6, lcd_d7, lcd_bl, lcd_blpol); // new constructor with backlight support
#else
LiquidCrystal lcd( lcd_rs, lcd_en, lcd_d4, lcd_d5, lcd_d6, lcd_d7); // old style constructor w/o backlight
#endif

While these examples are a bit verbose, I think they might help users better understand how to modify
the parameters for their device.

I'll be happy to work with you make this happen if you want to move in this direction.
We can discuss off line.

BTW, I'll be getting and adafruit LCD backpack soon.
That board uses a MCP23008 instead of a PCF8574
so I'll be doing a MCP23008 device layer for it.
This is another area of confusion for some users in that some have
PCF8574 based boards, and some have MCP23008 and yet to them it is just "I2C".
Compounding this is the vendors supply libraries called "LiquidCrystal_I2C".
So some LiquidCrystal_I2C libraries out there are not for PCF8574 based chips.
My plan is to create a MCP23008 i2c device layer I'm just not sure what to call it.
Any suggestions?

FWIW, +1 for such verbose but very clear usage examples.

Hi Bill, sounds like a very good idea. After seeing a good range of queries that have been constantly being brought up in the forum, I think it is a good idea to change a bit the examples that are both in the wiki and in the examples that come with the library. No backpack is identical wiring wise.

Regarding the I2C I was thinking in the lines of writing an abstract class, similar to the LCD class but for different I2C interfaces. I haven't got round to writing it up for several reasons:

  1. Time, I was hoping to do a bit of coding this Xmas break but... kids tend to demand a lot more during the holiday season.
  2. I didn't need it for any of my on going projects (this sounds a bit selfish but I tend to dedicate a bit of time to other projects too).
  3. I didn't think much about how people would initialize and create the particular instance of the I2C module they had. With an abstract class, you would have to pass a reference in the constructor and such constructions would most likely blow some fusses on some newbies and cause more hassle than it would solve. The main idea behind it was using the I2CIO as a generic abstract to access any I2C for the min library. That way, you would just have a class I2CIO that would be used on any porting to any extension module.

Your offer is more than welcome. Please send me an email and we can split the work and we can also try and figure out which would be the most simple and elegant way to solve the problem.

I also like the idea of using the macro to use the backlight. This is something that I feel would be nice to have in the library.

I was also looking to add support for a SPI interface to drive an LCD but time, time, time...

The other thing that I've checked in (I think) is moving the documentation files to a support directory since in the coming Arduino versions it will cause problems importing the libraries into the IDE. I think I committed the changes a few weeks ago.

bperrybap, you are a lifesaver with those clear examples!

I have been playing with this for the last hour and a half and getting increasingly frustrated, but not wanting to come back here and ask further until exhausting my own efforts in consulting the library files.

Anyway, I was just about to post and I saw yours and it made everything clear.

I found the full constructor for ADDR, EN, RW, RS, D4, D5, D6, D7, Backlight, POLARITY and used this for the example sketch.

I also found the reference to setBacklightPin(BacklightPin, POLARITY) and the setBacklight(0-255) and thus set this too.

I was getting nothing!

Why?

Because I was using the 8574 pin numbers in the constructor:-

LiquidCrystal_I2C lcd(0x27, 9, 10, 11, 4, 5, 6, 7, 12, POSITIVE); // addr, EN, RW, RS, D4, D5, D6, D7, BacklightPin, POLARITY
  lcd.setBacklightPin(12, POSITIVE);
  lcd.setBacklight(1);

Your clear examples said to use the BIT NUMBER! Thus I changed to:-

LiquidCrystal_I2C lcd(0x27, 4, 5, 6, 0, 1, 2, 3, 7, POSITIVE); // addr, EN, RW, RS, D4, D5, D6, D7, BacklightPin, POLARITY
  lcd.setBacklightPin(7, POSITIVE);
  lcd.setBacklight(1);

This got me most of the way but the backlight wasn't working correctly.

I was taking the POSITIVE or NEGATIVE to be the style of LCD but, of course, it's referring to whether backlight is set with a HIGH or LOW.

My backpacks have PNP transistors controlling the backlight so the BL is on when LOW or nothing on the transistor base. Pull the base low and the transistor turns off and BL is off.

So, a final change to:-

LiquidCrystal_I2C lcd(0x27, 4, 5, 6, 0, 1, 2, 3, 7, NEGATIVE); // addr, EN, RW, RS, D4, D5, D6, D7, BacklightPin, POLARITY
  lcd.setBacklightPin(7, NEGATIVE);
  lcd.setBacklight(1);

And.....VOILA! Everything working as it should.

I totally agree that the examples need to be clearer. Certainly that reference to BacklightPin is very confusing, as when using the I2C it is actually BacklighBit. I totally understand it is a common setting across all the different connection methods but it is misleading if you haven't got a clear example showing the connection Bits that each LCD line is controlled by on the 8574 IC.

Anyway, happy now that I can use this new library with my projects and with different hardware connection methods. I may well play with the Shift Register method as some SR backpacks would be less expensive than equivalent 8574 versions to have made. I just need to consider any overhead in processor cycles and speed vs the cost saving.

Many thanks again. I'm off to try the MENWIZ library now this is working. :wink:

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.