A useless discussion about how a working sketch can't possibly work

I have been using the NewLiquidCrystal library from fmalpartida for years (basically since I started using I2C LCD in my second Arduino project).

I recently started a new project and thought it would be a good idea to update my libraries to the latest. I thought it was a good idea. Apparently I was wrong.

None of my sketches that include I2C LCDs work. They used to and now they don't.

I had been using the line to define the LCD
LiquidCrystal_I2C lcd(0x27);

now I have to use
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

Any idea on what other library update may have caused this issue?

I don't know what the update changed. I, too, used that library for years. Just lately I discoverd the hd44780 library. I believe the hd44780 library is superior. It will auto detect the I2C address and the I2C expander to LCD wiring. Most of the functions are the same as the other liquid crystal libraries. Use the hd44780_I2Cexp class.

The frustrating thing is that there are multiple libraries of the same name but with different APIs. So it may be that you updated to a different library of the same name. Or maybe the API of the library you were using changed since the version you were using previously. You have the choice of updating your code according to the new API or finding a library/version compatible with your code.

It's a good idea to document the dependencies of your projects with links to where they can be downloaded from and which version the code was written for. That only takes a few seconds while you're writing the project and can save you or someone else a ton of time and frustration later. I like to add a comment after the #include directive for each external dependency.

pert:
The frustrating thing is that there are multiple libraries of the same name but with different APIs. So it may be that you updated to a different library of the same name. ...

It's a good idea to document the dependencies of your projects with links to where they can be downloaded from and which version the code was written for. That only takes a few seconds while you're writing the project and can save you or someone else a ton of time and frustration later. I like to add a comment after the #include directive for each external dependency.

Been there done that. I know exactly who wrote it and where I got both libraries from. They are both revisions of the NewLiquidCrystal library written by fmalpartida. I even have copies of the new and the old libraries Though I cannot find a revision or revision history in the old library, so I'm not sure which version it is; but I do have a copy of it.

pert:
Or maybe the API of the library you were using changed since the version you were using previously. You have the choice of updating your code according to the new API or finding a library/version compatible with your code.

Very possible. But I'm not sure of that and here is why:

I uninstalled IDE v1.8.4 cleaned everything. Installed 1.8.5, updated all the built-in libraries and then added the old fmalpartida NewLiquidCrystal library and they still don't work on the project without the change (they compile fine, just not work on the project). Since I'm not interested in being stuck on one IDE version, it did not make sense to reinstall 1.8.4 and try to get my sketches to work. I want to keep moving forward, not stuck in the past. So my interest is to understand what changed that caused my sketches to now fail to work.

adwsystems:
I had been using the line to define the LCD
LiquidCrystal_I2C lcd(0x27);

now I have to use
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

Any idea on what other library update may have caused this issue?

I don't believe you. From the "older" Malpardita library:

#define D4 0
#define D5 1
#define D6 2
#define D7 3


// CONSTRUCTORS
// ---------------------------------------------------------------------------
LiquidCrystal_I2C::LiquidCrystal_I2C( uint8_t lcd_Addr )
{
   config(lcd_Addr, EN, RW, RS, D4, D5, D6, D7);
}

i.e. the short form constructor puts the data bus on P0, P1, P2, P3 of the PCF8574
your long form constructor puts the data bus on P4, P5, P6, P7 of the PCF8574

All the backpacks that I possess use P4, P5, P6, P7.
Obviously there are a whole load of P0, P1, P2, P3 style backpacks on the market but I have never seen one.

Whichever library you choose, it is wise to run a diagnostic to determine which style of backpack you possess.
Personally, I would advise using the hd44780 library. Especially since it is supported by the Library Manager.

David.

david_prentice:
I don't believe you.

That's fine. But it is a fact.

I have two dozen happy customers with units with this code installed:

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

// DEBUG_MODE
// 1 ADC Readings
// 2 Temp reading timer
// 4 DAC
#define DEBUG_MODE 4

