Introduction: C Library for HD44780 LCD Display Controller

About: Software Developer, like to work with electronics, embedded systems, robots etc.

Hello all,

I have started working with Texas Instruments MSP430 value line micro controllers. I still enjoy working with Ardunio but I can pick up a 16 bit TI MSP-EXp430G2 for $9.95.

Texas Instruments is a large company and has really embraced the DIY, maker community. Their online support and documentation is fabulous.

https://store.ti.com/MSP430-LaunchPad-Value-Line-Development-kit-P2031.aspx

I started getting familiar with the chip architecture for the above MSP430. What better way to learn about the chip then to write some code.

I have a few LCD display lying around and decided that this would be a good project to develop.

In doing some digging out on the web I discovered that many LCD displays use the Hitachi HD44780 controller as a programmable interface.

https://www.sparkfun.com/datasheets/LCD/HD44780.pdf

I did some searching out on the web and found a few code examples and one library that implements code for the HD44780.

But most of the code was only small samples of code and really was not formatted for for real production use.

Most of the code I found was incomplete, and really buggy, When I pressed the reset button several times the display when nuts and displayed corrupted characters.

I did find one example of someone who put together a rather nice library, well documented but was missing some common functions that I wanted.

Also nowhere did I fine any really good code samples that implemented the features of the HD44780 interface.

So I decided to take the following library and modify it to add the features that I wanted and then provide some working code examples.

So a bit thanks goes to nikosapi at

http://nikosapi.org/w/index.php/MSP430_HD44780_Controller_Software

Below I will publish some links to my Kiln repository, with public access so everyone can download the code.

Over the next few posts I will also discuss the coding samples I put together.

I have put together a YouTube video of the code samples printing out to a 2 line 40 character display that prints 4 lines, 20 characters each. If you have a different LCD display the library functions will still work, you may have to alter the text length that you are sending in the example code.

Here is the link to the Kiln repository, Click on the "Download Archive" to download the files to your workstation:

https://objetek.kilnhg.com/Code/msp430-hd44780-4-bit-library/Group/Release/Files

The library was tested using the above MSP430 launchpad, but the library should work with most micro-controllers.

The library and code samples were created in Texas Instruments Code Composer Studio, which is an Eclipse application with custom plug ins.

But the code can be taken with run with any tool chain.

Download the code so you can follow along:

Step 1: How to Print Special Characters

SpecialCharacters.c

Look over the below code and we will review

Above is a screen shot of the sample code running on the display:

Notice the line through the 5 x 10 characters. My display is an ERM2004-1

Looking at the specification the below character detail, might explain this line. But I cannot tell for sure as documentation is limited.

#include
#include "hd44780_4bit_lib.h"

/* * This code example uses 5 x 10 character and one line * to display the special characters show in table 4, ROM Code A00 * in the hd44780 specification. * Note using the 5 x 10 characters you can only write to one line on * the display. * */

void main() { WDTCTL = WDTPW | WDTHOLD; // Disable watchdog timer

// according to spec give the display 10ms to come up to voltage __delay_cycles(10000 * CPUSPEED);

// set up data length, number of lines and font // Note 1 line and 5 x 10 characters hd44780_init(N_1LINE, FONT_10);

// if needed set up the cursor and blink // hd44780_send_command(HD44780_CMD_DISPLAY_ON_CURSOR); // hd44780_send_command(HD44780_CMD_DISPLAY_ON_CURSOR_BLINK);

// set Increment direction and cursor direction hd44780_send_command(HD44780_CMD_INCREMENT); hd44780_send_command(HD44780_CMD_MOVE_CURSOR_RIGHT);

// refer to table 4 ROM Code AOO // on how to convert upper 4 bits and // lower 4 bits to formulate the below characters

hd44780_write_special_char(0xEB); hd44780_write_special_char(0xEB); hd44780_write_special_char(0xEB);

hd44780_write_special_char(0xEF); hd44780_write_special_char(0xEF); hd44780_write_special_char(0xEF);

hd44780_write_special_char(0xFF); hd44780_write_special_char(0xFF); hd44780_write_special_char(0xFF);

// this character and the next // character takes up the full // 10 dots in height to print the // decending j and g

hd44780_write_special_char(0xE7); hd44780_write_special_char(0xE7); hd44780_write_special_char(0xE7);

hd44780_write_special_char(0xEA); hd44780_write_special_char(0xEA); hd44780_write_special_char(0xEA);

hd44780_write_special_char(0xEB); hd44780_write_special_char(0xEB); hd44780_write_special_char(0xEB);

}

