Utility to find LCD i2c address and write it to EEPROM

I searched the web for a sketch that would determine a display’s i2c address and write it to EEPROM for subsequent uses. I couldn’t find any, so I wrote my own. I useed the EEPROM extended library, because other parts of my sketch require it, but this utility only really needs the standard EEPROM library, since it only deals with bytes. It seems to work so far. Note that there are only 2 addresses for this part: 0x3f or 0x27. Now, if someone has to replace the LCD screen, in theory, it should be plug & play. LOL

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

#define BLUE_LED 6
#define RED_LED 7
#define WHITE_LED 8

void setup() {
  Serial.begin(9600);
  pinMode(BLUE_LED,OUTPUT);
  pinMode(RED_LED,OUTPUT);
  pinMode(WHITE_LED,OUTPUT);
}

void loop()
{
  LCD_i2c_Scan();
  delay(5000);
}
void LCD_i2c_Scan()
{
  byte error;
  byte address;
 digitalWrite(RED_LED,LOW);
  
 
    Wire.beginTransmission(27);
    error = Wire.endTransmission();
 
    if (error == 0)
    {      
     EEPROM.writeByte(100,27); 
     
     for(int count = 0; count < 20; count++)
          {
          digitalWrite(BLUE_LED,HIGH);
          delay(200);
          digitalWrite(BLUE_LED,LOW);
          delay(200);
          }
          Serial.println("LCD Address is 0x27, written to EEPROM address 100");
          delay(5000);     
    }
    
    else if (error!= 0)
    {
      Wire.beginTransmission(63);
      error = Wire.endTransmission();
         if(error == 0)
         {
          EEPROM.writeByte(100,63);
          
          for(int count = 0; count < 20; count++)
          {
          digitalWrite(WHITE_LED,HIGH);
          delay(200);
          digitalWrite(WHITE_LED,LOW);
          delay(200);
          }
          Serial.println("LCD Address is 0x3f, written to EEPROM address 100");
          delay(5000);
         }
    }
    else
    {
      while(true)
      {
      digitalWrite(RED_LED,HIGH);
      } 
    }    
  }

I added this to the setup() in the main program, so it only has to run the utility once;

if(EEPROM.readByte(100) != 63 && EEPROM.readByte(100) != 27)
  {
   LCD_i2c_Scan();
   delay(1000);
  }

…and added this line at the top of the program, where the LCD object is defined:

LiquidCrystal_I2C lcd(EEPROM.readByte(100),20,4);

JohnDeere630: Note that there are only 2 addresses for this part: 0x3f or 0x27.

Not exactly. Those are two addresses, but there can be more. There are two based addresses depending on the chip used. 0x20 and 0x38. Then there are 3 address jumpers than can be set. Some backpacks set them to low and some high by default. That means that means "out of the box" you can see 0x20, 0x27, 0x38 or 0x3f. And if the user solders the address jumpers it could be any address between 0x20 and 0x27 or 0x38 an 0x3f

Now, if someone has to replace the LCD screen, in theory, it should be plug & play. LOL

Couldn't agree more about things being "plug & play". However, not only can the i2c address be different on different backpacks, but the way the PCF8574 chip is wired up to the LCD data and control lines as well as the backlight control circuit can be different.

If you want plug and play, have a look at using my hd44780 library. The hd44780_I2Cexp i/o class will auto locate the i2c address, and then auto detect the pin mappings and the backlight control of the backpack. This allows it to "just work" with the half a dozen or so different backpack designs that are floating around out there.

It is available in the library manager. You can also read more about it here: https://github.com/duinoWitchery/hd44780

--- bill

@bperrybap,

Thanks! I'll look into it. I didn't come across your library in my initial googling. All the LCD boards I have came from the same vendor, and I have only seen the 2 addresses, although it seems logical there would be more. Running an i2c scanner and putting the returned address in the sketch is easy enough, but I wanted something that was automatic, more as a learning exercise than anything.

I suppose I could write a function that scans all 127 possible addresses....LOL

Thanks again!

Update,

I rewrote it to check every address between 8 and 119, (according to Mr. Gammon's most excellent i2c reference, addresses 0-8, and 120-127 are reserved), and write the found address to EEPROM. I also noticed my original is NOT plug and play, as once one of the two addresses was written to EEPROM, the if statement in setup() would always return false, and never run the utility...doh! :blush:

I'll test this tomorrow, and post it if it works, and if it doesn't, I won't.

JohnDeere630: Update,

I rewrote it to check every address between 8 and 119,

Totally, unnecessary. I gave you the possible addresses in post #1.

But as I also mentioned in post #1 the wiring between the PCF8574 and the LCD as well as the backlight control circuit can be different as well. The library you are using assumes this wiring:

PCF8574    LCD
--------------
 P0         RS
 P1         RW
 P2         E
 P3         Backlight (Active HIGH)
 P4         DB4
 P5         DB5
 P6         DB6
 P7         DB7

There are multiple backpack designs out there. When you buy one, You really don't know which one you will get. So If you end up with a backpack that uses a different wiring or different backlight active level, that library won't work, even if the i2c address is correct.

--- bill

Bill, I appreciate your feedback, you obviously know a great deal more about this than I, but all I am looking at doing is automagically finding the LCD's i2c address and incorporating it into a running sketch without having to manually edit the sketch. This is purely a learning bit for me, as obviously, I have a lot to learn. In this context, I am not concerned with which particular backpack it is, nor it's exact connection to the LCD, nor the library to use the LCD; I know that there may be many other combinations out there, but they all use a unique address to work with the arduino, and that is all I am concerned with in this function. This function could be used with any i2c device, not necessarily an LCD display.

If I may give a bit of background to put things in perspective; I designed an arduino-powered gadget that monitors a number of sensors and operates a collection of solenoid valves, relays and motors in a fairly harsh environment, and outputs the status on a 20 x 4 LCD. These devices for arduinos are basically toys, but they are cheaper than industrial-rated components; I can get these LCDs for $12, so if one gets wet, or freezes, it's not a big deal. The idea behind this function is that when I plug a new one in, I won't have to jigger with a laptop to edit the sketch, just plug it in, turn on the Aduinio, and go back to work.

I am no expert, for sure, as I still can't get my head wrapped around the proper use of pointers...LOL

The idea behind this function is that when I plug a new one in, I won't have to jigger with a laptop to edit the sketch, just plug it in, turn on the Aduinio, and go back to work.

What I'm trying to get across is that just detecting the i2c address of the PCF8574 chip on the backpack isn't enough. The next i2c LCD you buy may have the PCF8574 on the backpack wired up to the LCD differently than the one you are using now. The wiring between the PCF8574 to the hd44780 pins is in etch traces on the PCB of the backpack. There is no standard for how to connect a PCF8574 to an hd44780 LCD. As a result there are close to half a dozen different ways that vendors are doing it. If the next one you buy is wired up differently to the LCD from the way the one you are currently using, it won't work with the LiquidCrystal_I2C library you are using even if you get the correct i2c address of the chip correct. That is why I was suggesting you take a look at the hd44780 library. It can not only locate the i2c address but also auto detect how the PCF8574 is wired up to the LCD and whether the backlight is controlled by an active high or active low signal. This allows it to work with any of the backpack designs unlike the LiquidCrystal_I2C library which only works with one design.

In terms of address detection for devices the i2c addresses are assigned by NXP the owner of the i2c spec. For specific addresses you can look at the datasheet for the slave device. For PCF8574 chips used on these LCD backpacks the address ranges are 0x20 to 0x27 and 0x38 to 0x3f

--- bill