two 16x2 lcds + mcp23017

hi guys I'm learning how to drive a 16x2 lcd by a mcp23017
I've found the LiquidTWI2 librarie and I can drive well my lcd but on my mcp there are 7 free pins
now, my question is can I drive with the mcp another one 16x2 lcd?

we are talking to drive the lcds in i2c :wink:

I2C protocol uses ADDRESSES instead of chip selects so if you have two I2C lcds, they cannot have the same address.
One solution is a backpack with an ADDRESS dip switch like this one:
http://www.ebay.com.au/itm/New-IIC-I2C-TWI-SPI-Serial-Interface-Board-Module-Port-For-2004-1602-LCD-Display-/261176654807?pt=LH_DefaultDomain_0&hash=item3ccf577bd7&_uhb=1

If you want to see how that works you can read Reply #22 on this post:
http://forum.arduino.cc/index.php?topic=210349.15
and it will show all the addresses available using this backpack (I2C adaptor).
The difference between this and the lcd you are using is that you probably can't change the address on yours and also
this is not an lcd , it is a Parallel to i2C adaptor that converts a 16 pin parallel lcd to I2C and provides a dip switch so
you have a total of 8 combinations (including all switches OFF) allowing 8 lcds to operate from the same uController
using different addresses. Each set of code for one of the eight would have to have the lcd descriptor before any code
for that lcd and the next lcd code would have a different descriptor so if you look through the program it looks like
the lcd is being reinitialized repeatedly until you look at the descriptors and see they are all different addresses and
the code for one is not being executed by the others because they have different addresses.
To do what you are asking with this product you would need to purchase two of these adaptors and two standard
parallel lcds. You would then need to solder a 16 pin inline header on the parallel lcds so you can plug them into the
backpack (adaptor). .Once they are plugged in and the dipswitches set , they are I2C lcds and the backlight is controlable
with software. If you choose this approach, be sure to copy the descriptor information in Reply#16 of that post so
you will be able to configure your adaptors. You can then follow the instructions in Reply #22.
I don't know how to change an address on an I2C lcd that has the backpack soldered to the lcd and does not
have a dipswitch. I don't know if it is even possible to change the address on most I2C lcds. That's why I bought
one of these adaptors.

my question is can I drive with the mcp another one 16x2 lcd?

Yes. As a matter of fact you can drive many more LCDs from a single MCP23017 although I doubt you would find a library already written to do so.

You need to dedicate five pins on the MCP23017 for all of the RS, D4, D5, D6, and D7 pins. Each of the remaining nine pins would go to the individual E pins.

As you can see this means that you can drive up to nine LCDs with your Arduino and each can have it's own message.

Don

we are talking to drive the lcds in i2c

raschemmel:

we are talking to drive the lcds in i2c

Yes, that is precisely what the MCP23017 is for.

The point is that it may require customisation of the library in two regards, one being to function with the different chip select allocations, and the other to ensure that calls are "atomic" so that only complete command sequences are sent to a given LCD.

Actually, if the library already supports the MCP23017 and individual constructors can describe the respective chip selects, it probably will work already.

The suggestion of nine displays presumes you control all the backlights as one, otherwise four displays.

That's a lot of functionality for $1.20.

The suggestion of nine displays presumes you control all the backlights as one, otherwise four displays.

I didn't consider the backlights at all. I guess that's because my ancient displays have no backlights.

I didn't count correctly either since there are 16 I/O pins you could run 16 - 5 or 11 displays without backlight control.

You might want to settle for fewer displays so you could keep all of the data lines on one port and all of the control lines on the other. This would also let you use an 8-bit interface for the LCDs which would further simplify the programming.

Don.

The point is that it may require customisation of the library in two regards, one being to function with the different chip select allocations, and the other to ensure that calls are "atomic" so that only complete command sequences are sent to a given LCD.

It's not as bad as it sounds. All of the LCDs always get the same data and the same register select signals simultaneously. Only the one(s) with the Enable pulsed will react to those signals.

I've already done this for four LCDs without the MCP23017 (http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1265969050) but I can't recall if I did more than one LCD with the MCP23017. I'll poke around and see if I can find out.

Don

floresta:
It's not as bad as it sounds. All of the LCDs always get the same data and the same register select signals simultaneously. Only the one(s) with the Enable pulsed will react to those signals.

I was thinking in terms of ensuring that the command sequence to each LCD should be kept separate, or at least that the invocations of the library should be kept separate. Presumably they will be anyway. Does the standard library allow for a MCP23017 as against the PCF8574?

Paul__B:
Does the standard library allow for a MCP23017 as against the PCF8574?

Which "standard" library are you refering to?

or at least that the invocations of the library should be kept separate

I'm just curious, on that subject, could you do something like the following ?
For Enable lines 8, 9, 10, & 11,

int i=9;
/* Create an instance of the LCD library. */
for (i=9;i<12;i++)
       {
       LiquidCrystal lcd(12, i, 5, 4, 3, 2);
        lcd.init;
        lcd.print("hello world");
        }

I'm just curious, on that subject, could you do something like the following ?
For Enable lines 8, 9, 10, & 11,

You do need several instances of the library but I'm not a C programmer so I don't try doing everything in loops. Follow the link in reply #7, I think I answered your question there.

Don

Yeah, I saw that yesterday, (the photo of 2 lcds and the other of 4 lcds ) and you had separate instances.
I saw that.
My reason for asking about the loop is to ask if that is not the same thing ?
Each iteration through the loop is an instance so when it exits the loop you have four instances don't you ?
I guess the question I was asking is :
Is there any reason why you cannot use a loop like I suggested ?
This:

 As TchnclFl mentioned, you have to start two instances of the LCD library which I think you would do somewhat like this:
