main index My Arduino-related project pages begin here!

After seeing that Arduino environment release 0012 includes support for HD44780-like alphanumeric LCD screens, I decided to give a try.

I bought a nice 20×4 LCD display (blue background, white characters), claiming to be HD44780-compatible and "only requiring 5V". It was actually a Winstar 2004A display with a KS-0066 compatible controller, which is said to be pin-to-pin compatible with Hitachi HD44780 ones.

Driving such a display requires, at minimum:

Project target: sending a string from the computer to the Arduino, and see them printed on the LCD screen.

It was fun because it was not that easy. When you read specifications, you just think "I only have to connect a few wires and run the example program". Well, I had to troubleshoot until late evening...

Problem #1: I only connected +5V and GND, but the LCD does not show anything, not even a pixel. And I already double-checked all wires!

It seems that almost all LCD out there do need the "contrast adjustment" pin to be set to some level, generally depending on ambient temperature (!).

In the datasheet of the LCD I found that "Vss-V0" has to be, at 25ºC, 4.1 to 4.7V, with a typical value of 4.5V. That is, when Vss is 5V, then V0 (contrast control pin) should have tipically 0.5V; I had no time to work out any solution and just tried shorting V0 to GND: it worked, I finally saw the display showing a white row, a "black" one, a white again, and a black one again (this is what appeared after powering up the LCD display: in that moment I only had +5V, GND and V0-to-GND pins).

Later, I connected V0 to a PWM pin of the Arduino, and tried the analogWrite function to send out different values (with 0 meaning GND and 255 meaning "always 5V"); it does not work (even if it appeared to work for a fraction of a second). So I switched back to the original el-cheapo setting (V0 shorted to GND).

Problem #2: the LiquidCrystal library does not work! Arduino environment complains about missing parameters, and so on...

This appens in the 0011 release. I just had to upgrade to Arduino-0012 and the LiquidCrystal finally compiled and worked.

Problem #3: 4-pin drive does not work! Display does not show anything, and LiquidCrystal does not have any error logging.

This was the least fun part of all the work. I added wires for 8-pin mode... and later I found that the LiquidCrystal-related page I read mentioned D0/D1/D2/D3 making me wiring DB0/DB1/DB2/DB3 instead of DB4/DB5/DB6/DB7 (when driving an HD44780-compatible in 4-bit mode, you have to use the high nibble - DB4 to DB7 - not the low one!)

Problem #4: I finally see something on screen but... it's all garbage!

This was an easy pick: I just reverse-placed the cable (so that DB7 went on DB4, DB6 on DB5 and so on).

Problem #5: I finally am able to write on the screen but it works out the odd rows first, and then the even ones!

This is documented in the HD44780 datasheet. I solved this in software. My program accepts up to 80 characters, including new-lines, and reconstructs the correct "screen map" to be output to the LCD.

Simply speaking: the first 20 characters go straight on the first row; the next 20 are to be sent as if they appeared on the third row (that is, offset 40 instead of offset 20), the next 20 on the second row (that is, offset 20 instead of 40) and the last 20 on the fourth row (offset 60).

Problem #6: the display is still hard to read even when in daylight...

The display is useless if you don't backlight it!

I had to wire the "A(Vee)" and "K" pins of the LCD (backlight power source and ground).

As of the LCD datasheet, the backlight requires 4.2V (ouch!); I tried a few seconds shorting the "A" pin to +5V and it worked great (giving out some great intense light), but I don't want to fry it in a few days (minutes?), so I had to try some solution.

At first, I used a diode (the "small flying thing" next to the "small thing" on the left side, on the 3v3/5v/gnd Arduino pins): the voltage dropped to 3.9V, thus in "safe zone".

Then I tried to short "A(Vee)" to Arduino's +3.3V, which also worked - with less light (this solution is good for night time) :-)

Problem #7: where did you take all those Arduino pins?

The six Arduino "analog" pins may be used as common GPIO pins and are numbered from 14 to 19 (14 is analog pin 1, etc).

It is thus legal to issue a pinMode(14, OUTPUT) and then a digitalWrite(14, 0).

Problem #8: the display (or the Arduino) seems to reset without any reason (or resets while receiving data).

Just check the wires and do not follow my "spaghetti-like" wiring shown below (I just was in a hurry to show to my friends the working display).

Other problems and possible solutions

1) incorrect voltage; my display was guaranteed to work at 5V (Arduino works at 5V), is yours "5V" or "3.3V" or other voltage? (example: only the "Arduino Micro" works on 3.3V); does it require different voltages? (example: +5V power supply, 3.3V control lines; I cannot swear that every HD44780-compatible display works on 5V...); you may need to use some "drop-voltage" solution (example: a diode in the correct direction makes out some 0.7V voltage drop);

