HD44780 Instruction Set

There are a lot of LCD modules that use the HD44780 controller. This is a chip that accepts parallel data (8 bits) to control an LCD character display. In my recent twitter2LCD project I needed to determine some of the control instructions such as how to make text scroll and how to control the position of the cursor. There are quite a few places where the complete instruction set is posted, but they are geared more toward seasoned digital electronics users. The main insight I can offer is that if you are using a serial-enabled LCD (as I was), you have to convert the 8 control bits into a byte and send that byte after a specific control character. For the Sparkfun LCD-09393 and related SerLCD modules, the control byte is “0xFE.” This byte grabs the attention of the onboard controller and tells it that the following byte is an instruction and not a character.The basic instructions can be determined from the following table.

The instruction set for an HD44780 LCD controller

The various bit values have specific meanings outlined in the following figure.

Interpretation of the instruction bit values for HD44780

The trick is then to read the DB0 throught DB7 bits as a byte where the LSB is DB0. For example, to clear the display I would send binary “00000001” or hex: 0x01. This is the documented clear byte in the Sparkfun SerLCD datasheet. Some other examples are included in that datasheet, but the following is a table of all HD44780 control combinations.

Instruction Byte
Clear display 0x01
Return cursor to home, and un-shift display 0x02
Entry mode: The following control how the cursor behaves after each character is entered
move cursor right, don’t shift display 0x04
move cursor right, do shift display (left) 0x05
move cursor right, don’t shift display (this is the most common) 0x06
move cursor right, do shift display (left) 0x07
Display control: The following control display properties
turn display off 0x08

display on, cursor off, 0x0C
display on, cursor on, steady cursor 0x0E
display on, cursor on, blinking cursor 0x0F
The following commands move the cursor and shift the display
Shift cursor left 0x10
Shift cursor right 0x14
Shift display left 0x18
Shift display right 0x1C
Function set: the following commands set functions of the controller.
These are more advanced and with a serial controller, you won’t need to mess with them. If you do have to change these, follow the recipe of creating a byte from the bits shown in the table above.
Cursor position: see following discussion for more detail. 0x80 + position

The cursor position can seem like black magic but it makes much more sense once you know that the HD44780 is designed to control a 40 character 4-line display. So if you have a 16×2 then you will only see the first 16 characters of the top two lines. Simple enough once you get used to taking these character positions into account. For example, in a 16×2 display, the first line is position 0-15. So 0x80 is the first position, 0x80 + 12 = 0x8C is the 13th (remember, they are zero indexed). The second line is a little tricky since it shows positions 64-79. Just add the position number (in decimal) to 0x80 (in hex) to get the hex address of the cursor position. The address is the command to move the cursor to that location. So, to move to the 13th position of the top line in a 16×2 Sparkfun Display, I would send “0xFE 0x8C”. The first byte warns the onboard microcontroller that a command is coming, and the second byte is the command.

About these ads

