i2C display + regular display don't work together

Hello,

I'm beginner at Arduino and C++ programming and I have a big problem.
I have 2 LCD's that have to work together. 1 LCD is regular and 1 i2C. I have 2 example codes that work separate but won't work together, need your help guys.

i2C

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

// Set the LCD address to 0x26 for a 16 chars and 2 line display
LiquidCrystal_I2C lcd(0x26, 16, 2);

void setup()
{
	// initialize the LCD
	lcd.begin();

	// Turn on the blacklight and print a message.
  lcd.setCursor(0,0);
	lcd.print("Big Problem!");
}

void loop()
{
	// Do nothing here...
}

Regular with 3 pin connection

#include <Wire.h>
#include <LiquidCrystal_SR.h>
LiquidCrystal_SR lcd(2, 4, 3);



void setup(){

lcd.begin(16,2); // Initializing LCD


}

void loop()

{
lcd.clear();
lcd.setCursor(0,0);
lcd.print(" >> Hello <<"); // Print Something on LCD
lcd.setCursor(3,1);
lcd.print("World ");


delay(2000); // Waiting for a while


lcd.clear(); // Clearing LCD
lcd.setCursor(0,0);
lcd.print("Big"); // Print Something on LCD
lcd.setCursor(5,1);
lcd.print("Problem");
delay(2000); // Waiting for a while


}

I2C scanner

What did the I2C scanner report?

Please show the code of your attempt to combine.

You will have to change the names of the lcd objects.

How old are the LCD libraries that you use ?

A up-to-date library is called "hd44780" by Bill Perry and it is in the Library Manager of the Arduino IDE. It can deal with both of your displays.

Here is an example of how the code would be with both your displays:

// For: https://forum.arduino.cc/t/i2c-display-regular-display-dont-work-together/1048684
// This Wokwi project: https://wokwi.com/projects/347227935571182164
//
// 2 nov 2022
//
// Using the excellent "hd44780" library.
// The library is in the Library Manager of the Arduino IDE.
//
// For explanation and details of the library and the sketch, see these links:
// Library: https://github.com/duinoWitchery/hd44780
// Using pinIO example: https://github.com/duinoWitchery/hd44780/blob/master/examples/ioClass/hd44780_pinIO/HelloWorld/HelloWorld.ino
// Using I2C   example: https://github.com/duinoWitchery/hd44780/blob/master/examples/ioClass/hd44780_I2Cexp/HelloWorld/HelloWorld.ino
//
// The public domain UpTime() function was taken from:
//   https://github.com/duinoWitchery/hd44780/blob/master/examples/ioClass/hd44780_pinIO/UpTime/UpTime.ino
//


#include <Wire.h>
#include <hd44780.h>                       // main hd44780 header
#include <hd44780ioClass/hd44780_pinIO.h>  // Arduino pin i/o class header
#include <hd44780ioClass/hd44780_I2Cexp.h> // i2c expander i/o class header


const int rs=8, en=9, db4=4, db5=5, db6=6, db7=7;
hd44780_pinIO lcd1(rs, en, db4, db5, db6, db7);  // lcd object for pin I/O

hd44780_I2Cexp lcd2;      // declare lcd object: auto locate & auto config expander chip

const int LCD_COLS = 16;
const int LCD_ROWS = 2;

void setup()
{
  Serial.begin(115200);                 // Set the Serial Monitor of the Arduino IDE also to 115200
  Serial.println( "The sketch has started");


  int status = lcd1.begin(LCD_COLS, LCD_ROWS);
  if(status) // non zero status means it was unsuccesful
  {
    Serial.println( "The pinIO LCD failed.");
    // hd44780 has a fatalError() routine that blinks an led if possible
    // begin() failed so blink error code using the onboard LED if possible
    hd44780::fatalError(status); // does not return
  }

  status = lcd2.begin(LCD_COLS, LCD_ROWS);
  if(status) // non zero status means it was unsuccesful
  {
    Serial.println( "The I2C LCD failed.");
    // hd44780 has a fatalError() routine that blinks an led if possible
    // begin() failed so blink error code using the onboard LED if possible
    hd44780::fatalError(status); // does not return
  }


  // Print a message to the LCD
  lcd1.print("Hello LCD One");
  lcd2.print("Hello LCD Two");

  // Optional extra: the library can do line wrap.
  lcd2.lineWrap();
  lcd2.setCursor(0, 0);
  lcd2.print("Optional extra: line wrapping.");
}

