HELP! Still frustrated 16X2 LCD I2C Display

All,

I posted earlier that I have been trying to get an Arduino to display information on an LCD display.

  1. first I bought some 16X2 LCDs, wired 1 up and everything worked OK, except that it was a complicated wiring taking up a lot of space

  2. I bought some I2C interfaces for the 16X2 LCDs and breadboarded 1 up. While the code worked and the backlight displayed, no information displayed

  3. I soldered the I2C interface to the 16X2 board and still got no information to display

  4. I bought an OLED I2C display - never got anything to display

  5. I bought another 16X2 display from another vendor with the I2C interface already attached. I checked the wiring a bazillion times

GND -> GND
VCC ->5v
SDA ->A4
SCL ->A5

I wrote the following code

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

LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for 16 chars and 2 line display

void setup() {
Wire.begin();
Serial.begin(9600);

while (!Serial); // wait for serial monitor
Serial.println("\nI2C LCD display");

byte error, address;
int nDevices;

Serial.println("Beginning...");
address = 0x27;
Wire.beginTransmission(address);

if (error == 0)
{

Serial.println("Valid I2c Address!");
}
else
{
Serial.println("Wrong I2C address");

}
// error = Wire.endTransmission();

// put your setup code here, to run once:

lcd.backlight();
Serial.println("Backlight on");
lcd.print("Hello world!");
Serial.println("Hello World printed");

}

void loop() {
// put your main code here, to run repeatedly:

}

The serial monitor displayed the following:

I2C LCD display
Beginning...
Valid I2c Address!
Backlight on
Hello World printed

Yet even with adjusting the variable resister, while the backlight is on, no Hello World or anything else displays

I must be doing something wrong, but I am clueless how to go from here to figure out what it is. Any help as to how to proceed would be appreciated

Regards,

George Clay

Use the upgraded HD44780 library now available in the IDE Library manager.

Use the examples provided with it to test your connections and backpack configuration.

Paul_B,

I thought that I already added it. There is a library listed as hd44780 under the subtitle of"contributed libraries" in my "include library". How can I tell if it is the recent one I should use or not?

I looked at the sample programs and many of them look like shells in which one must add code to make them do what they need to do. I am also confused as to what some these do such as LCDiSpeed, or hd44780examples. Is there some sort of "Hello World" example there? Do I need to get into the nitty gritty of hd44780? If so where is the best place to look?

Regards,

George Clay

Yes there are many examples that show how to use the library, including a simple HelloWorld.
You are looking in the wrong place.
I would recommend taking a little time to read the included Documentation that comes with the hd44780 library.
It is in a sketch called "Documentation". Bring it up in the IDE.
There is LOTS of information there and clickable links to even more information, including the hd44780_I2Cexp i/o class wiki: ioClass: hd44780_I2Cexp · duinoWitchery/hd44780 Wiki · GitHub

The hd44780 library is little bit complicated in that it supports several different i/o interfaces to talk to hd44780 displays.
There is an i/o class for each i/o interface each with its own examples.

The i/o class for a i2c backpack is hd44780_I2Cexp
There are several examples under that i/o class.
The first one you should run is the diagnostic sketch, I2CexpDiag which will check out the i2c signals and LCD hardware.

The LCDiSpeed example is available under all the i/o classes. It is used to measure the LCD and i/o interface speed.
For an i2c backpack based LCD, you will want to run the one that is under the hd44780_I2Cexp i/o class.

See the included documentation and wiki for more information.

--- bill

bperrybap,

Thank you,. That looks like a good step by step way to resolve this. I will let you know how it works out.

George

bperrypap,

I have been very busy and haven't had as much time to do this research as I would like to have, so it has taken me awhile. I have found that virtually no straightforward "Hello World" program worked. However, The I2CexpDiag sketch DID work. The problem was that this sketch is extremely complicated and does a lot of things I do not want to do in my programs, and was difficult to determine what the "bare bones" code would be to simply make the LCD work. I have stripped out many pieces piece by piece and the following code does work

// vi:ts=4

// ----------------------------------------------------------------------------
// I2Cexpdiag - i2c LCD i/o Hello WOrld
// Created by Bill Perry 2016-06-17
// Copyright 2016 - Under GPL v3
// Modified by G Clay 7/20/2019

// ----------------------------------------------------------------------------

// The serial port is configured to 9600 baud.

//

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

#ifndef INPUT_PULLUP
#error Sketch requires INPUT_PULLUP which is not supported by this IDE/core version
#endif

// ============================================================================

// user configurable options below this point

// ============================================================================

// Uncomment and use this line instead of the one below if you have a SYDZ backpack
//hd44780_I2Cexp lcd[1]={{I2Cexp_ADDR_UNKNOWN, I2Cexp_BOARD_SYDZ}}; // to run on a single SYDZ based backpack
hd44780_I2Cexp lcd[16]; // auto locate & configure up to 16 displays

// All displays will be assumed to be 16x2
// Even if display is larger the sketch should still work correctly
const int LCD_ROWS = 2;
const int LCD_COLS = 16;

