Reading from LCD 16x2

Hello, I'm new to LCD coding and I'm facing some difficulties trying to read the characters from the LCD controler.

I understand from the datasheet that this can be performed by turning the RS ans R/W pins to HIGH. Then I should specify an adress and turn the Enable pin HIGH to read the corresponding data (which is in ASCII code).

The thing is that I don't know how that would translate in the Arduino language. I know how to set RS, R/W and E to HIGH but how should I specify the adress of what I want to read ? Can I use setCursor() to do that ? I also lack some understanding on how does the microcontroler (UNO) actually communicate the data to be displaid by the LCD (at a specified location). Consequently, I don't know neither how or even what to read. Would it be a binary coded ASCII character ? And in that case how could it be described with only 4 bits (as in the Hello World example : when it should take 8 bits to do so ?

Please help me :confused:

It must first be asked - why would you want to read back what you have already written to the display?

It is far easier for such a small display, to simply write what you want, and you already know what you wrote anyway.

It is not a trivial exercise to read information from the LCD module and, as Paul has said there's rarely any reason to do so.

The LiquidCrystal library does have provisions to implement a connection to the R/W pin but it has no provisions to use that connection. Theoretically you could write some additional functions to do so.

If you are interested then you should start by looking for programming examples that implement the 'busy flag' since the information that you desire is retrieved along with the busy flag. A simple Google search for 'LCD programming examples' will yield such code.

You indeed would use setCursor() to specify the address of what you want to read.

When you use a 4-bit connection to read 8-bit data you do so by doing two consecutive reads and you then reassemble the byte from that data.


Thank you for your answers. The reason I’m doing this is that I am designing a digital clock to be displaid on the LCD without using an RTC module. What I want is to have a method that would allow the user to set the time using buttonswitches from the breadboard. This would update the initial time from which I add a duration using millis(). In this particular situation, the display changes quite fast and it might be a bit risky to relly on what I think the time will be at a given time.

I will have a look to those busy flag examples and try to figure it out. Thank you again for your help.


the display changes quite fast and it might be a bit risky to relly on what I think the time will be at a given time.

But YOU are updating the display, so no matter how fast 'it' changes you are asking 'it' to display something, so you should know what that is at all times.

So from what you describe, you have absolutely no need whatsoever to read from the display then.

You will find that the main problem with rapidly changing the display information, is that it will blur as in particular, it takes significant time for a "lit" segment to fade. Your problem seems to be the very opposite of what you imagine. Do not attempt to update the display any more often than eight times per second. Three to five is far more realistic.

Perhaps you should play with the "Mario" exercise first to get the idea. :grinning: Try increasing the FPS from the default 4.

Ok, I get it, “don’t even try” :grin:
I’ll just create variables to store what I send to the LCD instead of throwing directly the outputs of my “timer functions”. Anyway, I’ve learned some quite interesting things along the way, in particular that an 8bit interface divides by two the communication time (relative to the 4bit interface that I was using) which will definitely be better in this project (considering I don’t use much more other pins on my UNO anyway).

Thanks again for helping !

Yes, you can read a HD44780 if you have the RW pin under program control. Just look to see how a library checks the BUSY.

The speed of 4-bit or 8-bit interface is similar. You can write the single Enable strobe in 1us for an 8-bit. You can write the two strobes in 2us for a 4-bit.

The actual operation cycle takes 37us to complete. So you can write a fresh character every 37us. e.g. 1us + 36us to do something else. Or 2us + 35us to do something else. You may find this significant !

Of course, I am talking theoretically. The Arduino library probably wastes the 35us anyway. And will probably have some processing overhead.

It is a mystery why young people are so concerned with writing fast to an LCD. Your eyes can't read that fast. The actual liquid crystal takes time to change.


Many: Anyway, I've learned some quite interesting things along the way, in particular that an 8bit interface divides by two the communication time (relative to the 4bit interface that I was using) which will definitely be better in this project (considering I don't use much more other pins on my UNO anyway).

Again - it simply is not worth it. Use the 4-bit interface like everyone else! :grinning:

There is a delay involved in sending a command to the controller - but the delay is in the controller, not the interface!

While you could use the "busy" flag (which involves the same read command as you would use to read data) to minimise delay, it is in practice simpler just to invoke a delay. Now the trick is that the delay only occurs once you issue the command, and the command is only issued once it receives all eight bits. This means that you issue the second four bits immediately after issuing the first four bits, there is no delay between, only after you have issued the command, So in practice, there is negligible inefficiency in using the four bit mode and you will find it no faster to use the library in 8-bit mode.

Whilst the delay is written into the library, you could bypass that and remove the "busy waiting", writing your own code to perform the command transfer, then execute other code while waiting for the command to complete.

But again, the counting task in your situation is far slower than the delay involved in sending commands to the LCD and simplicity will win out. :grinning:

Ok... I'll keep it simple :D

One more thing. If you do use the busy flag in an attempt to get rid of the fixed delays involved in dealing with the LCD you should incorporate some sort of timeout sequence in your busy-flag code. Otherwise your entire program could hang up (waiting for the flag to change) if there is a problem with the LCD.


Thanks for this advice. Since the delay is so small I will keep it simple in the context of this project but I’ll try this afterwards, if only to get a better understanding of LCD display.