Lets break the code down and analyse it line by line:

// according to spec give the display 10ms to come up to voltage
__delay_cycles(10000 * CPUSPEED);

// set up data length, number of lines and font
// Note 1 line and 5 x 10 characters
hd44780_init(N_1LINE, FONT_10);

The __delay_cycles() function pauses 10 milliseconds to give the display voltage to come up to operating range. Take a look at the hd44780_4bit_lib.h file. There are some CPU speed related constants that are defined for use with the __delay_cycles() function.
Note: __delay_cycles() function can only take constants as an argument so you cannot use a variable with this function.

The hd44780_init() function initializes the display and arguments can be passed to establish number of lines and font size. This function also sets up the hd44780 interface to use 4 bit operation instead of 8 bit operation. Check the specification for details.

// if needed set up the cursor and blink
// hd44780_send_command(HD44780_CMD_DISPLAY_ON_CURSOR);
// hd44780_send_command(HD44780_CMD_DISPLAY_ON_CURSOR_BLINK);

// set Increment direction and cursor direction
hd44780_send_command(HD44780_CMD_INCREMENT);
hd44780_send_command(HD44780_CMD_MOVE_CURSOR_RIGHT);

The hd44780_send_command() function is used to send commands to the hd44780 interface. The hd44780 can accept both commands and data. By changing some bits in the MPU interface you can either send data or instructions.
So in this next example, if we un-comment either of the two lines we can display a cursor and or blink the cursor.

If you are interested see the reference to the RS Register Selector bit, RS and the RW, Read Write bit for more information.

One of the cool things you can do with the hd44780 interface is determine whether you want to write data from the left to right or right to left. These next two commands determine these settings. We can increment or decrement the cursor move direction, and move the cursor to the left or right when data is sent to the display.

// refer to table 4 ROM Code AOO
// on how to convert upper 4 bits and
// lower 4 bits to formulate the below characters
hd44780_write_special_char(0xEB);
hd44780_write_special_char(0xEB);
hd44780_write_special_char(0xEB);

hd44780_write_special_char(0xEF);
hd44780_write_special_char(0xEF);
hd44780_write_special_char(0xEF);

hd44780_write_special_char(0xFF);
hd44780_write_special_char(0xFF);
hd44780_write_special_char(0xFF);