// turn on ESP8266 specific pin decoding
// Turn this off if it creates issues.

#define I2CEXPDIAG_CFG_DECODE_ESP8266PINS

// ============================================================================
// End of user configurable options
// ============================================================================

#ifndef BIT
#define BIT(_bitnum) (1 << _bitnum)
#endif

//#define MAX_ERRORS 16
//#define DEFPROMPT ((const char *) 0)

int NumLcd; // number of LCD displays found.
uint16_t WorkingLCD = 0; // bitmap of LCDs that are "working"

// macros to process working lcd info
#define isWorkingLCD(_n) (WorkingLCD & BIT(_n))
#define setWorkingLCD(_n) WorkingLCD |= BIT(_n)
#define clrWorkingLCD(_n) WorkingLCD &= ~BIT(_n)
#define anyWorkingLCD (WorkingLCD) // non zero if there are any working LCDs

// convert a define to a string
#define define2str(s) _str(s)
#define _str(...) #VA_ARGS

//********************************************************************************************************************************************************
void setup()

{

int nopullups;
delay(5); // allow the hardware time settle
Serial.begin(9600);

/*

  • Locate all the displays by attempting to intialize each one
    */
    //if(lcd[0].begin(LCD_ROWS, LCD_COLS) != 0)
    // Serial.print(F(" LCD begin failed "));
    // setWorkingLCD(0); // mark LCD as "working"

for(NumLcd = 0; NumLcd < (int) (sizeof(lcd)/sizeof(hd44780_I2Cexp)); NumLcd++)
{
char buf[16];

// If begin fails, then assume we have no more displays
if(lcd[NumLcd].begin(LCD_ROWS, LCD_COLS) != 0)
break;

Serial.println(NumLcd);
setWorkingLCD(NumLcd); // mark LCD as "working"
Serial.print(F(" LCD at address: "));
Serial.print(F("0x"));
Serial.print(lcd[NumLcd].getProp(hd44780_I2Cexp::Prop_addr), HEX);
Serial.print(F(" | config: "));

}

}

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

void loop()
{
static unsigned long lastsecs = -1; // pre-initialize with non zero value
unsigned long secs;
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

// write the 'uptime' to each working display
for(int n = 0; n < NumLcd; n++)
{
if(!isWorkingLCD(n))
continue; // skip over non working displays
//-------------------------------------------------------------------------------------
// set the cursor to column 0, line 1
// (note: line 1 is the second row, counting begins with 0):
if(lcd[n].setCursor(0, 0))
{
clrWorkingLCD(n); // mark display as no longer working

// output uptime and error message to serial port
PrintUpTime(Serial, secs);
Serial.print(F(" - Error on Display: "));
Serial.println(n);
}
else
{
lcd[n].write("Hello World!");
}

// set the cursor to column 0, line 1
// (note: line 1 is the second row, counting begins with 0):

if(lcd[n].setCursor(0, 1))
{
clrWorkingLCD(n); // mark display as no longer working

// output uptime and error message to serial port
PrintUpTime(Serial, secs);
Serial.print(F(" - Error on Display: "));
Serial.println(n);
}
else
{
// print uptime on lcd device: (time since last reset)
PrintUpTime(lcd[n], secs);

}
//------------------------------------------------------------------------------------------
}

}

}

// --------------------------------------------------------------------------------------------------------------------------------------------------------

// PrintUpTime(outdev, secs) - print uptime in HH:MM:SS format
// outdev - the device to send output
// secs - the total number of seconds uptime
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
// 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);
}

Maybe someone can use it to help them to write code to use this kind of display. Also I have not yet been able to simplify the array approach of such code as

for(NumLcd = 0; NumLcd < (int) (sizeof(lcd)/sizeof(hd44780_I2Cexp)); NumLcd++)
{
char buf[16];

// If begin fails, then assume we have no more displays
if(lcd[NumLcd].begin(LCD_ROWS, LCD_COLS) != 0)
break;

Serial.println(NumLcd);
setWorkingLCD(NumLcd); // mark LCD as "working"
Serial.print(F(" LCD at address: "));
Serial.print(F("0x"));
Serial.print(lcd[NumLcd].getProp(hd44780_I2Cexp::Prop_addr), HEX);
Serial.print(F(" | config: "));

}

into something like

//if(lcd[0].begin(LCD_ROWS, LCD_COLS) != 0)
// Serial.print(F(" LCD begin failed "));
// setWorkingLCD(0); // mark LCD as "working"

and get it to work. Any help in such continued simplification would be appreciated

George

was difficult to determine what the "bare bones" code would be to simply make the LCD work.

Here is a bare bones sketch to test the display using the hd44780 library. It works just fine on my Uno with 16x2 LCD.

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

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

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

void setup()
{
   lcd.begin(LCD_COLS, LCD_ROWS);
   lcd.clear();
   lcd.print("Hello World");
   lcd.setCursor(0,1);
   lcd.print("Millis ");
}

