[solved] 16x4 LCD: Characters in row 3&4 are moved to the right

Here is the code from the lib.

void LiquidCrystal::setCursor(uint8_t col, uint8_t row)
{
int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
if ( row > _numlines ) {
row = _numlines-1; // we count rows starting w/0
}

command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
}

It seems that the row_offsets are wrong for my display.
I guess, this is really controller specific.

Aye. I think most people are either using it with a 16x2 or a 20x4, so the issue doesn't pop up.

Finally I finished my RGB selection menu...

Thanks for the support!

you need, in setup(), a line that says lcd.begin(4,16);

Hi jrraines

Thanks for your reply. However, I the code, which caused the problem, included the begin statement. My original code is here. It has the described effect in lines 3&4.

// include the library code:
#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
  // set up the LCD's number of columns and rows: 
  lcd.begin(16, 4);
  // Print a message to the LCD.
  lcd.print("hello, world!");
}

void loop() {
  // set the cursor to column 0, line 1
  // (note: line 1 is the second row, since counting begins with 0):
  lcd.setCursor(0, 1);
  // print the number of seconds since reset:
  lcd.print(millis()/1000);
  
  lcd.setCursor(16+1, 0);
  // print the number of seconds since reset:
  lcd.print(millis()/1000);
  
  lcd.setCursor(16, 1);
  // print the number of seconds since reset:
  lcd.print(millis()/1000);
}

Kaouthia:
Aye. I think most people are either using it with a 16x2 or a 20x4, so the issue doesn't pop up.

If my recollection is right, there are two ways to address the LCD onboard memory (DDRAM?) that stores characters in a 16X4 display, 20 bytes for one line, the same way as 20X4, or 16 bytes for one line. I don't think the library can tell which way so it simply looks at 2 or 4 rows and makes a decision that is compatible with most displays.

olikraus:
Finally I finished my RGB selection menu...

Thanks for the support!

Nice work! Maybe you can use some of my library or not to expand your menu.

Sorry to get in here so late but my broadband service has been out for a week. This problem has come up several times before, here's one instance back in September of 2009: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1253367247

The problem with lines 3 and 4 being offset on 16x4 displays is due to the fact that the LiquidCrystal library does not currently use all of the information provided by the lcd.begin function. As mentioned in reply #4 the library assumes that the starting addresses for lines 3 and 4 are always 0x14 and 0x54 whereas for the 16x4 display they are actually 0x10 and 0x50.

If you want to read about the reason for the curious addressing scheme for these LCD displays then check out the link to LCD Addressing at http://web.alfredstate.edu/weimandn.

Don

If my recollection is right, there are two ways to address the LCD onboard memory (DDRAM?) that stores characters in a 16X4 display, 20 bytes for one line, the same way as 20X4, or 16 bytes for one line. I don't think the library can tell which way so it simply looks at 2 or 4 rows and makes a decision that is compatible with most displays.

There's only one way to address the DDRAM in the LCD controller so there is no decision to be made by the library. The real problem is that the same controller is used for all display configurations and there is no way to inform the controller as to which configuration it is driving. Take a look at the link in reply #11 for the full explanation.

The problem here is in the cursor positioning, not in the storage of data in the DDRAM. The library could be modified to actually use the information in the lcd.begin argument to correctly position the cursor for any display configuration. I believe that John has already done this in his LiquidCrystal440 library.

Don

@Don
I read information at http://web.alfredstate.edu/weimandn/lcd/lcd_addressing/lcd_addressing_index.html. Altogether it seems that the build in (shiped) Liquid Crystal lib is somehow incomplete regarding the unusual 16x4 display. However, i now have a workaround... so for now it is ok for me.

@liudr

Nice work! Maybe you can use some of my library or not to expand your menu.

Thanks. However, the 16x4 port is only a small part of the project i am working on. Actually I am working on a graphical user interface (Google Code Archive - Long-term storage for Google Code Project Hosting.). It also should be portable, so I spent some time on the LCD port of the user interface. I am also aware of your excellent LCD library. It contains features, which i probably will never put into a graphical user interface. Great work!

Here is a picture of the same menu, rendered on a DOGS102 graphics display (however, focus has moved to the ok button)

Oliver

That looks great. I am going to expand my library to ks0108 display but more or less to stay text based. We could exchange some tricks. I am sure if our libraries share some aspects, users of both libs will appreciate. I am going to use java-like names for new stuff. This should make it easier for those with some java background.

liudr:
I am going to expand my library to ks0108 display

I have planed a device independent library. Hopefully it should also work with the GLCD lib.

liudr:
We could exchange some tricks.

Sure. But then, we probably should have another thread about tricks and approaches on user interfaces for embedded systems.

