Ghost characteres LCD 2004 I2C

Hi, I´m newcomer in Arduinos’ programing, I was trying to learn how to use a Liquid Crystal I2C (LCD 2004), then, I bumped in to autoscroll() noAutoscroll() functions, I wrote a very simple sketch but it was doing strange thing, so I went in to searching for examples and the one I’d found was doing the same strange thing. What happens is, I’m writing only in the first row (row number 0) and, as soon as the autoscroll() function is called, everything goes right in the first line, but at the same time a ghost lines appears on the 3tr line (row 2), doing the same thing that happens in the first line.
I have another screen (LCD 1602), and everything works fine but the screen only has two lines and the ghost characters does not appears.
I’m using an Arduino UNO, the LCD 2004 is connected: LCD VCC – UNO 5v, LCD GRN – UNO GRN, LCD SDA – UNO A4, and LCD SCL – UNO A5. Using, Arduino IDE 1.8.13 and LiquidCrystal_I2C.h downloaded from https://gitlab.com/joearmstrong980/LCD_I2C.
I will appreciated if you guys can point me to the right direction, wrong library, broken screen

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

// LCD address and geometry and library initialization
/*
const byte lcdAddr = 0x27;  // Address of I2C backpack
const byte lcdCols = 16;    // Number of character in a row
const byte lcdRows = 2;     // Number of lines
*/

const byte lcdAddr = 0x3F;  // Address of I2C backpack
const byte lcdCols = 20;    // Number of character in a row
const byte lcdRows = 4;     // Number of lines


LiquidCrystal_I2C lcd(lcdAddr, lcdCols, lcdRows);

// Demo parameters
const byte lcdScrollRow = 0;          // Number of a demo row counting from 0
const unsigned int digitDelay = 500;  // Miliseconds before displaying next digit

// Function for displaying demo digits
void printDigits() {
  for (byte thisChar = 0; thisChar < 10; thisChar++) {
    lcd.print(thisChar);
    delay(digitDelay);
  }
}

void setup() {
  lcd.init();
  lcd.backlight();
}

void loop() {
  lcd.setCursor(0, lcdScrollRow);
  printDigits();

  // Set the cursor to the last column of the demo row and turn on autoscroll
  lcd.setCursor(lcdCols, lcdScrollRow);
  lcd.autoscroll();
  printDigits();
  lcd.noAutoscroll();
  lcd.clear();
}

Ghost-Char.mpg (596 KB)

You need to understand that on the 2004 display, the third line is simply part of - or indeed an extension of - the first line.

I am not sure what the "autoscroll" function is, or what you expect it to do. You have shown only the code for a 1602 display. If you use that code on a 2004, then you obviously cannot complain about anything that happens. :astonished:

In any case, you are using an old library whose functionality is quite limited. If you want more functionality, we advise you use the Library Manager to install the "HD44780" library by Bill Perry and work through the examples and functions it offers.

The specific library you are using not in good shape.
I would recommend not using it or the LiquidCrystal_I2C library in the IDE library manager (which is the parent of this library) as it has some issues (bugs), including a licensing issue, and is not being maintained.
I would recommend that you install the hd44780 library and use the hd44780_I2Cexp i/o class.
Once the hd44780 library is installed, there is lots of documentation included in the Documentation sketch that you can reference directly from the IDE.
The first thing that you should run, after installing it is the included I2CexpDiag sketch to check that everything is working as it will test the i2c signals and the internal memory of the LCD.
Then you can try any of the other hd44780_I2Cexp i/o class examples and/or proceed with your own code after looking at the examples.
You can also see the more information & documenation on the hd44780 github page:

--- bill


Here is some background on the library you are using.
It is a fork from a copy of original over on github at:

which is available in the IDE library manager.
The LiquidCrystal_I2C library on gitub was a checkin of a library from a person named Mario H that goes back to 2009.
It was put on github to get it added to the IDE library manager for easy installation.
However, The person who set it up with this initial github commit couldn't maintain it so he handed it over to "John Rickman".
Rickman made a copy of it and moved it to gitlab, then renamed it, then illegally changed the copyright and license away from LGPL to MIT.
Rickman, also has decided to not maintain the "official" copy on github that the Arduino IDE uses.
In the brief time after the rename to LCD_I2C and illegal re-licensing, but before the repository was removed, a few people (including myself) forked/cloned it.
The copy you have from Joseph Armstrong on gitlab is one of those forks.
Shortly there after, rather than revert/fix the license back to LPGL, Rickman deleted his gitlab LCD_I2C repository.
He is not maintaining the original LiquidCrystal_I2C version on github and so far is not answering my emails.

