8 Jan

TimeWasters LCD Framework for HD44780 and Arduino

At the moment i am working on my Geiger-counter which is based on this hardware, but has many more features added to it (GPS, SD-Card and Buttons). I will post more information as soon as i managed to fixate the last piece of hardware in the case.

While working on it i wanted to have a luminous LCD display and stumbled over a very nice piece of hardware: OLED displays from Electronic Assembly.

OLED displays have many advantages over classical LCD displays:
– Low power consumption
– Perfect contrast
– No viewing angle
– Bright
– Background is really Black

But after ordering a 2×16 OLED display for round about 30 euros from Reichelt i was not able to correctly use it with the Arduino LiquidCrystal library, it showed most the time pixel garbage.
At first i thought the display was broken, but as i was digging deeper into the matter i found that this display is only HD44780 controller “compatible”. What that means depends on the manufacturer.

After weeks of experimenting and reading tons of documentation i was finally able to drive the display (almost) without errors.
I have written my own minimal LCD “framework” to drive my OLED, mainly because the OLEDs from Electronic Assembly will most the time not work correctly with the Arduino library.
The cause is that the OLEDs use a different initiation command order and are reacting VERY strange if one does not follow them.

Driving a HD44780 compatible LCD is simply a pain in the ass. The command structure is not that hard to understand, but ambiguously written documentation and the sensitive behavior on the timing of the commands is not really helpful.

So here i present you my framework, published under GPL for your using pleasure.

The framework is intentionally stripped to the bare bone, the absolute minimum to use the LCD, there are no “convenience methods”. It is written for 2×16 character displays but it will work with other ones if you adapt the code. The advantage is that it is only 70 lines in size (with commentary!) instead of 400 lines on the Arduino LiquidCrystal library.

The framework will also work with “real” HD44780 displays, i tested it with the old display which was bundled with the Geiger counter board.

Here is an excerpt from the commentary:

 * Features:
 *  - The most simple code needed to drive the LCD
 *  - Define your own characters
 *  - Uses the String class for convenience
 * Usage:
 * Copy this file into your projects directory (where "your_project.ino"
 * resides) and add the following code
 * - To the top of your main project file: "const byte lcdPins[7] = {0, 1, 2, 3, 4, 5};"
 *   Change this numbers to the pins on your Arduino you have the LCD connected to.
 *   The order of the pins are: {RS, E, D4, D5, D6, D7} (those are the pins on your LCD)
 * - Into the setup method: "lcdInit();"
 * without the quotation marks respectively.
 * Close the Arduino IDE and reload your project.
 * For a general reference how to connect your LCD, please refer to:
 * http://arduino.cc/en/Tutorial/LiquidCrystal
 * This framework works with the 4-bit connection only, but can be 
 * rewritten to work with 8-bit.
 * This Framework is configured to work with 2x16 displays with 5x8 pixel 
 * character size. To use another size of display you have to change the 
 * configuration in lcdInit() according to the manual you received from
 * your LCD manufacturer.
 * Usage Examples:
 * write text to the display:
 * - lcdWriteLine(String("Line"), 0x80);
 * The second parameter is the cursor position where the line is written
 * to. The first character of the first line is 0x80, the first character 
 * of the second line is 0xC0 and so on. If you do not want to set it to 
 * the first character respectively, you have to add the number of 
 * characters to the hexadecimal value. For instance: You want to
 * write to the 6th character in the first line, you have to set the 
 * cursor to 0x85. The String can be of any length.
 * Clear the Display:
 * - lcdWriteCommand(0x01);
 * Please note: you have to wait at least for 1.7 milliseconds before
 * you write anything else to the LCD, otherwise you will have random 
 * effects. Just use delayMicroseconds(1700); afterwards.
 * Create a user defined character:
 * - lcdCreateChar(8, myCoolCharacter);
 * The first parameter is the position to write the character to, there 
 * are 8 positions available, 8 to 15. The second parameter is a bytearray
 * consisting of 8 bytes containing the character pixel data:
 * const byte myCoolCharacter[8] = {B00001,
 *                                  B00011,
 *                                  B00111,
 *                                  B11111,
 *                                  B11111,
 *                                  B00111,
 *                                  B00011,
 *                                  B00001};
 * Please use exactly this format. every "1" in the binary data is a 
 * visible pixel, where all 8 bytes form a complete character, line 
 * for line. This command can be called from any method, but i suggest 
 * using it only in the setup method. 
 * Use a user defined character:
 * - lcdWriteLine(String(char(8)), 0x80); 
 * It is better to write every user defined character with a separate 
 * command, i had some very strange behavior if i concatenated those 
 * characters with other Strings, and i have NO F***ING idea why. I 
 * checked EVERY byte transmitted to the LCD without any clue.
 * The typecast is needed to force the String Class to accept the value
 * as a byte representation instead of a string representation (which 
 * would consist of 3 characters representing the readable value if you 
 * write "125" for instance).
 * Tip:
 * if you want to send a float or double value to the LCD, it is not 
 * natively possible with the String class. You have to cast it to 
 * string using the following commands:
 *   char tempBuffer[20];
 *   String myValueAsString = String(dtostrf(myFloatValue, 6, 2, tempBuffer));
 * The second parameter of the dtostrf command is the minimum character 
 * length reserved for the string, the third value is the number of 
 * decimal places the string will have. In the above example the string 
 * will look like the following:
 *       0.12345678 =   "  0.12"
 *       1.12345678 =   "  1.12"
 *      12.12345678 =   " 10.12"
 *     123.12345678 =   "123.12"
 *    1234.12345678 =  "1234.12"
 *   12345.12345678 = "12345.12"
 * This is very counter intuitive, but i don't know how to explain 
 * it better. This command will NOT round.

I hope it will be as useful for you as it is for me, although i give no guarantee for it.

Download: TimeWasters LCD Framework v1.0

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.