How to read HD44780 LCD programmatically

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

robtillaart:

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?

For reading data from the lcd, I'd prefer that it work just like the write() interface.
A single read() function that returns a byte(s) starting
wherever the address pointer is and lets it increment so it it is consistent with the write() interface.
i.e. a dual function overload:
read()
read(*buffer, size);

Any other needed functionality to set the location can be done by the users sketch code
using the existing API functions like setCursor()
Also having a simple read() API interface doesn't affect any of the other existing code
in the library as well as keeps the new API interface to support it clean and simple.

Having to deal with things like line wrapping on the display gets messy particularly since the existing Arduino supplied
LiquidCrystal library doesn't have any support for wrapping.

--- bill

I also thought of a lcd.read(*buf); that reads into buffer until end of line OR until a non-ascii (e.g. space) is encountered.
and what to think of lcd.readFloat();

and yes, these are all "intelligent" wrappers around reading a single char.

Another idea: (thinking out loud :wink:
should there be a separate current position for read and one separate current position for write?
Or do they share one current position?

The latter is easier, less footprint, but the first one might have some extra value..

In the library, the set cursor position moves to a row and column. There would be no difference between that and read. The only advantage I could see to a separate read position function would be to remember the old location of write and put it back. But that could just be done in the users code. With the read function, you just read out the address counter.

I think it makes the most sense to keep out bells and whistles (not because I am lazy) but because adding functions that the user will not use just makes the code bigger. I know there are ways to do conditional compiling, but I am not that advanced yet otherwise I would modify a nice FAT library to allow changing features since FAT libraries are around 10-13K in size when I mainly would only use read only!

I agree, keep the lib small

the read functions could be conditional with a "simple" #define construct.

something like this is all you need (

// uncomment next line to support LCD read function
//#define SUPPORT_LCD_READ

...

#ifdef SUPPORT_LCD_READ
uint8_t readChar()
{
  uint8_t ch;
  digitalWrite(RWpin, HIGH);

  ...

  digitalWrite(RWpin, LOW); // set back to write mode
  return ch;
}
#endif

Well, that's pretty simple isn't it? I will add that in.

I haven't finished the code yet. Well, actually finished it, but having some issues with timing and haven't had time to work on it again since last night.

I see another post like this in the forum, recently. I am really curious what the purpose would really be. I can't think of any use I would have for it. I was thinking maybe to support input by a user, but you have to white the character to be displayed for the input anyway, so you already know what it is.

This is very low priority for me.

Guys,
keep in mind that the LiquidCrystal library that ships with Arduino today is pretty much stateless.
It does not track any LCD state information like cursor position, memory addresses, scroll modes, etc...
i.e. when you set a cursor position using setCursor() it sends a command to the LCD
to set the memory address and that is it.
Yes it does a quick sanity check on the values, but
it does not keep track of the cursor position, nor any subsequent internal address changes
when future writes are done.

Keeping track of the cursor position inside the LCD is not terribly difficult but the code to do that currently
isn't there and isn't as easy as it would first seem.

To track things for line wrapping takes more than just knowing the geometry.
You also have to keep and track state information for things the left-to-right vs right-to-left addressing.
It also conflicts with the auto scroll modes, so that will potentially drag in the need for some other
new API calls to deal with that.

In my view, these libraries should be very small and simple and limited to unique
hardware functionality.
Any other functionality like reading strings or parsing strings should not be done
in a hardware library.
That type of functionality should be handled by an upper layer since that functionality
is not unique to the hardware.


With respect to using ifdefs, issues with the Arduino IDE
build methodology quickly arise. Library files are built separately from the sketch.
So that means that a sketch cannot set defines to control conditional compilation
of the library within the source code of the sketch.
Also the way the IDE works, the IDE does not have a mechanism to set defines for a sketch.
A library can have a separate configuration header file down its source directory which works
for controlling conditional compilation options but
then the defines, and hence conditional compilation, is global since
it will set the conditional values for all sketches.

--- bill

I was aware of all those things up to the conditional compiling part. I did not know that. That sucks.

But, yeah, I knew that there would have to be other methods for reading the address counter to get the position, etc.. If the user wants to translate that into row and column, that would have to be left up to him. The easiest way to do this independent of the geometry is to just treat it like 0x00 to 0x80 memory addresses.

I'm certainly not planning to spend a great deal of time on it when I really don't see much of a purpose to it anyway. If someone wants to chime in (the OP perhaps) with a great reason to have this capability, I might move it up on my list of priorities. I just cannot think of a single use I would have for this.

A full implementation of the HD44780 is not necessary for 99.9% of the users. Reading the LCD would only be necessary for those who want to copy the display to another device (PC, for example) or who need to test the LCD programatically in a production environment.

Hello Retroplayer,

do you have finished your code? If so, please publish it here, or mail it to me. I am looking for such a code for my "Textsystem" to write, edit, read text strings to/from a 2 x 16 or 2 x 20 or 4 x 16 or 4 x 20 LCD, and store the text, in case of error edited text, in arduinos- or external eeprom. I create and edit the text strings with a german ps/2 keyboard.

PS/2 keyboard functionality of writing and editing text, including cursor control for the LCD, are ok so far. Because all displayed charcters are stored within the lcd, the easiest way to store the displayed text in external eeprom ist to read the text from the lcd RAM, and move it to the eeprom. So your code would help me very much.

Thanks.