There is a table in the specification, Table 4 ROM Code A00 that lists characters and symbols that are supported by the hd44780. If you follow arcoss the top of the table to get the column of the symbol you are looking for, (write down the upper four bits) then follow down to the row that contains the symbol you are looking for, write down the lower 4 bits, of that symbol.
You now can construct a full 8 bit symbol, convert this binary number to hex and this hex value is what you can send using the hd44780_write_special{char() function.

The hd44780_write_special_char() function changes the RW and RS bits in the MPU interface and sends the symbol to the display (DDRAM) register (DR).

After writing to DR register the AC, address counter is incremented or decremented based on the status of the Increment/Decrement, Cursor Left/Cursor Right settings. Once you set the starting address the address counter keeps track of where the characters/symbols are written.

// this character and the next<br>// character takes up the full
// 10 dots in height to print the
// decending j and g</p><p>hd44780_write_special_char(0xE7);
hd44780_write_special_char(0xE7);
hd44780_write_special_char(0xE7);</p><p>hd44780_write_special_char(0xEA);
hd44780_write_special_char(0xEA);
hd44780_write_special_char(0xEA);</p><p>hd44780_write_special_char(0xEB);
hd44780_write_special_char(0xEB);
hd44780_write_special_char(0xEB);

This next section of code also uses the hd44780_write_special_char() function to write characters to the display. Two of those characters are the lowercase 'g' and 'j'. The interesting thing to note is that these two characters are extended longer and use the full 10 dot pattern of the 5 x 10 character pattern.
So when printing these characters you must change the display upon calling the above hd44780_init() function. The limitation of setting the display to 5 x 10 character dot pattern is you loose one line of the display, you now can only print to one line on the display.

Step 2: How to Print at a Specific Cursor Position

Let us continue with reviewing the hd44780 LCD library code examples. Please refer to the previous post for links to the source code and an explanation of what we are working on.

We will now look at the next code example:

CursorPosition.c

Note: In the above image, the lines that start with '0' and '1' are line one.
The lines that start with '2' and '3' are line two.

The display I have is an ERM2004-1. It supports two 40 character lines split across 4 20 character lines on the display.

If you have not done so, refer to the last post, for the code repository link, and download the source code so you can follow along.

We will first display the entire code example and then discuss the code section by section.

#include
#include "hd44780_4bit_lib.h"

/* * This code example uses the hd44780_setCursorPosition() functioh * to set the starting cursor position using row, col information * This cursor info is then written to the DDRAM address. * Using this method it is very easy to postion text on the dissplay */

void main() { WDTCTL = WDTPW | WDTHOLD; // Disable watchdog timer

// according to spec give the display 10ms to come up to voltage __delay_cycles(10000 * CPUSPEED);

// set up data length, number of lines and font // notice we have setup the display for 2 lines and // using the 5 x 8 character size hd44780_init(N_2LINE, FONT_8);

// if needed set up the cursor // hd44780_send_command(HD44780_CMD_DISPLAY_ON_CURSOR); // hd44780_send_command(HD44780_CMD_DISPLAY_ON_CURSOR_BLINK);

hd44780_send_command(HD44780_CMD_RETURN_HOME); hd44780_send_command(HD44780_CMD_CLEAR_DISPLAY); // set Increment direction and cursor direction

hd44780_send_command(HD44780_CMD_INCREMENT); hd44780_send_command(HD44780_CMD_MOVE_CURSOR_RIGHT);

// hd44780_send_command(HD44780_CMD_RETURN_HOME); //hd44780_send_command(HD44780_CMD_CLEAR_DISPLAY);

// The display I am testing with is a two line 40 character display // The display shows 20 characters per line so each line wraps twice // for what looks like a 4 line display. // On line one if you write past the 20th character the text // shows up on what appears // to be the third line. // Same goes for the second line, any character past the // 20th character is written // to what appears to be the fourth line. //

hd44780_setCursorPosition(0, 0); hd44780_write_string("0123456789");

hd44780_setCursorPosition(0, 10); hd44780_write_string("0123456789");

hd44780_setCursorPosition(0, 20); hd44780_write_string("11234567890123456789");

hd44780_setCursorPosition(1, 0); hd44780_write_string("21234567890123456789");

hd44780_setCursorPosition(1, 20); hd44780_write_string("31234567890123456789");

hd44780_send_command(HD44780_CMD_RETURN_HOME);

}

The first section of the code is explained in the previous section.

The hd44780_send_command() function sets up the hd44780 interface to send commands to the IR, instruction register. These commands are just setting up the display for writing.

If you are interested, please refer to the hd4780 specification for details. Refer to the previous post for a link for the specification.

hd44780_setCursorPosition(0, 0);
hd44780_write_string("0123456789");

hd44780_setCursorPosition(0, 10);
hd44780_write_string("0123456789");

hd44780_setCursorPosition(0, 20);
hd44780_write_string("11234567890123456789");

hd44780_setCursorPosition(1, 0);
hd44780_write_string("21234567890123456789");

hd44780_setCursorPosition(1, 20);
hd44780_write_string("31234567890123456789");

hd44780_send_command(HD44780_CMD_RETURN_HOME);

The hd44780_setCursorPosition() function calls an Instruction, called 'Set DDRAM address"
The arguments passed set up the line and cursor position so that the next time data is sent to the display, that data is positioned at the correct location.

The hd44780_write_string() function takes the passed string and prints one character at a time to the starting location specified by the hd44780_setCursorPosition() function. The AC Address Counter works it magic so you do not have to worry about incrementing or decrementing the cursor position.

Step 3: How to Read From the Display

readDDRAM.c

This display does not look like much, but take a look at what is really happening.
First we are writing some text to the display, then we reset the starting position of the AC, Address Counter and read the characters that were written.

Then we write the characters that were read back to the display.

Lets look at the code:

#include
#include "hd44780_4bit_lib.h" #include

/* * This code example show how to read text from DDRAM, * in this example we will write some text to the display * then read the text and then write the read text * back to the display. */

void main() { WDTCTL = WDTPW | WDTHOLD; // Disable watchdog timer

uint8_t rtn = 0; uint8_t readStr[80]; uint8_t *pint; unsigned int cnt = 0; unsigned int charCnt = 0;

// according to spec give the display 10ms to come up to voltage __delay_cycles(10000 * CPUSPEED);

// set up data length, number of lines and font // notice we have setup the display for 2 lines // and using the 5 x 8 character size hd44780_init(N_2LINE, FONT_8);

// turn display on and clear the display // and set cursor to home position 0x00 // hd44780_send_command(HD44780_CMD_DISPLAY_ON); // hd44780_send_command(HD44780_CMD_RETURN_HOME); // hd44780_send_command(HD44780_CMD_CLEAR_DISPLAY);

hd44780_setCursorPosition(0, 0); hd44780_write_string("this");

hd44780_setCursorPosition(0, 0);

pint = readStr;

// reads characters from display while(1) { rtn = hd44780_readByte(); if (rtn == ' ') { break; }

*pint = rtn; pint++; charCnt++; }

// writes read characters back to display for(cnt = 0; cnt < charCnt; cnt++) { hd44780_write_special_char(readStr[cnt]); }

hd44780_send_command(HD44780_CMD_RETURN_HOME); }