17 thoughts on “HD44780 Instruction Set

  1. Pingback: Twitter to LCD – with scrolling text « The Daily Photon

  2. Hello,

    Is there a way to retrieve the current cursor position in the HD44780 LCD?

    For example, If I type “1234567_” the current cursor position is in the 7th place in the LCD(0 based indexed). Is there a way of retrieving this information through a reading of a register?


    • I don’t know of a way to get that information. I’m sure, like you mention, that some register is holding that data. I’ll let you know if I see anything that suggests reading the cursor position.

      It is usually just easier to move the cursor to wherever you want it to be. That also require less interaction from whatever is driving the LCD.

      • This may be easier than I thought, I had forgotten there was a “read busy flag and address” command. In the table above, setting RS low and R/W high will return the busy flag on DB7 and the remaining data bits will be the address counter value.

        I’m just not sure if this address is the CGRAM or the DDRAM address. Presumably it’s for the DDRAM but you may have to play with it. As for getting this info over a serial interface, the serial interface isn’t designed to read from the LCD so that is probably not an option.

  3. Hi,

    Thanks for the prompt reply. I was looking at the “read busy flag and address” command as well. I was under the impression this would read the entire address counter contents? I was hoping I could just retrieve the actual hardware cursor location.

    Incrementing and decrementing the cursor works well. And although I could keep track of the cursor position through software, I believe retrieving the actual cursor position, and using it as an index is a more fail safe way when trying to manipulate characters in my string array.


    • You are right, the address counter is the address of the cursor. You might be thinking of the DDRAM contents (Display Data RAM). The DDRAM holds all characters that are on the display (and perhaps others that are held in the register outside the limits of the display).

      There are commands to set the DDRAM address (i.e., move the cursor), write to DDRAM (write characters) and this one should read the DDRAM address, which is what you need.

      Let me know if you get a chance to play with it. All my parallel HH44780 boards are wired into things, I only have some serial interface boards so I can’t test it at the moment.

      • Hmmm.. So, being able to retrieve the actual cursor location is possible?

        In other words, if this string is typed ‘”abcdefg_” Can I somehow read a register which will convey the current cursor location is now 7? The ‘_'(underscore) after the g is representing the cursor in this example.

        Unfortunately I haven’t seen code from anyone attempting to get the cursor position. I know it’s not a common mechanism to implement but it would simplify my code greatly.


  4. In general, yes it is possible to find the cursor location by reading the DDRAM address counter. However, physically being able to get the information depends on your setup. Are you coding to a HH44780 that is wired in parallel to a microcontroller of some sort? In other words, do you have wires running to all the pins of the HH44780 or are you sending data to a serial interface like the sparkfun LCD-09393?

    If you are using a serial interface, I don’t think they have anything set up to read from the LCD end (getting info off the HH44780). If you are writing directly to pins on the HH44780, then you should be able to send the “read busy flag and address” command (by setting RS low and R/W high) and then reading the values on the data pins.

    What is your electronic setup?

    • Hi,

      Basically I’m using a driver which was developed by a company called EMAC https://svn.emacinc.com/public/linux-2.6.28-at91/trunk/drivers/char/lcd447.c.

      The driver uses a writecommand() function which writes commands to the LCD registers. I can shift the cursor left or right but I do not see a read command. The data is being sent serially to the device.

      It’s unfortunate there is no other way to read from the LCD if someone is using a serial interface to the controller.


      • Ok. In this case, it is probably just as good to keep track of the characters you write and use a counter (or cursor address) that is software-based.

  5. Hi,

    Question.. If I wanted to simply read the address counter, could I poll the busy flag until it is cleared, wait a certain amount of time and then read the address counter? For example, if the cursor is under the 13th character on the first line of a 2×16 display should I see a value of 0x8C returned back from the read?


    • Yes. Since the busy flag and the counter address come out on different pins, the “read busy flag and address counter” lets you read both of them. The busy flag comes back on the DB7 pin and the address is DB0 through DB6. It is probably a good idea to wait until BUSY is cleared, otherwise you might read the wrong address (i.e., if the current operation is changing the address).

  6. Hi Sir,
    I want to implement the vt52 protocol on 16X2 LCD.
    Actually i want to convert the vt52 cursor commands sequences into our normal LCD commands
    For example- Autowrap on/off,Move cursor up/down n lines, Erase from cursor to end of display..etc
    I want to implement all such commands into LCD please help me for this.

    Thank you.

    • I know it has been a few years since you posted this question but I’m just getting into Microcontrollers and display techniques so I’d like to discuss it.

      So let’s say I have a 16 x 2 display and I want to navigate the cursor around the display with arrow ‘keys’ (just push buttons in a + configuration), I could make left -1 off the address counter with if statements to stop me from going off the screen(controlled by the micro controller) e.g. If I was on the first position on the second line and I press ‘right’ key).

      And to jump up and down lines, I could plus or minus X (X = however many positions is needed to jump a line). Would X be constant?
      e.g. if I was on position 5 of the second line, and I wanted to go up one line I would minus 40 from the address counter. and if I was on pos. 13 of the first line, and I press down, I would add 40?

      Just and idea, but it works in my HALF knowledgeable mind xD (like I said, I’m not experienced, and it’s 6:30 on the morning and I haven’t slept yet, thanks work!)

      Anyway post your thoughts and/or your knowledge on this situation please.

      • Sorry xD

        “e.g. If I was on the first position on the second line and I press ‘left’ key the position of the cursor will jump to the 16th position on first line”

  7. Yes, for a given display size (i.e. 16×2) the number of characters you have to skip to go from the end of the first line to the beginning of the second will be constant. Your display is always a subset of the 40×4 that the controller keeps in memory. It is interesting too that you can write to characters that aren’t displayed and then shift the memory around. Think of the display as a 16×2 view into a 40×4 array of characters.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s