Many: Thank you for your answers. The reason I'm doing this is that I am designing a digital clock to be displaid on the LCD without using an RTC module. What I want is to have a method that would allow the user to set the time using buttonswitches from the breadboard.

As paul said, from that description there is absolutely no reason to read the display. In fact, you probably need to re-think your implementation. For something like that, the typical design is to separate things into separate and distinct "layers". - Time keeping - Time Display - Time setting

For tracking time, you will want to use something that runs in the background. And the best way to track time is actually not to track it in human form of (hr, min, sec, etc...) but by using an epoch counter. The Time library is great for handling time as it tracks time using an epoch an includes all the necessary API functions to access the time, convert it to human elements like yr, mnth, day, hr, min, sec, etc, and to set the time. The Time library can work with or without an RTC.

Then all you need is a way to display the time elements and a user interface to set it.

It doesn't make much sense to be worrying about the timing overhead of things like 4 bit vs 8 bit as as 4 bit mode when used across something as slow as a i2c i/o expander can still update the display memory faster than the liquid crystal inside the LCD display can rotate its molecules to change the actual pixels. And then the human eye is not particularly fast at seeing changes so the speed of updating the display of 4bit vs 8bit is not a visual issue. It may be a CPU overhead issue if you have other CPU needs in your code as a slower interface uses more CPU, but it is pretty much a non issue from a visual perspective. And for something as simple as a clock, there shouldn't be any realtime CPU overhead issues.

--- bill

I know how it uses just 4 bits to communicate what needs 8 bits. First it flashes the first 4 bits of the code and the. last 4 bits of the code.

Commenting to unlock the thread at the request of a forum member.

Hi to everybody,

I believe I was Many time ago.

I can't explain how, why and ... but I asked because I am a cybersecurity expert, and those days I was looking for answers in question. Nowadays I am developing a project called SOS. It is a project of 1k of ways to send an SOS signal.

In the project I have implemented what I asked here, thanks to you all and the data sheets plus the docs. Then, I am here to advice the code is ready. On GitHub: Please pay attention to it!

Why did I this project of reading RAM of LCD? Simply: resources. Avoid using a buffer to save shell commands and answers, in case of a situation of emergency where we won't have enough... the philosophy is to keep the resources alive in consequence, to work harder. Have a look the a use case in the same project. Subproject number 1: KeyToLCDEMAIL2... nothing else. Here to serve & try to help. Best regards and thanks to all.

freeyournetwork, Lots of poetry/philosophy about life in your project. I am not grasping the project. I do see a modified LiquidCrystal library with the added code in a recv() and read4bits() to read data from DDRAM but it does not appear to be used in the KeyToLCDEMAIL2.ino sketch. So I don't understand the use case for needing to read the LCD ddram.

BTW, the hd44780 library includes a read() function and a status() function to allow reading data from ddram and getting the lcd status value which includes the current ddram address. These functions are available across multiple i/o classes so you can use them on lcds that are controlled directly with pins or via a i2c backpack.

--- bill

Hello bill (bperrybap),

thanks for your interesnt on the project and my reply. I have to say that I am a bit scared of receiving bad words, but at the moment all of those are plenty of grace.

Well, I need to explain a bit the project and the motivation, and I do as follows. The covid-19 made me to encourage against the need of resources, and I was wondering to save memory from the LCD readings... (sorry my bad english). But the project is abdandoned and I don't know really why I removed the implementations of the LCD char reading... but I did to be able to use the SOS... well, no matters. The true is that I was thinking first to do some way and later I realized to do it better other way. And as it costs to me a lot to do the code for reading the LCD; I decided to publish it.

The true is also that I hope somebody can use it instead of me, or also as me. I did first, but later I removed it because I found other way to do a tty on the LCD and the SIM... well, that's how I can explain it. If someone wants to use the code and to improve it is welcome. I was used to encourage against unimplemnted things and try to do them. Usually there're not needed, and some others I just remove them from the main code. Anyway, the project is now finished... ( I mean Idk if it will be used somewhere by me or anyone else...).

Poetry is because those days were really hard to me, we are experiencing a hard situation where I was trying to situate me in a very chaotic world, and nobody helped. Well, that's not really true. I mean, nobody else helped on the development actively or shared my worrying... which I recognize was really high. But... I realized also I can not fight against the world, I can try to do my best, but if I see is a waste of time and energy to try to save the world with SOS systems to help each other in a very chaotic world, and people is thinking in going for party for example (I don't judge I only say the main thinking of myself) instead of doing something to help... what can a man only do for the rest of the world? A lot of people, well, some 5 people, helped me on Tg and Fb with likes... it was very interesting and heavily hard to speak about the topic, but... I also realized those systems are really also hard to build for an expert, how complicated may be to people without skills? And without the proper injection of money or help, the project went inside the place of the sunken dreams... sorry. I tried. The probability of losing was high, the only way to do it was to try it and hope the people will help. That's the way I was so poetic... and philosophic. But... maybe I was wrong and the world isn't so wrong actually. I really don't know. I just try to continue my life and try to give the best I have.

Thanks by your help. Hope this at least, helps also.

--- Abel

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.