void loop()
{
  static unsigned long lastsecs = -1; // pre-initialize with non zero value
  unsigned long secs;
  int status;

  secs = millis() / 1000;

  // see if 1 second has passed
  // so the display is only updated once per second
  if(secs != lastsecs)
  {
    lastsecs = secs; // keep track of last seconds
    lcd1.setCursor(0, 1);
    // print uptime on lcd device: (time since last reset)
    PrintUpTime(lcd1, secs);
  }
}

// PrintUpTime(outdev, secs) - print uptime in HH:MM:SS format
// outdev - the device to send output
//   secs - the total number of seconds uptime
//
// This is a fancy output routine.
// outdev is a Print class object which indicates
// where the output should be sent.
// PrintUpTime can be used with any object that uses the Print class.
// This code works with Serial objects, as well as the the hd44780 lcd objects.
// i.e. you can call with Serial: PrintUpTime(Serial, seconds);

void PrintUpTime(Print &outdev, unsigned long secs)
{
  unsigned int hr, mins, sec;

  // convert total seconds to hours, mins, seconds
  mins =  secs / 60;  // how many total minutes
  hr = mins / 60;    // how many total hours
  mins = mins % 60;  // how many minutes within the hour
  sec = secs % 60;  // how many seconds within the minute
  
  // print uptime in HH:MM:SS format

  if(hr > 99)
    hr %= 100; // limit hr to 0-99

  // Print class does not support fixed width formatting
  // so insert a zero if number smaller than 10
  
  if(hr < 10)
    outdev.write('0');
  outdev.print((int)hr);
  outdev.write(':');
  if(mins < 10)
    outdev.write('0');
  outdev.print((int)mins);
  outdev.write(':');
  if(sec < 10)
    outdev.write('0');
  outdev.print((int)sec);
}

This sketch in the Wokwi simulator:

Beyond requiring that your two lcd objects must have different names,
there can be library & header file name collisions and API differences depending on which libraries you use in your sketch as well has which lcd libraries you have installed.
I.e. you don't necessarily have to be using an installed library for it to have a name collision with a library that you are using.

Which lcd libraries are you using? and which lcd libraries are installed?
Most notably do you have fm's newLiquidCrystal library installed?
newLiquidCrystal has several i/o classes with a header file for each.
Due to the way the IDE works, the IDE can get confused between header files in this libraryand header files with the same name in other libraries.
This is because the IDE guesses which library to use based on which header files it "sees".
For example, both newLiquidCrystal and LiquidCrystal_I2C libraries have a header file named "LiquidCrystal_I2C.h" so things can break.
Even if the IDE guesses correctly, it won't always work since the IDE uses compiler include paths to point to library directories. This is not reliable when the colliding libraries are both being used by a sketch.

I ask about libraries since newLiquidCrystal is the only library I know of with a header file named LiquidCrystal_SR.h for the i/o class that supports using a shift register.
newLiquidCrystal also has a header file named LiquidCrystal_I2C.h for the i/o class that supports a PCF8574 based backpack.

The constructor and APIs for newLiquidCrystal LiquidCrystal_I2C i/o class and the LiquidCrytsal_I2C library are not compatible.
Your example code uses the constructor and initalization API for the LiquidCrystal_I2C library vs new newLiquidCrystal LiquidCrystal_I2C i/o class.

