How to read HD44780 LCD programmatically

How can I read the LCD? It is a common HD44780 compatible LCD, connected in parallel 4-bit mode.
Arduino Mega 2560 Rev 3.

#include <LiquidCrystal.h>
. . .
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

There are lots of methods now for lcd, but they have to with writing to the display.
Are there other methods for the HD44780 in LiquidCrystal.h that are not exposed in the header that I can use for reading the display?
Is there another library with some methods for reading?

How can I read the LCD? It is a common HD44780 compatible LCD, connected in parallel 4-bit mode.
Arduino Mega 2560 Rev 3.

#include <LiquidCrystal.h>
. . .
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

There are lots of methods now for lcd, but they have to with writing to the display.
Are there other methods for the HD44780 in LiquidCrystal.h that are not exposed in the header that I can use for reading the display?
Is there another library with some methods for reading?

There is no reading back as far as I know in any library.
The only way to do this correctly is to make a "shadow" screen which buffers the content send to the screen.

This will effectively result in a HD44780 simulator, not trivial but doable - definitely a project in itself.

2nd thought,

Better is to use a model view design pattern.
That means that you make a model (set of vars) you want to be displayed. This model will be displayed on the LCD in a separate function. for that it reads the model too.

pseudo code

struct model
{
int voltage;
float temperature;
}

void loop()
{
  model.voltage = analogRead() * 5.0/1023;
  model.temperature = getTemperature();

  if (millis() - lastDisplay >= refreshTimeout)
  {
     lastDisplay += refreshTimeout;
     // display values from model here
  }
  
  // read back model
  x = model.temperature;
  y = model.voltage;
}

It is not possible to read from the LCD using the current LiquidCrystal library as there are no provisions to use the R/W signal on pin 5 even if you do choose to connect it.

The LiquidCrystal440 library and its updated successor does have provisions for checking the busy flag (which involves reading from the LCD) so you could take a look at that library for some ideas.

To get a copy start here:--> Google Code Archive - Long-term storage for Google Code Project Hosting. and follow the Downloads link to get to the latest version.

Don

Please do not cross-post. This wastes time and resources as people attempt to answer your question on multiple threads.

Threads merged.

  • Moderator

The only way to do this correctly is to make a "shadow" screen which buffers the content send to the screen.

You are answering this from a more modern perspective than might have originally been intended when the LCD controller was designed. I mean that it looks like you are assuming that he wants to read back information that corresponds to that displayed on the screen.

If you are using a display with less than 80 characters then there is some unused RAM in the LCD controller. In ancient times when RAM was scarce this RAM was a valuable resource and could be (and was) used for general purpose storage. Perhaps the OP has an application such as this in mind.

Here is what the HD44780U data sheet has to say (just before Figure 1).

Display Data RAM (DDRAM) 

Display   data   RAM   (DDRAM)   stores   display   data   represented   in   8-bit   character   codes.   Its   extended 
capacity is 80 × 8 bits, or 80 characters. [b]The area in display data RAM (DDRAM) that is not used for 
display can be used as general data RAM.[/b] See Figure 1 for the relationships between DDRAM addresses 
and positions on the liquid crystal display.

Don

The HD44780 LCD has functions to read the display in libraries for other microcontrollers (PicBasic, for example). So I was just searching for the same functions for the Arduino. I really, really like the Arduino, and don't like it when there is support for other microcontrollers which is lacking for the Arduino.

For the immediate need, I will create an in-memory ("shadow") view of the LCD, send that view to the LCD, and also then be able to read fro that view. It will be a simple 2x16 array of char. Fortunately there is a lot of extra programming space in the Mega 2560. Having this view in RAM serves the capability of cloning the LCD display to the PC, but doesn't help any in auto-testing the LCD, hence the need to read the LCD.

In the future I will work on providing an update to the Arduino library to make it more complete.

Thank you for all the comments and suggestions! I consider the question to be answered.
Phil Dorcas

Do you have access to library code of one of those other platforms?
Can you post a link?

In PicBasic, the support for the LCD is built into the language, and I don't have access to it's source code.
The methods to read has two parameters, the first is the address to read from the LCD, usually $80 or $C0 for the first and second lines respectively. The second parameter is an array of characters, where the LCD characters were placed.

Examples for reading from the LCD:
LCDIN $80, [ InArray[20], InArray[21], InArray[22], InArray[23],_
InArray[24], InArray[25], InArray[26], InArray[27],_
InArray[28], InArray[29], InArray[30], InArray[31],_
InArray[32], InArray[33], InArray[34], InArray[35] ]