Let us break up the code and see what is going on:

uint8_t rtn = 0;
uint8_t readStr[80]; uint8_t *pint; unsigned int cnt = 0; unsigned int charCnt = 0;

// according to spec give the display 10ms to come up to voltage __delay_cycles(10000 * CPUSPEED);

// set up data length, number of lines and font // notice we have setup the display for 2 lines // and using the 5 x 8 character size hd44780_init(N_2LINE, FONT_8);

First off we setup some variables that we can use during the reading and writing of the characters extracted from the display.
Notice we are setting up the display for 2 lines and 5 x 8 character dot pattern.

hd44780_setCursorPosition(0, 0);
hd44780_write_string("this");

hd44780_setCursorPosition(0, 0);

pint = readStr;

// reads characters from display while(1) { rtn = hd44780_readByte(); if (rtn == ' ') { break; }

*pint = rtn; pint++; charCnt++; }

We now set the cursor position, on the display to the row 0, column 0 and write the text to the display.
We setup a pointer to the readStr array. Now we loop through the DDRAM, grabbing a character at a time and placing the character into the array.

If the next received character is ' ', we then assume that there are no more characters and we exit the loop.

This is just an example, if you expect a series of words then your logic will have to be a bit more complex, such as looping through the entire line, an easy fix.

// writes read characters back to display
for(cnt = 0; cnt < charCnt; cnt++) { hd44780_write_special_char(readStr[cnt]); }

hd44780_send_command(HD44780_CMD_RETURN_HOME);

Since the cursor position is being tracked by the AC, Address Counter, our cursor is already sitting at a location after the read text. All we have to do is read the characters from the array and display them one at a time back to the display.

Step 4: How to Animate Characters on the Display

animate.c

This image is rather boring. But check out the video later in this post.
animate.c code example shows the animateLeft() and animateRight() functions.

I wanted to spice up task of writing text to displays.

