Sometimes LCD doesn't display anything?

Hi all,

I have a parallel (?) 16x2 LCD wired to my Arduino, as per this PDF: Arduino Playground - HomePage

3 out of 5 times (approx) when I power up the Arduino using an external power source, nothing appears on the LCD screen. I know that the Arduino code is running because I chucked in an LED blink in the loop.

My external power source is from a regulated 9v IC. I know I'm not giving it too much power and it's as clean as a whistle. So I also tried putting a delay in the setup routine.

Is there something more I need to know about having an LCD connected?

Here's the code I'm using:

#include <LiquidCrystal.h>

// LiquidCrystal display with:
// rs on pin 12
// rw on pin 11
// enable on pin 10
// d0, d1, d2, d3 on pins 5, 4, 3, 2
LiquidCrystal lcd(3, -1, 2, 7, 6, 5, 4);

void setup()
{
  delay(2000);
  // Print a message to the LCD.
  lcd.print("hello, world!");
}

void loop()
{
  digitalWrite(13, HIGH);
  delay(500);
  digitalWrite(13, LOW);
  delay(500);
}

Any ideas would be helpful!

Cheers,
Scott

When I turn it on and there's nothing on the display...if I press the reset button, the text will appear on the screen...

I've tried this code, same result:

void setup()
{
  delay(2000);
}

void loop()
{
  digitalWrite(13, HIGH);
  delay(500);
  digitalWrite(13, LOW);
  delay(500);
  lcd.clear();
  lcd.print("hello, world!");
}

I don't use LiquidCrystal myself, but from what I can see the LCD is initialized when you create an instance of LiquidCrystal. Perhaps this is done too soon after power-on, maybe the LCD needs a initial delay before you set it up? Adding a delay() in setup doesn't help, because the instance is a global variable created as soon as the sketch is called by the bootloader.

You can test this theory by creating the instance and printing the welcome-message in loop() instead. Then lcd won't be created until loop() is called the first time.

void setup(void)
{
  delay(1000);
}

void loop(void)
{
  static LiquidCrystal lcd(3, -1, 2, 7, 6, 5, 4);
  static welcome = 0;

  if (!welcome)
  {
    lcd.print("Welcome");
    welcome = 1;
  }

  // Do stuff
}

I don't know if this will compile as I don't have Ardunio 0012 installed on this computer.

To compile that code try it with these changes:
LiquidCrystal lcd(3, -1, 2, 7, 6, 5, 4); // remove static
static int welcome = 0; // needs a type

To compile that code try it with these changes:

 LiquidCrystal lcd(3, -1, 2, 7, 6, 5, 4); // remove static

If you do this the code won't work. lcd will be created every time loop() is called, which basically is all the time. It must be static for this to work. Isn't it possible to create static objects? I'm not a C++-programmer, I only use C.

static objects yes, static classes apparantly not (or at least not using that syntax).

One solution is to modify the LiquidCrystal.cpp file and add in a delay in the constructor. I think the Hitachi datasheet does say it needs a delay of 15 milliseconds after power on before the chip should be initialized. There are some other delays that also seem to be missing from the init sequece:
Wait at least 15 msecs after power is applied.
Write function set cmd to LCD and wait 4.1 msecs
Write function set to LCD and wait 100 usecs

Perhaps mellis can say why the delays are not in included

One solution is to modify the LiquidCrystal.cpp file and add in a delay in the constructor. I think the Hitachi datasheet does say it needs a delay of 15 milliseconds after power on before the chip should be initialized.

Another solution is to not initialize the LCD in the constructor, but rather have a separate method for this. Then the user can choose when to initialize the LCD.

This is something I need to do in a project I'm working on, where the LCD's power is controlled by the Arduino. I'm not using LiquidCrystal though so this is not a problem for me.

There are some other delays that also seem to be missing from the init sequece:

I haven't studied the source of LiquidCrystal very closely, but I'm using my own code to control LCDs and know that timing is critical if the code needs to work on a variety of displays. My code currently work in 4-bit mode on 16x2, 20x4 and 40x2 displays from various manufacturers.

@skumlerud
I think a separate method to init the lcd would only be necessary if pinMode and digitalWrite were not valid when the class was instantiated

But putting in the recommended timings should make the library suitable for a wider range of LCD panels. Perhaps you could look at the code and propose changes based on your code that you think better meet the specs.

@skumlerud
I think a separate method to init the lcd would only be necessary if pinMode and digitalWrite were not valid when the class was instantiated

And - as in my case - the LCD is not powered when the Arduino boots and the class in instantiated.

But putting in the recommended timings should make the library suitable for a wider range of LCD panels. Perhaps you could look at the code and propose changes based on your code that you think better meet the specs.

Yes, I could do that.

Edit:

I had a closer look at LiquidCrystal, and from what I can tell there are missing delays after each write, and the enable-pulse is way too short. Also, some commands are missing from the four-bit init-sequence compared to my code, but it's been a while since I touched that part so I can't tell if it matters. I'll try to look into this tonight or on Saturday.

Have you tried it with the RW pin connected?