#define TEMP_READ_INTERVAL 250 // enter interval in milliseconds
#define SP_DISPLAY_TIME 5000 // enter interval in milliseconds

#define ALM_ACK 2
#define ALM_LIGHT 12
#define ALM_BUZZER 11

#define TEMP_PIN 2
#define OFF_SP_PIN 1
#define ON_SP_PIN 3

#define SP_Offset 100.0 //degF
#define SP_Sens 100.0 / 5.0 //100 degF span over 5.0 volts
#define temp_amp_gain 2.0
#define on_amp_gain 1.0
#define off_amp_gain 1.0
#define adc_sens 1.0*5.0/1024.0 // voltage value of one ADC step

LiquidCrystal_I2C lcd(0x27);


// define some values used by the panel and buttons
int lcd_key     = 0;
int adc_key_in  = 0;
byte adc_pin = 0;

int adcReading;
boolean adcStarted=false;
boolean adcDone=false;

float on_temp_sp, off_temp_sp, temp_reading;

byte Startup_Complete =0;

boolean alarm_status = 0;
boolean alarm_ack = 0;


// ADC complete ISR
ISR (ADC_vect)
{
  byte low, high;

  low = ADCL;
  high = ADCH;

  adcReading = (high << 8) | low;
  adcDone = true;
}  // end of ADC_vect

void setup()
{
  lcd.begin(16, 2);

  Serial.begin (115200);

  pinMode(ALM_ACK, INPUT);
  pinMode(ALM_BUZZER, OUTPUT);
  pinMode(ALM_LIGHT, OUTPUT);

  Startup_Complete=0;
  alarm_ack=0;
  digitalWrite(ALM_BUZZER, 0);
  digitalWrite(ALM_LIGHT, 0);
  
  adc_pin = TEMP_PIN;
  
  Wire.begin();
}

Please feel free to explain how it works.

(only the relevant part posted as the whole program exceeds the 9k limit)

Edit:

Here is the code from the HelloWorld_I2C included with fmalpartida NewLiquidCrystal library:

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



#define BACKLIGHT_PIN     13

LiquidCrystal_I2C lcd(0x38);  // Set the LCD I2C address

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


// Creat a set of new characters
const uint8_t charBitmap[][8] = {
   { 0xc, 0x12, 0x12, 0xc, 0, 0, 0, 0 },
   { 0x6, 0x9, 0x9, 0x6, 0, 0, 0, 0 },
   { 0x0, 0x6, 0x9, 0x9, 0x6, 0, 0, 0x0 },
   { 0x0, 0xc, 0x12, 0x12, 0xc, 0, 0, 0x0 },
   { 0x0, 0x0, 0xc, 0x12, 0x12, 0xc, 0, 0x0 },
   { 0x0, 0x0, 0x6, 0x9, 0x9, 0x6, 0, 0x0 },
   { 0x0, 0x0, 0x0, 0x6, 0x9, 0x9, 0x6, 0x0 },
   { 0x0, 0x0, 0x0, 0xc, 0x12, 0x12, 0xc, 0x0 }
   
};

void setup()
{
   int charBitmapSize = (sizeof(charBitmap ) / sizeof (charBitmap[0]));

  // Switch on the backlight
  pinMode ( BACKLIGHT_PIN, OUTPUT );
  digitalWrite ( BACKLIGHT_PIN, HIGH );
  
  lcd.begin(16,2);               // initialize the lcd 

   for ( int i = 0; i < charBitmapSize; i++ )
   {
      lcd.createChar ( i, (uint8_t *)charBitmap[i] );
   }

  lcd.home ();                   // go home
  lcd.print("Hello, ARDUINO ");  
  lcd.setCursor ( 0, 1 );        // go to the next line
  lcd.print (" FORUM - fm   ");
  delay ( 1000 );
}

void loop()
{
   lcd.home ();
   // Do a little animation by writing to the same location
   for ( int i = 0; i < 2; i++ )
   {
      for ( int j = 0; j < 16; j++ )
      {
         lcd.print (char(random(7)));
      }
      lcd.setCursor ( 0, 1 );
   }
   delay (200);
}