Using hd44780_set_cursorPosition() function, the Increment/Decrement, MoveLeft and MoveRight commands, you can do some rather nice text animation.

Let us look at the code and see how we can accomplish this task.

#include
#include "hd44780_4bit_lib.h" #include

/* * This code example writes text to the screen using the * Cursor Increment, Decrement and Cursor Left and Right * commands, along with some functions that anaimate the * printing of characters to the display * I was going to use timer events for the character * wait time, but I wanted the code to be non CPU specific. */

void main() { WDTCTL = WDTPW | WDTHOLD; // Disable watchdog timer

// according to spec give the display 10ms to come up to voltage __delay_cycles(10000 * CPUSPEED);

// set up data length, number of lines and font // notice we have setup the display for 2 lines //and using the 5 x 8 character size hd44780_init(N_2LINE, FONT_8);

// if needed set up the cursor // hd44780_send_command(HD44780_CMD_DISPLAY_ON_CURSOR); // hd44780_send_command(HD44780_CMD_DISPLAY_ON_CURSOR_BLINK);

hd44780_send_command(HD44780_CMD_INCREMENT); hd44780_send_command(HD44780_CMD_MOVE_CURSOR_RIGHT);

hd44780_setCursorPosition(0, 0);

// The anaimate functions take three parameters: // The text string to print // The visible width of the display in characters // The justification, 'L' for Left justification // 'C' for centered text // 'R' for right jusificatiopn // The number of clock cycles you want to wait after // each character is printed

hd44780_animateRight("This is Right", 20, 'C', 2500);

hd44780_send_command(HD44780_CMD_DECREMENT); hd44780_send_command(HD44780_CMD_MOVE_CURSOR_LEFT); hd44780_setCursorPosition(1, 19);

hd44780_animateLeft("This is Left", 20, 'C', 2500);

hd44780_send_command(HD44780_CMD_INCREMENT); hd44780_send_command(HD44780_CMD_MOVE_CURSOR_RIGHT); hd44780_send_command(HD44780_CMD_RETURN_HOME); }

Let us take the code and review section by section:

hd44780_setCursorPosition(0, 0);

// The anaimate functions take three parameters: // The text string to print // The visible width of the display in characters // The justification, 'L' for Left justification // 'C' for centered text // 'R' for right jusificatiopn // The number of clock cycles you want to wait after // each character is printed

hd44780_animateRight("This is Right", 20, 'C', 2500);

First we set the AC Address Counter to Increment the text, then we set up the display to move the cursor to the right.
Then we set the cursor position to row 0, column 0.

We then call the hd44780_animateRight() function.

Notice we have to pass a few arguments to this method.

The text you want to print to the display

The visible width of line on the display, On my display line one is split between two 20 character lines on the display.

Then we specify the text justification on the display. 'L' for left justification, 'C' for center justification and 'R' for right justification.

You also have to enter a micro second pause time, this parameter will specify the pause time after each character is printed on the display. By changing this parameter you can speed up or slow down the animation of the characters being printed to the display.

Calling the hd44780_animateRight() function will then print the string of text to the display.

hd44780_send_command(HD44780_CMD_DECREMENT);
hd44780_send_command(HD44780_CMD_MOVE_CURSOR_LEFT); hd44780_setCursorPosition(1, 19);

hd44780_animateLeft("This is Left", 20, 'C', 2500);

hd44780_send_command(HD44780_CMD_INCREMENT); hd44780_send_command(HD44780_CMD_MOVE_CURSOR_RIGHT); hd44780_send_command(HD44780_CMD_RETURN_HOME);

Likewise, we can then change the AC, Address Counter to Decrement the cursor position and move the characters to the left.
We now set the cursor position to row 1 and column 19, last character of of the first line. Remember display is zero based. Start counting from 0 instead if 1.

We then call hd44780_animateLeft() to animate the characters to the left.

These coding samples are just a basic example of what you can do with the hd44780 controller interface.

If I come up with more additions to the library I will add them any let everyone know in a new post.