Help ! How to dynamically select 1of2 descrete I2C addresses on an LCD I2C.

Apologies... Posted in possible wrong forum

First time posting, so please give me a bit of patience if I stray, but I'll try and be on point.

I have been working with a project(s) that use a 20x4 Line LCD display with the Serial I2C interface.
All of the displays I have used to date have had the default address of 0x27 Hex.
Last week I received some additional modules, lo and behold "no Display data". Tried a second LCD and same scenario. I2C Scanner to the rescue, it revealed an address of 0x3F Hex. And no way to change the address to 0x27, you can get it to 0x38 by shorting All address lines.
The Problem is the older I2C interfaces have had the PCF 8574T Chips and the New I2C interfaces have the PCF8574AT Chip. Difference is one has a default value of 0x27 the other has a default of 0x3F.

Here is my request for help: (Finally)
There is a way to interrogate the I2C bus and find one (0x27) or the other (0x3F) address.
But how can I insert that discovered address (byte addr) into the
[ (LiquidCrystal_I2C lcd(addr,2,1,0,4,5,6,7,3,POSITIVE); ] object?

I have tried a couple of simplistic approaches but unsuccessful.

I hope someone has seen this problem before and solved it. !

You use two instances:

LiquidCrystal_I2C lcd_A(addr01,2,1,0,4,5,6,7,3,POSITIVE); 

LiquidCrystal_I2C lcd_B(addr02,2,1,0,4,5,6,7,3,POSITIVE);

Don

Thanks for the reply... I need to clarify the issue.
I have one common sketch that I use for multiple applications. All of the LCD addresses have been up to now (0x27Hex).
I ordered some additional LCDs and their address is (0x3FHex).
I do not wish to maintain two separate programs one for 0x27 and one for 0x3F if at all possible.

Therefore my task is as follows:
interrogate the I2C bus for the possibility of either (0x27) or (0x3F) addresses, depending on which one
is detected, assign that address to the [LiquidCrystal_I2C.lcd(0Xyz),2,1,0,4,5,6,7,3,POSITIVE).
Where (0Xyz)= Decoded address either 0x27 or 0X3F.
ANd do this without intervention of any type.

In a nut shell automatically detect the I2C address for the LCD installed and assign that address to the
LiquidCrystal_I2C.lcd object..

What you want to do is not call the constructor until you know the address.
You could do this by declaring the object but not calling the constructor with all the parameters.
Unfortunately, that won't work with the current code because there is no base constructor that doesn't require any
arguments (including the address which you don't know yet).

You have a few options

  • Go Don's route with multiple objects but that is messy and would potentially need 16+ objects to account for all the addresses plus it makes a wreck of the main code since the object name changes when the address changes.

  • Just fill in the constructor with a default address then call the constructor to reassign the parameters when you know the real address (should it be different from the default one you assigned) by using:
    lcd = LiquidCrystal_I2C( all the correct parameters here);
    This will work but it may loose a little bit of memory (not sure if the C++ on the AVR cleans up in the absence of a destructor function)

  • modify the library to allow you to patch the address.
    To do this, will need to move the _Addr field out of the private section into the public section in the LiquidCrystal_I2C.h header file.
    This is a bit ugly but it it is pretty simple and will allow you do this:
    lcd._Addr = address;
    To modify/change/assigne the i2c address at any time. Just remember that you must call begin() at least once after you have set the proper address.

In either of the lower two cases you will have to determine the i2c address in your setup() function.
If you don't know how to do that, it is fairly simple. You can look at the i2c scanner to see the sequence of how to determine if a device is answering a given address.

--- bill

1 Like

gusgaglio:
I do not wish to maintain two separate programs one for 0x27 and one for 0x3F if at all possible.

Nonsense.

That is of course, exactly what you need to do, but only in the sense of one point.

The "addr" is a declared constant at the very beginning of your code - you just change that constant when you upload the code to a particular unit. There is no need to maintain different "versions" of the code, you just switch the address if required as the last thing before you upload. It isn't rocket science.

Of course, you can adapt the "I2Cfinder" code to do this automatically (you only need a line or three of the code, only one test if there are only two alternatives), but I cannot see why it would be worth the bother. Do you intend to "dynamically" swap displays on a given MCU unit? Why?

Thanks for all the input folks.
Bill, I followed your suggestion, and it became clear as a bell.

A few lines of code added to existing program and problem solved.
Default address 0x27, test in setup for 0x3F , if there change address and go happily to loop.

Thank you all.
Problem solved

Paul__B:
Of course, you can adapt the "I2Cfinder" code to do this automatically (you only need a line or three of the code, only one test if there are only two alternatives), but I cannot see why it would be worth the bother. Do you intend to "dynamically" swap displays on a given MCU unit? Why?

We don't really know much about project involved.
It may be that the situation does not require dynamically swapping displays with different addresses but does require runtime determining the address at startup.
This could be the case if the code is not developed and hard coded to work with the final display h/w.
For example, a product might come with a pre-programmed AVR and then the user adds their display or potentially replaces a broken display with a new one. Or perhaps there a single common f/w build and then the displays are added later and there is no guarantee as to what the i2c address will be. For these situations it would be very inconvenient to have to re-build the firmware in the AVR.

--- bill

bperrybap:
Or perhaps there a single common f/w build and then the displays are added later and there is no guarantee as to what the i2c address will be.

That was what I meant by dynamically swapping displays.

As usual, we will never know the reason. :grinning:

Thanks for a helpful post and a useful reply from bperrybap. Solved my problem.

I have several arduino based builds all running the same sketch. I no longer need to keep a note of which chip is on the LCD and to make sure I pick the correct conditional compilation when uploading. Now one sketch works whatever the hardware.

Huge thanks bperrybap!

Modified my LiquidCrystal_I2C.h as suggested and updating the lcd._Addr with the scanned address worked splendidly.

Just remember your changes when you have something needing to run multiple displays

Really good point INTP! I commented the daylights out of this code with explicit instructions and a link to this post so I could reference it sometime down the road (like if I ever update the I2C LCD library) because I surely will have moved on from what I did here.

I've purchased boards on eBay twice now and unjumpered have come up with two different addresses. At that point I though"well this sucks", that was before several hours of trying to beat my code into submission which sucked even more. If I ever get real serious about larger projects, I think I'll just pony up and purchase through a channel where I can get repeatable results. Very cool to see this post, and learned a couple more things about OOP. Probably that I need to do some more reading. :slight_smile:

Best!

  • Bill

Original post:

The Problem is the older I2C interfaces have had the PCF 8574T Chips and the New I2C interfaces have the PCF8574AT Chip. Difference is one has a default value of 0x27 the other has a default of 0x3F.

Reply #11:

I've purchased boards on eBay twice now and unjumpered have come up with two different addresses.

Both of you are turning what should be considered a feature into a perceived problem. By providing three selectable address pins the original PCF 8574T chip gave you the ability to individually deal with up to eight of these devices on one I2C bus.

With the availability of the PCF8574AT, which is essentially an identical chip with a different address range, you now have the ability to individually deal with up to sixteen devices on the same I2C bus.

It's not that the 'A' model has replaced the original chip, it is available in addition to the original one. The problem is that the manufacturers of the adapter boards sold on ebay seem to indiscriminately use whichever chip happens to be on hand at the time. At least they did (in most cases) provide jumpers with which to select any one of the eight possible addresses for the chip that is present.

Don

Yep. Nice feature. I managed to secure a device with which I was able to apply a thin layer of unknown chemicals to the PCB of the I2C backpack to indicate what the I2C address of each particular LCD display was.

To the layperson you could say it looks a lot like I took a Sharpie and wrote on the PCB "0x3F".

If you only ever want to run single LCDs on your projects and want them to all have the identical I2C addresses so you can grab one out of the bin and have it work without having to go through the drudgery of typing in 2 characters, you can buy your LCDs and I2C backpacks separate. Buying backpacks en masse from the same source should essentially guarantee you get all of the same chip, either 8574T or 8574AT. You can even desolder and replace those pesky misfits you currently have and incinerate them for all the heartache they have caused you.

That is a really nice feature, however there is not any benefit in my case since my design has but one I2C device. The only reason I've gone to this solution is to shave off a few needed pins so they are available for my end users to play with. This project is aimed squarely at the DIYer market, but not necessarily to those savvy in electronics, so the possibility of having a part go bad and having to screw around with jumpers to make sure they've got a viable replacement en-route quickly just isn't something that interests me. Make no mistake, there would be nothing perceived about my annoyance if this were the only option available. Even with the existing thin layer of unknown chemical :slight_smile:

Bperrybap's solution in this case was quick and dirty and ended a blurry-eyed session of wanting to take a bat to the computer. Time will tell how I plan my purchasing efforts, though will probably continue to remain with the scanning code as there will already be a mix of boards out in the wild.

Will there be more I2C devices added in the future? Who knows, but I'll document what I've done and it will be up to the end user at that point to instantiate their own toys.