Oliver

Yes. I have a thread on TUI in the software development. We could make a new thread or use that one.

162 is the basic display and my library is working on a 162 display. Some pretty features such as scroll bar and centering highlighted item won't show so well on 162 displays but all essential features are tested on my own phi-2 shield with 162 display :slight_smile:

hi,

is was browing through the forum when stumbling about this thread.
I had the same issue as I was using the LCD library with both 16x4 and 20x4 displays quite a bit and did not want to make any display sepcific programming (other than the parameters to the lcd routines). So I modified the code of the LiquidCrystal library:

i) added a private uint8_t _numcolumns variable
ii) in lcd.begin() saved the column number into this variable (currently it is not passed by the begin, but not used at all)
iii) changed the LiquidCrystal.setCursor to the following code:

void myLiquidCrystal::setCursor(uint8_t col, uint8_t row)
{
  uint8_t row_offsets[4];
    
  row_offsets[0]=0x00;
  row_offsets[1]=0x40;
  row_offsets[2]=row_offsets[0]+_numcolumns;
  row_offsets[3]=row_offsets[1]+_numcolumns;
	
  if ( row > _numlines ) {
    row = _numlines-1;    // we count rows starting w/0
  }
	
  command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
}

this works for both 16x4 and 20x4 display types. Maybe incorporate this in the LiquidCrystal Library ?

best

s

This thread is over a year old - perhaps you should start a new one.

this works for both 16x4 and 20x4 display types. Maybe incorporate this in the LiquidCrystal Library ?

That would be a really good idea and a simple fix. If you somehow catch a sympathetic ear then please try to get them to also change the default configuration (if you omit lcd.begin() statement) to the 16x2 configuration instead of the almost non-existent 16x1.

Don

floresta:
If you somehow catch a sympathetic ear then please try to get them to also change the default configuration (if you omit lcd.begin() statement) to the 16x2 configuration instead of the almost non-existent 16x1.

Don

While this is primarily an issue for other LiquidCrystal compatible library's it is something
to be aware of.

A potential problem with omitting lcd.begin() is that not all the LiquidCrystal compatible librarys call begin() from
their init() function which is often called from the constructors.

Some constructors and init() functions merely initialize their private object variables and perhaps set up
some of the Arduino pins but don't actually initialize the LCD hardware. The actual LCD initialization is
done later, often in begin().

The issue that comes into play is that not all the Arduino facilities are available when C++ constructors are called
because constructors are called so early during the C/C++ runtime initialization.

Because of this it may not be possible to initialize the LCD hardware if it is using something
more complex than directly connected 4/8 bit mode.
(I2c, serial, or some other hardware that may depend on interrupts, delay() etc...).

Just something to keep in mind.

--- bill

A potential problem with omitting lcd.begin() ...

As far as I can decipher with my limited 'C' background the last line of the LiquidCrystal constructor invokes begin() with a default (16,1) configuration and that is how the LCD controller will be initialized. If the sketch does not include an lcd.begin() statement then the LCD controller is left in that configuration but if such a statement is included then the LCD controller will be re-initialized for the new configuration.

As you well know there are one or more LCD suppliers who still publish old example programs written before the LiquidCrystal library was updated (around v0017). Those examples do not include an lcd.begin() statement and virtually anyone who uses one of those sketches with the current LiquidCrystal library will wind up with a configuration that does not display anything beyond the first row (or the first half of the first row on most 16x1 displays).

I can see no detriment to changing the default configuration from (16, 1) to (16, 2) and I can see no advantage in keeping the default configuration as it is.

Don

I do agree with you that if there is going to be a default, that 16x1 seems like an odd
choice for a default given that 16x2 seems be a much more common display.


The need for begin() isn't for the LiquidCrystal library that ships
with Arduino but rather for other 3rd party LiquidCrystal compatible libraries, that may
need other Arduino services that are not available when the constructor is called.

There are also some inconsistencies out there with respect to the default use of "begin()".
Some call it for you, some don't and at least one uses a different geometry than 16x1
So unless the sketch always call begin(), it isn't for sure that it will work or what you will get when using
3rd party libraries.

Here are some examples:

fm's library does not call begin() from the constructor. begin() is common code for all the interfaces.
While the library could call it for the 4/8 bit interface (it probably should for maximum compatibility),
it currently doesn't call it from any of the constructors.

teensyduino's liquidcrystalFast library uses a 20x1 default

LiquidCrystal library for Ladyada's MCP32008 i2c/SPI board calls begin in the constructors for SPI/serial but not for I2c.

LiquidTWI (faster i2c replacement for Ladyada's board) does not call begin() from the constructor.

ShiftRegLCD123 does not call begin() from the constructors.

--- bill