LiquidCrystal lcd1(12, 11, 5, 4, 3, 2);
LiquidCrystal lcd2(12, 10, 5, 4, 3, 2);
(note that the Enable lines are assigned to different pins)

and this:

int i=10;
/* Create an instance of the LCD library. */
for (i=10;i<12;i++)
       {
       LiquidCrystal lcd(12, i, 5, 4, 3, 2);
        lcd.init;
        lcd.print("hello world");
        }

are the same as far as the s/w and h/w are concerned aren't they ?
I'm not questioning the method you proved in the other post. I am simply asking if
a loop is the same thing or not, because I want to know.

in relation at the mcp I've found the LiquidTWI2 library to drive the mcp and the lcd
it drive well the lcd but I'm looking for how work this library to assign the pin and the data to the lcd

I suppose when I know that I will drive 2 or more lcds with the mcp
if any one wants to help me every thing is well accepted XD

raschemmel,
Its not really the same thing. The single lcd object you are using in your loop is an automatic and
has to be intialized each time. This does all kinds of things, from initializing the object
to clearing the display and will be very time consuming because of the call to
lcd.begin(rows, cols) (which is missing in your example) that must be in the loop.
If you look at the i2clcdguesser sketch it does this. But in it's case there is only
a single lcd so it re-uses the same object.

In the more general case of supporting multiple LCDs, you really want to have
multiple objects and have a seperate LiquidCrystal object for each physical LCD module.

So the better way is to declare an array of LiquidCrystal objects, then initialized them in setup().
Then simply use them by referencing them.

i.e.

// create lcd objects.
#include <LiquidCrystal.h>
LiquidCrystal lcd[] = {
	LiquidCrystal(12,  9, 5, 4, 3, 2),
	LiquidCrystal(12, 10, 5, 4, 3, 2),
	LiquidCrystal(12, 11, 5, 4, 3, 2),
	LiquidCrystal(12, 12, 5, 4, 3, 2)
};

#if 0

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd[] = {
	LiquidCrystal_I2C(0x27,2,1,0,4,5,6,7,3,NEGATIVE),
	LiquidCrystal_I2C(0x38,6,5,4,0,1,2,3,7,NEGATIVE),
};
#endif

struct lcdGeometry
{
	uint8_t rows;
	uint8_t cols;
};
// geometry for each display
const lcdGeometry lcdGeom[] = {
	{ 2, 16},
	{ 2, 16},
	{ 2, 16},
	{ 2, 16}
};

void setup()
{
const int numLCDs = sizeof(sizeof(lcd)/sizeof(lcd[0]));

	for(int i = 0; i < numLCDs; i++)
	{
		lcd[i].begin(lcdGeom[i].cols, lcdGeom[i].rows);
	}

	for(int i = 0; i< numLCDs; i++)
	{
		lcd[i].print("Hello World");
		lcd[i].setCursor(0, 1);
		lcd[i].print("Display #");
		lcd[i].print(i);
	}
}

void loop(){}

You can use any lcd object you want in the list.
(4bit, SR, i2c etc...)
The restriction of using an array is that all the objects have to be the same type.
4bit or i2c types etc...
If you use seperate objects not in array, then the types can be mixed and matched as desired.

For supporting multiple LCDs using the same MCP23017, all you would need
is a library that allows you to specify the pins in the constructor.
Maybe something that uses pin numbers 0-15 where 8-15 are portB pins.
If you have that, you could simply create an array like the i2c example above.

But in the larger sense driving multiple LCDs from a single i/o expander chip
seems a bit odd. Normally, with multiple displays
you would simply use a MCP23008 or PCF8574 on each display.

Although when using multiple displays on a single i/o expander,
you could actually write to more than one at the same time by simply
strobing E on all the displays you want to write to.

--- bill

SaxXx,
For clarification, when you say you want to drive two lcds, do you mean
independently or do you want them to show the same thing?
If they are to show the same them just make sure sure that r/w is wired to ground
and then hook up all the wires the same for both of them.

If you want to control them independently, like I mentioned above in the previous post,
you will need to be able to specify the pins.
If the LiquidTWI2 library you are looking at is the one for the
AdaFruit RGB LCD here:

Then you are in for quite a bit of work as everything is hard coded for that library with defines.
Yes you can change some defines to move some pins around,
but the library is very much hardcoded for that AdaFruit hardware. (LCD with RGB backlight and buttons)
And in some cases, if you move the pins around changing the defines, other defines and code
will break becuse they assume that pin mapping.

My opion is that it would be easier to start over and write a slim mcp23017 i2c device layer for fm's library.
That way you could simply treat pin #s 8-15 as pins for the B port.

--- bill

Thanks. I wouldn't have thought of that.
Great answer !

Here's my shorter version which I wrote a while ago and forgot to post.

This ... and this ... are the same as far as the s/w and h/w are concerned aren't they ?

I don't think so. You will wind up with nine versions of the same constructor instead of nine different constructors. Perhaps you overlooked the LiquidCrystal lcd1 vs the LiquidCrystal lcd2.

Don

Yes, your right, I did certainly overlook that.

floresta:
Here's my shorter version which I wrote a while ago and forgot to post.

This ... and this ... are the same as far as the s/w and h/w are concerned aren't they ?

I don't think so. You will wind up with nine versions of the same constructor instead of nine different constructors. Perhaps you overlooked the LiquidCrystal lcd1 vs the LiquidCrystal lcd2.

Don

The loop declares and initializes a single automatic object which only exists while the loop is active.
The code in the loop is calling the constructor for the same single object with the
given paramters each time through the loop.
As soon as the loop finishes the object is gone.

To be able to use the object later, it needs to be in static storage.
It makes no difference if you use objects with different names or an array
of objects with the same name. The only thing that changes is how you
reference the objects.

--- bill