void loop()
{
   static unsigned long lcdTimer = 0;
   unsigned long lcdInterval = 1000;
   if(millis() - lcdTimer >= lcdInterval)
   {
      lcdTimer = millis();
      lcd.setCursor(8,1);
      lcd.print(millis());      
   }  
}

See how it is neatly indented (ctrl-t or Tools, Auto Format) for readability and posted in code tags. See the how to use this forum-please read sticky for the forum posting guidelines.

If the display still will not "work", post the results (copy the serial monitor output to a post) of the diagnostic sketch. That information is, often, key to the solution of your problem.

What Arduino board are you using? Are you using an ESP8266?

// turn on ESP8266 specific pin decoding
// Turn this off if it creates issues.

#define I2CEXPDIAG_CFG_DECODE_ESP8266PINS

Oh come on!

Fourteen posts so far, that should be enough to learn to post (and format) code properly!

You need to go and read the forum instructions so that you can go back and modify each of your posts (not re-post them) - using the "More -> Modify" option below the right hand corner of your post - to mark up your code as such using the "</>" icon in the posting window. Just highlight each section of code (or output if you need to post that) from the IDE and click the icon.

In fact, the IDE has a "copy for forum" link to put these markings on a highlighted block for you so you then just paste it here in a posting window. But even before doing that, don't forget to use the "Auto-Format" (Ctrl-T) option first to make it easy to read. If you do not post it as "code" it can as you now see, be quite garbled and is always more difficult to read.

It is inappropriate to attach it as a ".ino" file unless it is clearly too long to include in the post proper. People can usually see the mistakes directly and do not want to have to actually load it in their own IDE. And that would also assume they are using a PC and have the IDE running on that PC.

Also tidy up your blank space. Do use blank lines, but only between complete functional blocks.

groundFungus:
What Arduino board are you using? Are you using an ESP8266?

// turn on ESP8266 specific pin decoding

// Turn this off if it creates issues.

#define I2CEXPDIAG_CFG_DECODE_ESP8266PINS

That is a line of code from the I2CexpDiag sketch.
The diag sketch has to run on all the platforms and there are some issues with the extended pin decoding when using very old ESP8266 cores.
The esp8266 pin decoding code can have issues on that older core.
Perhaps I should have used a #define to disable it with it commented out by default rather than have the define there all the time that is commented out if there is an issue.
Then the user would uncomment the define if there was an issue rather than comment it out if there is an issue.

While the define is there/on al the time, that define only enables code when used on the the ESP8266 core.
It has no effect when used on other cores.

I guess I could go in and tweak the comment a bit to make it clear that this define is only used if there an issue when building the code for an ESP8266 core. Possible even flip the ifdefs around so that a define can be set to disable the added pin decoding on the ESP8266 core.
Maybe that would help eliminate some confusion.

--- bill

gclayjr:
I have found that virtually no straightforward "Hello World" program worked. However, The I2CexpDiag sketch DID work. The problem was that this sketch is extremely complicated and does a lot of things I do not want to do in my programs, and was difficult to determine what the "bare bones" code would be to simply make the LCD work. I have stripped out many pieces piece by piece and the following code does work

Yes the diag sketch is complicated. But it is not meant to be used in any way other than to test things.
It not meant as a example of how to use the library. In fact it should not be looked as an example of how to use the library as it does many things that are not normal because it is testing things.
I would recommend not even looking at that code. Look at the other hd44780_I2Cexp i/o class examples for examples of how to use the hd44780 library and the hd44780_I2Cexp i/o class.

What you do mean by:

I have found that virtually no straightforward "Hello World" program worked.

The hd44780_I2Cexp i/o class includes many examples including a simple hello world sketch.
If the I2CexpDiag sketch is working then all the other hd44780_I2Cexp i/o class examples should also be working, including the HelloWorld example.

--- bill

Still would be nice to know which Arduimo they have. If a Mega, A4 and A5 are not I2C pins, for example.

GND -> GND
VCC ->5v
SDA ->A4
SCL ->A5

groundFungus:
Still would be nice to know which Arduimo they have. If a Mega, A4 and A5 are not I2C pins, for example.

True, but he did say: The I2CexpDiag sketch DID work

Which is why I can't understand why the HelloWorld sketch isn't working.
It doesn't make sense to me.

--- bill

GroundFungus,

Here is a bare bones sketch to test the display using the hd44780 library. It works just fine on my Uno with 16x2 LCD.

I am sorry for the delay in trying your bare bones code. I am involved in a lot of things (including other Arduino Projects). I just want to say …

P _E_R_F_E_C_T !!!

Thank you.

By the way I have also been using an Arduino UNO and a 16X2 display.

Regards,

George Clay

The hd44780_I2Cexp i/o class HelloWorld example sketch that comes with the hd44780 library is a bit smaller/simpler code than what GroundFungus provided.

--- bill

Hi everyone, I'm new with arduinos and I have a Winstar WH1602C-YYB-STK 16x02 display. Linked below:

https://www.winstar.com.tw/es/products/character-lcd-display-module/alphanumeric.html#

Could you please guide me on how to wire the display and what library should I be using to get this to work?

Thanks!