From your description and example code it appears that you might have both
newLiquidCrystal and LiquidCrystal_I2C installed.
If so, that can cause problems particularly since you won't be able to use both in the same sketch due to the way IDE handles libraries.
i.e. it is problematic to try to use LiquidCrystal_I2C for the backpack lcd and newLiquidCrystal LiquidCrystal_SR for the shift register lcd in the same sketch.
Depending on the order of how you do things in your code and/or the version of the IDE, it may or may not work as the IDE can end up picking newLiquidCrystal LiquidCrytal_I2C.h instead of LiquidCrystal_I2C LiquidCrystal_I2C.h
(usually it won't work and there is no work around)

If you are wanting/needed to use the newLiquidCrystal library, then you should uninstall LiquidCrystal_I2C and use the LiquidCrystal_I2C i/o class in newLiquidCrystal
The constructor and initialization API begin() call are different.

Alternatively, you could use other lcd libraries that don't conflict.

--- bill

@Koepel
The OP appears to want to use a shift register to control one of the LCDs.
Currently, there is no support for that in the hd44780 library.
Using hd44780 hd44780_pinIO i/o class would work but would use more Arduino pins than a shift register.

I could add support for a shift register i/o class to the hd44780 library, it isn't' difficult, particularly since I was the one that worked on the LiquidCrystal_SR i/o class for newLiquidCrystal....

I've thought about it; However, I just figured everyone was leaving using shift registers to control LCDs behind since PCF8574 based backpacks are now super cheap like $1-$2 USD shipped to your door.
Back when LiquidCrystal_SR was done (12+ years ago), PCF8574 chips and backpacks were quite a bit more expensive than shift registers. Today, that is not the case.

--- bill

Hi,
if you could do this, it would be great. I realy strugle with those 2 lcds. I ordered my pcbs already with that lcd setup, because im Newbie and didnt know much, so to change 1 LCD is not an option

--Gizi

Hi,

I tried, and it didn't work, only my i2C LCD worked =(

---Gizi

--- Scan started ---
I2C device found at address 0x26 !
I2C device found at address 0x68 !
--- Scan finished ---

Not sure what you mean by that.

You have not provided enough information about your hardware and software setup to be able to help you.

I asked a few very specific questions, that you have not yet answered.

--- bill

Hi,

I'm sorry, I was very excited to try things out that you guys suggested me.

It worked, yes my libraries were conflicting with each other that was my main issue, so I used hd44780 library + the LiquidCrystal_SR library, they work well together and don't conflict. It would be very nice if Bill could add LiquidCrystal_SR to hd44780, then we would have everything in 1 place.

THX a lot!!!
Problem solved!
Here is my working Code!

// vi:ts=4
// ----------------------------------------------------------------------------
// HelloWorld - simple demonstration of lcd
// Created by Bill Perry 2016-07-02
// bperrybap@opensource.billsworld.billandterrie.com
//
// This example code is unlicensed and is released into the public domain
// ----------------------------------------------------------------------------
//
// This sketch is for LCDs with PCF8574 or MCP23008 chip based backpacks
// WARNING:
//	Use caution when using 3v only processors like arm and ESP8266 processors
//	when interfacing with 5v modules as not doing proper level shifting or
//	incorrectly hooking things up can damage the processor.
// 
// Sketch prints "Hello, World!" on the lcd
//
// If initialization of the LCD fails and the arduino supports a built in LED,
// the sketch will simply blink the built in LED.
//
// NOTE:
//	If the sketch fails to produce the expected results, or blinks the LED,
//	run the included I2CexpDiag sketch to test the i2c signals and the LCD.
//
// ----------------------------------------------------------------------------
// LiquidCrystal compability:
// Since hd44780 is LiquidCrystal API compatible, most existing LiquidCrystal
// sketches should work with hd44780 hd44780_I2Cexp i/o class once the
// includes are changed to use hd44780 and the lcd object constructor is
// changed to use the hd44780_I2Cexp i/o class.

#include <Wire.h>
#include <hd44780.h>                       // main hd44780 header
#include <hd44780ioClass/hd44780_I2Cexp.h> // i2c expander i/o class header

hd44780_I2Cexp lcd2; // declare lcd object: auto locate & auto config expander chip


#include <LiquidCrystal_SR.h>
LiquidCrystal_SR lcd1(2, 4, 3);

// If you wish to use an i/o expander at a specific address, you can specify the
// i2c address and let the library auto configure it. If you don't specify
// the address, or use an address of zero, the library will search for the
// i2c address of the device.
// hd44780_I2Cexp lcd(i2c_address); // specify a specific i2c address
//
// It is also possible to create multiple/seperate lcd objects
// and the library can still automatically locate them.
// Example:
// hd4480_I2Cexp lcd1;
// hd4480_I2Cexp lcd2;
// The individual lcds would be referenced as lcd1 and lcd2
// i.e. lcd1.home() or lcd2.clear()
//
// It is also possible to specify the i2c address
// when declaring the lcd object.
// Example:
// hd44780_I2Cexp lcd1(0x20);
//hd44780_I2Cexp lcd2(0x26);
// This ensures that each each lcd object is assigned to a specific
// lcd device rather than letting the library automatically asign it.

// LCD geometry
const int LCD_COLS = 16;
const int LCD_ROWS = 2;

void setup()
{
lcd1.begin(16,2); // Initializing LCD
int status;

	// initialize LCD with number of columns and rows: 
	// hd44780 returns a status from begin() that can be used
	// to determine if initalization failed.
	// the actual status codes are defined in <hd44780.h>
	// See the values RV_XXXX
	//
	// looking at the return status from begin() is optional
	// it is being done here to provide feedback should there be an issue
	//
	// note:
	//	begin() will automatically turn on the backlight
	//
	status = lcd2.begin(LCD_COLS, LCD_ROWS);
	if(status) // non zero status means it was unsuccesful
	{
		// hd44780 has a fatalError() routine that blinks an led if possible
		// begin() failed so blink error code using the onboard LED if possible
		hd44780::fatalError(status); // does not return
	}

	// initalization was successful, the backlight should be on now

	// Print a message to the LCD
	lcd2.print("Hello, World!");
}

void loop() {
lcd1.setCursor(0,0);
lcd1.print(" >> Hello <<"); // Print Something on LCD
lcd1.setCursor(3,1);
lcd1.print("World ");
  }

---Gizi

Just curious why you didn't use i2c on both LCDs?
Simpler and avoids using any additional pins since both can be controlled with just two pins.

--- bill

Lesson learned :wink: Before designing PCBs, test your complete design on breadboard / protoboard.

I had only a small breadboard and only Arduino UNO, and I needed Arduino_Mega. I designed multiple separate programs. Now putting them all together is pain, thought it was easier. But ye I'm learning a lot and it's very interesting =)