2) incorrect DB4/5/6/7 wiring; you can correct it in software, at LiquidCrystal initialization; for example, if you were using LiquidCrystal lcd(11,2,3, 4,5,6,7) for 4-5-6-7 Arduino pins connected to DB4-5-6-7, you may have to change it to LiquidCrystal lcd(11,2,3, 7,6,5,4) (I reversed my 4-pin connector because I did not solder both ends), or -maybe- 4-6-5-7, or something like that; if in doubt, you may quickly try all combinations;

3) involuntary short-circuit on DB4-5-6-7; "visual inspection" (and tester-meter verification) should prove that you did not short any pins (if Arduino sends 0110 and the LCD gets 0111 you will always get garbage...);

4) same applies for RS-RW-E wiring errors: did you indvertently swap RS (register-select), RW (read-write) and E (enable) pins? This also is correctable in software. Incorrect wiring will give out lots of garbage even if you print only an "A";

5) problems using control characters and font/escape/command characters; at first, just print "Hola" and check if only those four characters get printed on screen (if the screen gets filled by garbage, then the problem is almost surely in the wiring);

6) finally... the display may be actually damaged :~) (I know a guy who fried a $149 board applying a non-regulated 5V power supply for almost two seconds).

Source code

If it appears too complex for you, go straight for HelloWorld and SerialDisplay sources in the .../arduino-0012/hardware/libraries/LiquidCrystal/examples directory.

#include <LiquidCrystal.h>

// my pinout from L (LCD pin) to A (Arduino pin):
// LCD pin 1: Vss --> to Arduino GND
// LCD pin 2: Vdd --> to Arduino +5V
// LCD pin 3: V0 (contrast) --> to GND (I chose the PWM pin 10, see below)
// LCD pin 4: RS (register select) --> to Arduino pin 11
// LCD pin 5: R/W- (read/write) --> to Arduino pin 2
// LCD pin 6: E (H/L enable) --> to Arduino pin 3
// LCD pin 7: DB0 (data bit 0) --> to Arduino PIN 4
// LCD pin 8: DB1 (data bit 1) --> to Arduino PIN 5
// LCD pin 9: DB2 --> to Arduino PIN 6
// LCD pin 10: DB3 --> to Arduino PIN 7
// LCD pin 11: DB4 --> to Arduino PIN 14
// LCD pin 12: DB5 --> to Arduino PIN 15
// LCD pin 13: DB6 --> to Arduino PIN 16
// LCD pin 14: DB7 --> to Arduino PIN 17
// LCD pin 15: A/Vee (backlight+) --> to a 4.2Vcc source (see documentation)
// LCD pin 16: K (backlight-) --> to Arduino GND

LiquidCrystal lcd(11,2,3, 4,5,6,7, 14,15,16,17);

int contrast = 10;                 // PWM pin (contrast level)
int led = 13;                      // LED pin (alive led)

char *boot = "(C) AlfonSoftWare   Winstar 2004A KS0066"
             "InterNational 2009  Arduino Diecimila   ";

void setup()                       // initialization

  pinMode(contrast, OUTPUT);
  pinMode(led, OUTPUT);

  analogWrite(contrast, 0);       // 0: maximum contrast  255: minimum
  digitalWrite(led, 1);


void loop()                        // main loop
  static int i=0, ctr=3;           // led blinking section
  i = (i+1)&31;
  digitalWrite(led, i>ctr);

  if(!Serial.available())          // no incoming text?
  static char pos[80] =
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
    40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
    20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
    60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
  static int con[9] = { 0, 30, 60, 90, 120, 150, 180, 210 };
  char buf[81], *ptr = buf, chr, flg = 0;
  int cur = 0;
  memset(buf, ' ', sizeof(buf));
  buf[80] = '\0';

  delay(15);                     // wait for all chars to be in (80 chars at 57600)
  while(Serial.available() > 0)  // for every character available:
    chr =;         // fetch next
    if(chr == '\n')              // simulate carriage returns
      if(! flg)                  // ignore fake carriage returns
        if(cur<20) cur=20;       // from 1st to 2nd line
        else if(cur<40) cur=40;  // from 2nd to 3rd line
        else if(cur<60) cur=60;  // from 3rd to 4th line
    flg = 0;
    if(chr >= 1 && chr <= 9)     // contrast setting characters
      ctr = chr*3;
      analogWrite(contrast, con[chr-1]);
    if(chr<' ' || cur>79)        // skip non-printable chars
      continue;                  // and out-of-area chars
    buf[pos[cur++]] = chr;       // store character
    if(!(cur % 20)) flg = 1;     // remember "end of line" condition
  lcd.print(buf);                // output the formatted screenshot

  Serial.print(buf);             // serial debug output

Yay! it works!

home page - send e-mail - continua (next page)