IMO, this project is now in a very bad state and should not be used.
It has some s/w issues (bugs) that need to be fixed and is using an an illegal s/w license as the license should be LGPL 2.1 since Rickman can't legally change it to MIT.

I probably should drop a note to the Arduino.cc developers to get LiquidCrystal_I2C removed from the IDE library manager given its current condition.

--- bill

bperrybap:
I probably should drop a note to the Arduino.cc developers to get LiquidCrystal_I2C removed from the IDE library manager given its current condition.

Clearly. :grinning:

Sorely needed correction. While you are at it, can you see if you can get them to sync Arduino with the Linux repositories?

Lotsa luck! :roll_eyes:

Paul__B:
While you are at it, can you see if you can get them to sync Arduino with the Linux repositories?

I don't think that is ever going to happen - mainly for technical reasons.
IMO, the arduino.cc team took a major wrong turn several years back in how/where they store things in their releases, libraries, and addon platform packages.
They decided to store everything under the users home directory and then also put add on packages under there and some of the add on packages overlap and install into sub directories.
This strategy will never be accepted by any linux distro for adding into their repository and I'm not sure it can even be technically done.

I tried for quite some time to try to get them to handle Arduino "libraries" differently to eliminate the issue of library collisions, and the manual process of adding them to the library manager.
Also on how and were the Arduino IDE is installed to make things easier for OS s/w package managers.
But like with many things in Arduino, they are head strong on doing things the goofy way they dream up.

--- bill

bperrybap:
But like with many things in Arduino, they are head strong on doing things the goofy way they dream up.

Like having tutorials suggesting you power the older (and otherwise most practical) Arduinos via "Vin" with 7 to 12 V. :roll_eyes:

Never mind, installation on Linux from the file on the download page via the package manager does work just fine. :sunglasses:

Paul__B:
Never mind, installation on Linux from the file on the download page via the package manager does work just fine. :sunglasses:

Not sure what you mean by this.
There are multiple ways to install Arduino on linux.
I install it from the zip file download from the arduino.cc

and put it where I want.
I have 20+ versions installed on my machine for various testing going all the way back to 2008 pre 1.0
It can be installed from the OS repository but that version is 1.05 which is not so useful and I would not recommend.
On Ubuntu 20.04 you can install a package from the Ubuntu Software store which uses their snap container system.
That version is 1.8.13
I don't use dekstop Ubuntu, (utterly unusable IMO), and I won't use snap or flatpak installations as they come with lots of potential inherent security risks due to how the apps can bundle their own libraries vs use the OS system libraries.

--- bill

Thanks, Paul__B for you responding so fast, even though, you admitted not having any idea of the matter

I am not sure what the "autoscroll" function is, or what you expect it to do.

By the way, the code is for both display the LCD1602 and the LCD2004

Papirrruqui:
What happens is, I’m writing only in the first row (row number 0) and, as soon as the autoscroll() function is called, everything goes right in the first line, but at the same time a ghost lines appears on the 3tr line (row 2), doing the same thing that happens in the first line.
I have another screen (LCD 1602), and everything works fine but the screen only has two lines and the ghost characters does not appears.

While you have not shown this in your photos, I assume that by "ghost lines" you mean that the same characters show up on line 2 that are showing up on line 0.
What you are seeing is the correct behavior on a 20x4 display given how the hd44780 chip set display memory works and the code you have written.
It obviously doesn't work the way you think it does.
In your example code, you are not getting "ghosts", you are seeing what you previous printed on line 0 show up on line 2 of the display as the display memory is shifted.
It isn't obvious since you printed the same 10 digits twice. Print something different each time and you will see what is really happening.
Had you printed enough characters, you would have also seen a similar effect on the 16x2 display as well.
i.e. the "duplication" was still happening on the 16x2 from the shifting, you just were not seeing it because the screen isn't showing all the internal display ram. print enough and the characters will start to spill over into the visible portion of the display memory.