Ok, I've had a look at LiquidCrystal and modified the timing according to my own code. However, in order to use the same init sequence in four-bit-mode, I need to re-structure the send-method a bit and I don't have time for that tonight.

Btw does anybody use 8-bit-mode with this library? I really don't see any reason for using this when the four-bit-mode is already there. Removing 8-bit-support will save a few bytes and simplify the code.

scootabug: You can try this modified version of LiquidCrystal.cpp, but I don't think it will make much difference in your case as I haven't modified the init-sequence yet. It's possible that the extended enable-pulse and delays between writes will help though, so please try it.

LiquidCrystal.cpp:

#include "LiquidCrystal.h"

#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "WProgram.h"

// When the display powers up, it is configured as follows:
//
// 1. Display clear
// 2. Function set: 
//    DL = 1; 8-bit interface data 
//    N = 0; 1-line display 
//    F = 0; 5x8 dot character font 
// 3. Display on/off control: 
//    D = 0; Display off 
//    C = 0; Cursor off 
//    B = 0; Blinking off 
// 4. Entry mode set: 
//    I/D = 1; Increment by 1 
//    S = 0; No shift 
//
// Note, however, that resetting the Arduino doesn't reset the LCD, so we
// can't assume that its in that state when a sketch starts (and the
// LiquidCrystal constructor is called).

LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
  uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
  uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7) :
  _four_bit_mode(0), _rs_pin(rs), _rw_pin(rw), _enable_pin(enable)
{
  _data_pins[0] = d0;
  _data_pins[1] = d1;
  _data_pins[2] = d2;
  _data_pins[3] = d3; 
  _data_pins[4] = d4;
  _data_pins[5] = d5;
  _data_pins[6] = d6;
  _data_pins[7] = d7; 
  
  pinMode(_rs_pin, OUTPUT);
  if (_rw_pin != NO_RW)
    pinMode(_rw_pin, OUTPUT);
  pinMode(_enable_pin, OUTPUT);
  
  for (int i = 0; i < 8; i++)
    pinMode(_data_pins[i], OUTPUT);
 
  delay(16); // The LCD must be powered on for at least 15ms before init
  command(0x38);  // function set: 8 bits, 1 line, 5x8 dots
  command(0x0C);  // display control: turn display on, cursor off, no blinking
  command(0x06);  // entry mode set: increment automatically, display shift, right shift
  clear();
}

LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
  uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3) :
  _four_bit_mode(1), _rs_pin(rs), _rw_pin(rw), _enable_pin(enable)
{
  _data_pins[0] = d0;
  _data_pins[1] = d1;
  _data_pins[2] = d2;
  _data_pins[3] = d3; 
  
  pinMode(_rs_pin, OUTPUT);
  pinMode(_rw_pin, OUTPUT);
  pinMode(_enable_pin, OUTPUT);
  
  for (int i = 0; i < 4; i++)
    pinMode(_data_pins[i], OUTPUT);
 
  delay(16); // The LCD must be powered on for at least 15ms before init

  command(0x28);  // function set: 4 bits, 1 line, 5x8 dots
  command(0x0C);  // display control: turn display on, cursor off, no blinking
  command(0x06);  // entry mode set: increment automatically, display shift, right shift
  clear();
}

void LiquidCrystal::clear()
{
  command(0x01);  // clear display, set cursor position to zero
  delayMicroseconds(2000);
}

void LiquidCrystal::home()
{
  command(0x02);  // set cursor position to zero
  delayMicroseconds(2000);
}

void LiquidCrystal::setCursor(int col, int row)
{
  int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
  command(0x80 | (col + row_offsets[row]));
}

void LiquidCrystal::command(uint8_t value) {
  send(value, LOW);
}

void LiquidCrystal::write(uint8_t value) {
  send(value, HIGH);
}

void LiquidCrystal::send(uint8_t value, uint8_t mode) {
  digitalWrite(_rs_pin, mode);
  digitalWrite(_rw_pin, LOW);

  if (_four_bit_mode) {
    for (int i = 0; i < 4; i++) {
      digitalWrite(_data_pins[i], (value >> (i + 4)) & 0x01);
    }
    
    digitalWrite(_enable_pin, HIGH);
    delayMicroseconds(1);
    digitalWrite(_enable_pin, LOW);
    
    for (int i = 0; i < 4; i++) {
      digitalWrite(_data_pins[i], (value >> i) & 0x01);
    }

    digitalWrite(_enable_pin, HIGH);
    delayMicroseconds(1);
    digitalWrite(_enable_pin, LOW);
  } else {
    for (int i = 0; i < 8; i++) {
      digitalWrite(_data_pins[i], (value >> i) & 0x01);
    }

    digitalWrite(_enable_pin, HIGH);
    delayMicroseconds(1);
    digitalWrite(_enable_pin, LOW);
  }
  
  delayMicroseconds(45);
}

I think you need to add the following to get it to compile:
#define NO_RW -1

Ahh, I forgot to add the updated .h-file. I'll do that tonight.

Thanks for the help guys.

@skumlerud: I'm using 4-bit mode to save on pins.
I'll give this stuff a try once you update the .h file.

Cheers!