---Gizi

@bperrybap Thank you. I didn't know what the "SR" was for, but now I understand.

@gizi Can you show a photo of your project or write a schematic on a piece of paper and make of photo of that ?
If the "hd44780" library can do both displays, that would be so much better. If you would replace one of the LCD displays with another type some day, then you would only have to change its declaration in the sketch.
Is it possible to remove the shift register ? If you don't have enough pins, then we can probably find a trick to combine pins.

I could remove shift register, and I would have enough pins, problem is, my PCB layout has to use shift register and to replace display I should order a new PCB with new layout =(
When I started my project I did not know about i2C LCD's and I had no enough pins, so I found a solution on the internet with a shift register

Okay, it is a old solution but you made it work :+1:

With help of community!

Ummm. Challenge this. Why not put two I2C displays on the I2C bus and simply not use the SR-based display at all? No PCB change required. The whole purpose of I2C is to allow multiple devices to be connected without using more controller pins! So your PCB-committed wiring for the second display wouldn't be used, but no big deal there, you might even find other devices to add that could be controlled via the SR later.

Now when I read, yes you are right!

That may not be the case.
We don't know anything about his environment like how these LCDs are wired in to the PCB or mechanically connected.
There could be mechanical or space limitations on the PCB or in whatever case might be involved.

The OP has provided ZERO information with respect to photos, schematics, PCB layout, or even the library being used for LiquidCrystal_SR even though it has been asked for multiple times.

i.e. for all we know the PCF8574 is not on a backpack but soldered directly into the custom PCB.

We simply don't know anything about the PCB, it could be nothing more than a shift register backpack for an LCD and the wires are just connected to UNO/MEGA; it could be a shield for a UNO or MEGA that the LCDs are soldered to, or it could be a full blown PCB with everything including micro-controller, shift register, PCF8574, and the LCDs are directly soldered to the PCB.

Or something else, we simply don't know enough to help much since the OP is not providing all the needed information about his environment.

--- bill

1 Like