You need to understand a bit more about how the hd44780 display works and what autoscroll() does and doesn't do.
First, the hd44780 chipset memory layout is hard coded internally.
It can be configured internally to be two 40 character lines or one 80 character line.
This is fixed and cannot be changed. ALL hd44780 displays work this way.
When the physical display is not two 40 character lines or one 80 character line, the physical LCD displays only a portion of the internal lines.
See this for more on how the internal memory is mapped to the physical display of the LCD for various geometries:

The LiquidCrystal API function autoscroll() turns on the S bit of the Entry Mode Set instruction.
From the data sheet:

S: Shifts the entire display either to the right (I/D = 0) or to the left (I/D = 1) when S is 1.
The display doesnot shift if S is 0.If S is 1, it will seem as if the cursor does not move but the display does.
The display does not shift when reading from DDRAM. Also, writing into or reading out from CGRAM does not shift the display.

What you need to understand is that whenever a shift is done, what is really happening is that the entire display of what is shown is shifted. Not just an individual line/row.
The physical LCD displays what is in display ram. it is like a window into that memory.
Normally display memory location 0 is the upper left corner of the physical display.
If you do a shift, the physical display will start showing characters at a different location as the starting point is shifted.
This will cause ALL the characters on the physical to shift.
Where this can look odd is on a 20x4 display since it shows all the display and given how the display memory is mapped to the physical display since line 2 on the physical display is contiguous with line 0 and line 3 is contiguous with line 1.
Many people assume that the 20x4 memory is mapped linearly from upper left to bottom right of the display.
i.e. if you start on line 0 and print characters then when the characters get to the end of line 0 that they will start printing on line 1.
But this is not the case. If you overrun line 0 it will start printing on line 2.
After line 2 it will go back to line 1 and after line 1 it will go to line 3.

Because of all the display mapping, things can get confusing when doing shifts, particularly on a 20x4 display.
BTW, your code is also attempting to address an invalid column on the display:

  // Set the cursor to the last column of the demo row and turn on autoscroll
  lcd.setCursor(lcdCols, lcdScrollRow);

While your comment suggests setting to the last column on the row, lcdCols is 20 which is beyond the end of the row.
The library that you are using does not check to see if you are attempting to go beyond the end of the last column.
With that library attempting to set the cursor position to 20,0 on the 20x4 display will be addressing LCD display memory location 20
Display memory location 20 maps to beginning of line 2 on the physical Display.
When combined with auto shift, things can get quite confusing.

Here is you code modified so you can better see the actual effects of the shifting:

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

// LCD address and geometry and library initialization
/*
const byte lcdAddr = 0x27;  // Address of I2C backpack
const byte lcdCols = 16;    // Number of character in a row
const byte lcdRows = 2;     // Number of lines
*/

const byte lcdAddr = 0x27;  // Address of I2C backpack
const byte lcdCols = 20;    // Number of character in a row
const byte lcdRows = 4;     // Number of lines


LiquidCrystal_I2C lcd(lcdAddr, lcdCols, lcdRows);

// Demo parameters
const byte lcdScrollRow = 0;          // Number of a demo row counting from 0
const unsigned int digitDelay = 500;  // Miliseconds before displaying next digit

// Function for displaying demo digits
void printDigits() {
  for (byte thisChar = 0; thisChar < 10; thisChar++) {
    lcd.print(thisChar);
    delay(digitDelay);
  }
}

// Function for displaying demo chars
void printChars()
{
  char thisChar = 'A';
  for (int i = 0; i < 10; i++)
  {
    lcd.print((char) (thisChar+i));
    delay(digitDelay);
  }
}


void setup() {
  lcd.init();
  lcd.backlight();
}

void loop() {
  lcd.setCursor(0, lcdScrollRow);
  printChars();

  // Set the cursor to the last column of the demo row and turn on autoscroll
  lcd.setCursor(lcdCols, lcdScrollRow);
  lcd.autoscroll();
  printDigits();
  lcd.noAutoscroll();
  lcd.clear();
}