LCDIN $c0, [InArray[36], InArray[37], InArray[38], InArray[39],_
InArray[40], InArray[41], InArray[42], InArray[43],_
InArray[44], InArray[45], InArray[46], InArray[47],_
InArray[48], InArray[49], InArray[50], InArray[51] ]

I'll read the Fujitsu documentation and figure it out for the Arduino. Wish I had other source code to access as a guide. Maybe from the mfg. Thank you.

Reading from the LCD is pretty much the same as writing to it. When you write to it, you are simply putting a byte into the DDRAM. So, you just read it instead... You do need control of the R/W line, though.

So you set the RS pin high, the R/W line high, then toggle the E line. Each time you toggle the E line, it will increment (or decrement depending on how you set it up) and give you the byte in the next address.

So the only difference is that you are setting the read/write line high instead of low and listening on the data lines instead of writing something to it. Modifying a library wouldn't be much more than copying the functions and changing them to set the read write line and return a byte ( or array of bytes) instead of sending one.

That sounds easy enough. Thank you! I'll look at the LiquidCrystal library, and make the recommended changes. Thank you very much for your help!

You got me looking at it, actually. There actually already is support for a RW pin if you define one. I've made several little changes already to support reading. If I were to modify the library, what functions would be useful? I would think a read function where you give it an address and length would be useful. What else?

So you set the RS pin high, the R/W line high, then toggle the E line. Each time you toggle the E line, it will increment (or decrement depending on how you set it up) and give you the byte in the next address.

It's not quite that simple in the 4-bit mode since you have to read twice for each byte and reassemble the nibbles. Also, don't forget that you do the actual reading while E is high, not after it goes low.

You got me looking at it, actually. There actually already is support for a RW pin if you define one.

Look again. If you define the pin then all they do is drive it low...PERIOD.

I am not trying to discourage you, I am just pointing out some of the problems. John went through all of this when he was writing the LiquidCrystal440 library a few years ago and I provided him with some code for starters. All he was doing is reading the busy flag, but the added work to get the other seven bits should be trivial*. Why don't you see if you can find anything here --> Google Code Archive - Long-term storage for Google Code Project Hosting. (follow the Downloads link to get to the latest version) before you try to reinvent the wheel.

Don

Edit: * Famous last words....

I would think a read function where you give it an address and length would be useful. What else?

primary functions would be

char lcd.readChar(row, col) // reads 1 char
char * lcd.readStr(row, col, len) // reads len chars - should it wrap around end of line?

some ideas:

char lcd.readChar(); // reads form last known (internal) row/col e.g. gotoxy(r,c); x = lcd.readchar()

char lcd.readNext(); // reads a char and moves to next position?

maybe some function to read self made chars / font back into an array?

readback backlight status?
bool lcd.getBackLight()

floresta:
Look again. If you define the pin then all they do is drive it low...PERIOD.

Well, obviously. That's because all of the functions in there are write functions. But the point is that pin is within control of the library if it is defined. In each writing function, they call it low again. So, for our read functions, we just drive it HIGH. How difficult is it to tell a signal to go high? Just one line of code added for that.

Nearly 90% complete with the added functions. NOT a huge deal.

In each writing function, they call it low again.

that means it was inefficient all the time ? :wink:

... - should it wrap around end of line?

Unless you want to open a really big bucket of worms you should probably deal with the LCD memory as just that, 80 bytes of memory, almost always with an unusual gap in its addressing pattern that is handled automatically by the LCD controller.

Don

floresta:

... - should it wrap around end of line?

Unless you want to open a really big bucket of worms you should probably deal with the LCD memory as just that, 80 bytes of memory, almost always with an unusual gap in its addressing pattern that is handled automatically by the LCD controller.

Don

At first I am writing it like that, just an absolute address. The user can handle any of that in code. I figured it would be more efficient that way since it would keep the code smaller for those that don't need all the bells and whistles. I will probably expand it further, though.

I don't think anyone has bothered doing this before because I can't really see a purpose for it, honestly. shrug

I don't think anyone has bothered doing this before because I can't really see a purpose for it, honestly. shrug

Nowadays there probably isn't any really useful purpose other than as an academic exercise. As I mentioned in reply #6 it could really be useful if you already were using an LCD in your design and you needed a few bytes of RAM for some purpose. If the LCD was memory mapped it was probably even easier do accomplish than it is now with our I/O approach. The Optrex manual (dmcman_full) has more on this aspect.

Don