Two items to note:

  1. The constructor is LiquidCrystal_I2C lcd(0x38);
  2. It doesn't work either without modifying the constructor. It used to work, I used it and the I2CLCDGuesser to test each LCD when it arrives.

This is from the readme.md file of the old library:

# README #

## Introduction ##

![LCD library](https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads/I2CLCDextraIO_assemblyProject_small.jpg)

Welcome to the *LCD Library* for **Arduino** and **Chipkit**. It is a derivate of the original LiquidCrystal Library as sourced in the Arduino SDK. It has been developed to be compatible with the current LiquidCrystal library, 
its performance is almost 5 times faster and fully extendable if need be. 

It supports most ``Hitachi HD44780`` based LCDs, or compatible, connected to any project using: 4, 8 
wire parallel interface, I2C IO port expander (native I2C and bit bang) and Shift Regiter.

It currently supports 4 types of connections:

* 4 bit parallel LCD interface
* 8 bit parallel LCD interface
* I2C IO bus expansion board with the PCF8574* I2C IO expander ASIC such as [I2C LCD extra IO](http://www.electrofunltd.com/2011/10/i2c-lcd-extra-io.html "I2C LCD extra IO").
* ShiftRegister adaptor board as described [Shift Register project home](http://code.google.com/p/arduinoshiftreglcd/ "Shift Register project home") or in the HW configuration described below, 2 and 3 wire configurations supported.
* ShiftRegister 3 wire latch adaptor board as described [ShiftRegister 3 Wire Home](http://www.arduino.cc/playground/Code/LCD3wires "ShiftRegister 3 Wire Home")
* Support for 1 wire shift register [ShiftRegister 1 Wire](http://www.romanblack.com/shift1.htm "ShiftRegister 1 Wire")
* I2C bus expansion using general purpose IO lines.

### How do I get set up? ###

* Please refer to the project's [wiki](https://bitbucket.org/fmalpartida/new-liquidcrystal/wiki/Home "wiki")


### Contributors
The library has had the invaluable contribution of:

* [piccaso](http://www.3guys1laser.com/blog-cheap-arduino-2-wire-lcd-display-0 "picas") - Florian Fida - Flo, thanks for testing and improving the SR library, initial version of the 1 wire interface and speed improvements.
* B. Perry - *bperrybap@opensource.billsworld.billandterrie.com*, with his thoughtful contribution, speed improvements and development support for the SR2W library.
* Adrian Piccioli, with his contribution to the i2c GPIO support.
* [todbot](https://github.com/todbot "todbot") Tod E. Kurt for the [softwarei2cmaster](https://github.com/todbot/SoftI2CMaster "softwarei2cmaster") library.
* [felias-fogg](https://github.com/felias-fogg) - Bernhard for the [softwarei2cmaster fast](https://github.com/felias-fogg/SoftI2CMaster "softwirei2cmaster")

#### Contribution guidelines

* Writing tests
* Code review
* Help out with bug fixing
* Setup a project logo
* Write new drivers to support more LCDs.

### Who do I talk to? ###

* Repo owner or admin
* For SoftI2CMaster latest versions, updates and support, please refer to [SoftI2CMaster](https://github.com/todbot/SoftI2CMaster "todbot")

I had the following libraries in the 'mysketches'->libraries directory:
Adafruit_ADS1X15-master
DallasTemperature
Firmata
NewliquidCrystal
OneWire
RTClib-master
SD
SDFat

I'm not BSing you all. It is as I said.

david_prentice:
Whichever library you choose, it is wise to run a diagnostic to determine which style of backpack you possess.

I use the i2cLCDguesser to determine the backpack settings. I now have two different backpacks to deal with. >:( The older backpacks are YWRobot, where I do not think you can change the I2C address. I now have several PCF8574A backpacks, where you can set/change the I2C address. Both have different settings for the pin assignments and for the addresses. I cannot set the PCF8574A version to the 0x27 address of the YWRobot version. :frowning:

You have 2 dozen LCD displays that use the library's default constructor to determine the LCD to I2C expander pin mapping. If you change to a different LCD display, there is no guarantee that It's pin mapping is the same. Then you have to modify the constructor in the sketch to match the new display.

With the hd44780 library, if you change a display, the library will, automatically, detect the new pin mapping (and the I2C address).

groundFungus:
You have 2 dozen LCD displays that use the library's default constructor to determine the LCD to I2C expander pin mapping.

Understood.

groundFungus:
If you change to a different LCD display, there is no guarantee that It's pin mapping is the same. Then you have to modify the constructor in the sketch to match the new display.

Understood. Expect the previously working sketches with the previously work YWRobot backpack no longer work. (I have put the new carton of PCF8574A LCDs aside until I can get the previously working YWRobot versions operable again.)

So no change to LCD model (ie., use old one) = does not work post-library update.

Can you provide links to the libraries (old and new). I did have a look around and found https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads/.

Installed 1.3.5 from there and compiled the HelloWorld_i2c without errors in IDE 1.8.5 (Windows 8); plenty warnings about unused parameters though.

sterretje:
Can you provide links to the libraries (old and new). I did have a look around and found https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads/.

Installed 1.3.5 from there and compiled the HelloWorld_i2c without errors in IDE 1.8.5 (Windows 8); plenty warnings about unused parameters though.

You have the link (same as in the readme file quoted above), only I am using 1.3.4. I have no errors of any sort during the compile or upload of the HelloWorld_I2C sketch to an Arduino UNO.

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

#define BACKLIGHT_PIN     13

LiquidCrystal_I2C lcd(0x38);  // Set the LCD I2C address

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


// Creat a set of new characters
const uint8_t charBitmap[][8] = {
   { 0xc, 0x12, 0x12, 0xc, 0, 0, 0, 0 },
   { 0x6, 0x9, 0x9, 0x6, 0, 0, 0, 0 },
   { 0x0, 0x6, 0x9, 0x9, 0x6, 0, 0, 0x0 },
   { 0x0, 0xc, 0x12, 0x12, 0xc, 0, 0, 0x0 },
   { 0x0, 0x0, 0xc, 0x12, 0x12, 0xc, 0, 0x0 },
   { 0x0, 0x0, 0x6, 0x9, 0x9, 0x6, 0, 0x0 },
   { 0x0, 0x0, 0x0, 0x6, 0x9, 0x9, 0x6, 0x0 },
   { 0x0, 0x0, 0x0, 0xc, 0x12, 0x12, 0xc, 0x0 }
   
};

void setup()
{
   int charBitmapSize = (sizeof(charBitmap ) / sizeof (charBitmap[0]));

  // Switch on the backlight
  pinMode ( BACKLIGHT_PIN, OUTPUT );
  digitalWrite ( BACKLIGHT_PIN, HIGH );
  
  lcd.begin(16,2);               // initialize the lcd 

   for ( int i = 0; i < charBitmapSize; i++ )
   {
      lcd.createChar ( i, (uint8_t *)charBitmap[i] );
   }

  lcd.home ();                   // go home
  lcd.print("Hello, ARDUINO ");  
  lcd.setCursor ( 0, 1 );        // go to the next line
  lcd.print (" FORUM - fm   ");
  delay ( 1000 );
}

void loop()
{
   lcd.home ();
   // Do a little animation by writing to the same location
   for ( int i = 0; i < 2; i++ )
   {
      for ( int j = 0; j < 16; j++ )
      {
         lcd.print (char(random(7)));
      }
      lcd.setCursor ( 0, 1 );
   }
   delay (200);
}

From the output window (blank spaces included to show that it is the actual output):

Sketch uses 4114 bytes (12%) of program storage space. Maximum is 32256 bytes.
Global variables use 332 bytes (16%) of dynamic memory, leaving 1716 bytes for local variables. Maximum is 2048 bytes.

Follow Mr Groundfungus's advice. Install the hd44780 library. It will detect the I2C address and wiring style automatically.
Your customers will never have to worry about the make and model of I2C backpack.

For your own information. Run the diagnostic on each of your 12 LCD displays. Stick a label on each one with address and wiring style.

There are 16 possible addresses and two common wiring styles. That makes MANY ways to go wrong.

The common wiring styles are data bus on P0..P3 and data bus on P4..P7.
The backlight could be active-high or active-low. The control pins could be in a different order. You can see that the permutations get enormous.

The other advantage of hd44780 is that you have one set of class methods. All the other
LiquidCrystal_I2C classes have incompatible API. Your customers will not always install Malpartida's library. They just use the first one they find.

David.

david_prentice:
Your customers will never have to worry about the make and model of I2C backpack.

The other advantage of hd44780 is that you have one set of class methods. All the other
LiquidCrystal_I2C classes have incompatible API. Your customers will not always install Malpartida's library. They just use the first one they find.

The customers use the device as programmed. They do not program it. If they do, that is their issue. But I don't think any of them are in to this sort of thing.

david_prentice:
For your own information. Run the diagnostic on each of your 12 LCD displays. Stick a label on each one with address and wiring style.

I have. I have two versions, discernible by just looking at the backpack. As for the settings, I have them noted for each.

We are straying from the OP. I'm interested to know what library update caused fmalpartida NewCrystalLibrary to now require the full constructor.

NewCrystalLibrary to now require the full constructor.

If the I2C expander pin map is the default, there is a constuctor that requires only the I2C address of the I2C expander.

From LiquidCrystal_I2C.cpp:

 #define EN 6  // Enable bit

/*!
 @defined 
 @abstract   Read/Write bit of the LCD
 @discussion Defines the IO of the expander connected to the LCD Rw pin
 */
#define RW 5  // Read/Write bit

/*!
 @defined 
 @abstract   Register bit of the LCD
 @discussion Defines the IO of the expander connected to the LCD Register select pin
 */
#define RS 4  // Register select bit

/*!
 @defined 
 @abstract   LCD dataline allocation this library only supports 4 bit LCD control
 mode.
 @discussion D4, D5, D6, D7 LCD data lines pin mapping of the extender module
 */
#define D4 0
#define D5 1
#define D6 2
#define D7 3


// CONSTRUCTORS
// ---------------------------------------------------------------------------
LiquidCrystal_I2C::LiquidCrystal_I2C( uint8_t lcd_Addr )
{
   config(lcd_Addr, EN, RW, RS, D4, D5, D6, D7);
}

groundFungus:
If the I2C expander pin map is the default, there is a constuctor that requires only the I2C address of the I2C expander.

I know because it used to work. But the displays I had on hand and worked previous with just the address in the constructor now require the full constructor. So are there any ideas on what may have happened to now require the full constructor to be specified where previously just the address worked?

Go on. The short form of constructor defaults to EN=6, RW=5, RS=4, D4=0, D5=1, D6=2, D7=3, BL=7

This will be equivalent to

LiquidCrystal_I2C lcd(0x27);
LiquidCrystal_I2C lcd(0x27, 6, 5, 4, 0, 1, 2, 3, 7, POSITIVE);

If you have the other style of adapter you must use the full-fat constructor:

LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

Since you own 12 different backpacks, you can use the appropriate constructor.

It has always surprised me that the default is D4=0, D5=1, D6=2, D7=3 because in my experience P4..P7 is more common.

David.

david_prentice:
Since you own 12 different backpacks, you can use the appropriate constructor.

I have 2 different backpacks, and many of each.

But that isn't explaining why the full constructor is now required when prior to the library updates it was not.

I give up. Both I and GroundFungus have explained it very clearly.

david_prentice:
I give up. Both I and GroundFungus have explained it very clearly.

I'm sorry I must not be seeing the answer. I see lot's of really good information, but not the answer. Can you give me a hint as to which post explains why the full constructor is now required when prior to the library updates it was not?

(stating to use a different library instead of a library that had been used and working for years, is not an explanation for why the sketch no longer works after having updated other libraries)