The shift mode capabilities on the hd44780 chipset are not very useful on multi line displays.
It tends to work ok on single line displays. It can be used on 2 line displays for some situations if you don't shift too much and are ok with shifting both lines at the same time.
It is all but useless on a 20x4 display since all display memory is shown and since any shift causes all lines to shift around and it can look really odd given the display memory to physical screen mapping is not linearly contiguous.


First, take a step back and consider what you want to do in terms of shifting.
In many cases it is not possible to use the hd44780 chipset shifting capabilities given the way it works.

And I would still suggest that you consider switching to the hd44780 library.
Not only is it simpler to configure, faster and have some added capabilities.
But it also is actively being maintained which is currently not the case for the LiquidCrystal_I2C library.

The hd44780 library has a long line wrapping capability that can be be enabled that can straighten out some of the memory mapping issues like when printing long lines so that wrapping works correctly on line boundaries.
The library you are using nor the LiquidCrystal library have this capability.

--- bill

So in short, to add to my original comment in #1, "autoscroll" is basically - useless! :sunglasses:

No surprises there.

Paul__B:
So in short, to add to my original comment in #1, "autoscroll" is basically - useless! :sunglasses:

Not necessarily completely useless, but, IMO, it only works on 1 line displays for certain applications.
These days there is often enough spare memory in micro-controllers to implement any kind of scrolling desired in the micro-controller s/w.

--- bill

THANK A LOT Bill, for explaining so well the complications of using the autoscroll() member.

bperrybap:
Here is some background on the library you are using.

In addition, knowing the history behind the libraries brings a shining light, there are so many different options available. Several places, people and libraries for using the same lcd screen. It is hard to take a decision of with one is the right one.

bperrybap:
While you have not shown this in your photos, I assume that by "ghost lines" you mean that the same characters show up on line 2 that are showing up on line 0.

I had upload a video of the LCD2004 running sketch; you have to download in order to view it.

bperrybap:
It isn't obvious since you printed the same 10 digits twice. Print something different each time and you will see what is really happening.

Great idea, it is far better and clearer using letters and numbers.

bperrybap:
LCD Addressing

Very good hd44780 documentation on memory mapping comparing against physical display.

bperrybap:
While your comment suggests setting to the last column on the row, lcdCols is 20 which is beyond the end of the row.

I read that, when autoscroll() is on, you have to print in the position 20 for the character to appear in 19th position, but, I cannot find where I read it, sorry. I test both way, if lcd.setCursor(19,0) the character appears on the 18th place living a blank space on position 19. I tested with both libraries, the hd44780 and the LiquidCrystal_I2C with the same result.

bperrybap:
Here is you code modified so you can better see the actual effects of the shifting:

Again, thanks for taking the time to explain the matter so well, and go over the code to improve it.

bperrybap:
First, take a step back and consider what you want to do in terms of shifting.
In many cases it is not possible to use the hd44780 chipset shifting capabilities given the way it works.

Yes, I will.
The project I’m working on, will use a menu, some of the menu items will be longer than 20 characters, and the planning is to scroll the option over the line. Clearly, the shifting functionality of the LCD screen wouldn’t work for the project.

bperrybap:
And I would still suggest that you consider switching to the hd44780 library.

Using hd44780_I2Cexp.h library is a most! Even thought, the sketch did almost double in size of program storage and grew 3% of dynamic memory, I believe, it is the best option.

carlos

Papirrruqui:
Using hd44780_I2Cexp.h library is a most! Even thought, the sketch did almost double in size of program storage and grew 3% of dynamic memory, I believe, it is the best option.

Unfortunately, gcc removed some link optimization capabilities in newer releases and as a result it is no longer possible to automatically remove unused virtual functions.
With the hd44780 library it means that there there are several functions, (like code to read from the LCD) that can be linked in even when they are not ever used.

I don't see gcc reverting this decision.

I've mulled around some ideas to try to work around this. None are pretty and they are not fullly backward with existing code, so I have yet to take any steps to help reduce the dead code problem which would lower the typical code footprint used by the library.

--- bill

This topic was automatically closed after 55 days. New replies are no longer allowed.